{
Bienvenue à la leçon neuf. À présent, vous devriez avoir une bonne compréhension d’OpenGL.
"CKER : Sinon, ce doit être la faute de mon traducteur...".
(Myling a ajouté : Mon péché est encore plus grand, haha)
Vous avez appris tous les détails de la configuration d'une fenêtre OpenGL.
Apprenez à cartographier et à ajouter un mélange de lumière et de couleurs (transparence) aux objets en rotation.
Cette leçon doit être considérée comme un tutoriel intermédiaire.
Vous apprendrez à déplacer un bitmap autour d'une scène 3D et à supprimer les pixels noirs du bitmap (en utilisant le mélange de couleurs).
Ensuite, coloriez les textures en noir et blanc, et enfin vous apprendrez à créer des couleurs riches,
Et mélangez des textures de différentes couleurs les unes avec les autres pour obtenir un effet d'animation simple.
Nous apporterons des modifications en fonction du code de la première leçon. Ajoutez d’abord quelques variables au début du code source du programme.
J'ai réécrit tout le code pour plus de clarté.
}
Var
h_RC : HGLRC ; // Contexte de rendu (tableau de description d'ombrage).
h_DC : HDC ; // Contexte du périphérique (tableau de description du périphérique)
h_Wnd : HWND ; // handle de fenêtre
h_Instance : HINST ; // Instance de programme (instance).
keys : Array[0..255] Of Boolean; // Tableau pour les routines de clavier
{Les lignes suivantes sont nouvellement ajoutées.
twinkle et tp sont des variables booléennes, ce qui signifie qu'elles ne peuvent être définies que sur TRUE ou FALSE.
twinkle est utilisé pour savoir si l'effet de scintillement est activé.
tp est utilisé pour vérifier si la touche « T » est enfoncée ou relâchée.
(tp=TRUE lorsque vous appuyez dessus, tp=FALSE lorsque vous le relâchez).}
twinkle : Booléen ; // Étoiles scintillantes (nouveau)
tp : Boolean; // Est-ce que 'T' est enfoncé (nouveau) ?
{Créons maintenant une structure.
Le mot structure semble effrayant, mais ce n’est pas le cas. (C'est le type d'enregistrement de Delphi)
Une structure utilise un ensemble de types simples de données (et de variables, etc.) pour exprimer une combinaison plus large de données similaires.
Nous savons que nous suivons les étoiles.
Vous pouvez voir les étoiles ci-dessous ;
Chaque étoile a trois valeurs de couleur entières. Un rouge (r), un vert (g) et un bleu (b).
De plus, chaque étoile est à une distance différente du centre de l'écran,
Et il peut s'agir de n'importe quel angle sur 360 degrés avec le centre de l'écran comme origine.
Un nombre à virgule flottante de dist pour garder une trace de la distance.
Le nombre d'angle à virgule flottante garde une trace de la valeur de l'angle de l'étoile.
Nous avons donc utilisé un ensemble de données pour décrire la couleur, la distance et l'angle des étoiles sur l'écran.
Malheureusement, nous suivons plus d'une étoile.
Mais il n'est pas nécessaire de créer 50 valeurs rouges, 50 valeurs vertes, 50 valeurs bleues, 50 valeurs de distance.
et 50 valeurs d'angle, et créez simplement une étoile de tableau. }
Taper
stars = Record // Crée une structure pour les étoiles, nommée stars
r, g, b : entier ; // couleur des étoiles
dist: GLfloat; //La distance de l'étoile au centre
angle: GLfloat; //L'angle actuel de l'étoile
Fin;
Var
star : Array[0..49] Of stars; // Utiliser la structure 'stars' pour générer un tableau 'star' contenant 50 éléments
{Ensuite, nous configurons plusieurs variables de suivi :
La distance variable (zoom) de l'étoile à l'observateur,
L'angle (inclinaison) sous lequel nous voyons les étoiles,
et la rotation variable qui fait tourner l’étoile scintillante autour de l’axe Z.
La variable loop est utilisée pour dessiner 50 étoiles.
texture[1] est utilisée pour stocker une texture en noir et blanc.
Si vous avez besoin de plus de textures,
Vous devez augmenter la taille du tableau de textures en fonction du nombre de textures que vous décidez d'utiliser.
}
zoom : GLfloat = -15.0; // La distance de l'étoile à l'observateur
tilt : GLfloat = 90.0; // L'inclinaison de l'étoile
spin : GLfloat; // La rotation de l'étoile scintillante
boucle : Gluint ; // variable de boucle globale
texture : Array[0..1] De GLuint; // Stocke une texture
PRocédure glGenTextures(n : GLsizei ; Var textures : GLuint stdcall );
opengl32;
Procédure glBindTexture(cible : GLenum ; texture : GLuint externe) ;
opengl32;
{
Le code immédiatement ci-dessus est le code que nous utilisons pour charger la texture.
Je ne vais pas expliquer ce code en détail.
C'est exactement le même code que nous avons utilisé dans les leçons 6, 7 et 8.
Le bitmap chargé cette fois s'appelle star.bmp.
Ici nous utilisons glGenTextures(1, &texture[0]),
pour générer une texture. La texture utilise un filtrage linéaire.
}
Function LoadTexture: boolean; //Charge le bitmap et convertit-le en texture
Var
Statut : booléen; // Indicateur d'état
TextureImage : Array[0..1] Of PTAUX_RGBImageRec; // Créer un espace de stockage de texture
Commencer
Statut := faux ;
ZeroMemory (@TextureImage, sizeof(TextureImage)); // Place le pointeur sur NULL
TextureImage[0] := LoadBMP('Star.bmp');
Si TextureImage[0] <> Nil Alors
Commencer
Statut := VRAI ; // Définir le statut sur VRAI
glGenTextures(1, texture[0]); // Créer une texture
// Créer une carte de filtre la plus proche
glBindTexture(GL_TEXTURE_2D, texture[0]);
// Générer une texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST // (nouveau) ;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST // (nouveau) ;
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
Fin;
Si assigné(TextureImage[0]) Alors // Si la texture existe
Si attribué(TextureImage[0].data) Then // Si l'image de texture existe
TextureImage[0].data := Nil; // Libère la mémoire occupée par l'image de texture
TextureImage[0] := Nil; // Libère la structure de l'image
résultat := Statut ; // Retourne le statut
Fin;
{Définissez le mode de rendu OpenGL dans glInit(). Nous n'allons pas utiliser de tests en profondeur ici,
Si vous utilisez le code de la leçon 1,
Veuillez confirmer si glDepthFunc(GL_LEQUAL) et glEnable(GL_DEPTH_TEST) ont été supprimés.
Sinon, les résultats que vous verrez seront désastreux.
Ici, nous utilisons le mappage de texture,
Assurez-vous donc d'avoir ajouté tout code qui n'était pas inclus dans la première leçon.
Vous remarquerez que nous avons activé le mappage de texture en mélangeant les couleurs.
}
Procédure glInit();
Commencer
If (Not LoadTexture) Then // Appel du sous-programme de chargement de texture (nouveau)
exit; // En cas d'échec du chargement, quittez (nouveau)
glEnable(GL_TEXTURE_2D); // Activer le mappage de texture
glShadeModel(GL_SMOOTH); // Activer le lissage des ombres
glClearColor(0.0, 0.0, 0.0, 0.5); // fond noir
glClearDepth(1.0); //Définit le tampon de profondeur
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Correction de perspective vraiment fine
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // Définit la fonction de mélange des couleurs pour obtenir un effet translucide
glEnable(GL_BLEND); // Activer le mélange des couleurs
{Ce qui suit est le nouveau code.
L'angle de départ, la distance et la couleur de chaque étoile sont définis.
Vous remarquerez à quel point il est facile de modifier les propriétés d'une structure.
Les 50 étoiles seront recyclées.
Pour changer l'angle de star[1], il suffit de star[1].angle=a certaine valeur ;
C'est aussi simple que ça ! }
Boucle For := 0 à 49 Do // Créer une boucle pour définir toutes les étoiles
Commencer
star[loop].angle := 0.0; // Toutes les étoiles partent d'un angle nul
{La distance entre la ème étoile de la boucle et le centre est divisée par la valeur de la boucle par le nombre total d'étoiles, puis multipliée par 5,0.
Fondamentalement, cela rend cette dernière étoile un peu plus éloignée du centre que l’étoile précédente.
De cette façon, lorsque la boucle vaut 50 (la dernière étoile), la boucle divisée par num vaut exactement 1,0.
La raison pour laquelle nous devons multiplier par 5,0 est que 1,0*5,0 équivaut à 5,0.
{CKER : C’est absurde, c’est absurde ! Pourquoi cet étranger ressemble-t-il à Kong Yiji ! :)』
La version 5.0 est déjà très proche du bord de l’écran. Je ne veux pas que les étoiles sortent de l’écran, donc la version 5.0 est le meilleur choix.
Bien sûr, si vous placez la scène plus profondément dans l'écran,
Vous pourriez peut-être utiliser une valeur supérieure à 5,0, mais les étoiles paraîtraient plus petites (tout cela à cause de la perspective).
Vous remarquerez également que la couleur de chaque étoile est un nombre aléatoire compris entre 0 et 255.
Vous vous demandez peut-être pourquoi la plage de valeurs de couleur ici n'est pas la plage habituelle d'OpenGL de 0,0 à 1,0.
La fonction de réglage des couleurs que nous utilisons ici est glColor4ub au lieu du précédent glColor4f.
ub signifie que le paramètre est de type Unsigned Byte.
La plage de valeurs d'un octet est comprise entre 0 et 255.
Il semble plus facile d'utiliser la valeur d'octet pour obtenir un entier aléatoire que d'obtenir un nombre aléatoire à virgule flottante.
}
star[loop].dist := (Trunc(loop) / 50) * 5.0; // Calcule la distance de l'étoile au centre
star[loop].r := random(256); // Définir un composant rouge aléatoire pour star[loop]
star[loop].g := random(256); // Définir un composant rouge aléatoire pour star[loop]
star[loop].b := random(256); // Définir un composant rouge aléatoire pour star[loop]
Fin;
Fin;
{
Passons maintenant au code de dessin glDraw().
Si vous utilisez le code de la leçon 1, supprimez l'ancien code DrawGLScene et copiez simplement le code ci-dessous.
En fait, le code de la première leçon ne comporte que deux lignes, il n’y a donc pas grand-chose à supprimer.
}
Procédure glDraw();
Commencer
glClear(GL_COLOR_BUFFER_BIT Ou GL_DEPTH_BUFFER_BIT); // Efface l'écran et le tampon de profondeur
glBindTexture(GL_TEXTURE_2D, texture[0]); //Sélectionner la texture
Boucle For := 0 à 49 Do // Boucle pour définir toutes les étoiles
Commencer
glLoadIdentity(); // Avant de dessiner chaque étoile, réinitialisez la matrice d'observation du modèle
glTranslatef(0.0, 0.0, zoom); // Allez plus profondément dans l'écran (en utilisant la valeur de 'zoom')
glRotatef(tilt, 1.0, 0.0, 0.0); // Angle de vision d'inclinaison (en utilisant la valeur de 'tilt')
{
Déplaçons maintenant les étoiles.
L'étoile commence au centre de l'écran.
La première chose à faire est de faire pivoter la scène le long de l’axe Y.
Si on le fait pivoter de 90 degrés, l'axe X n'est plus de gauche à droite, il sort de l'écran de l'intérieur vers l'extérieur.
Pour que ce soit plus clair, donnons un exemple. Imaginez que vous vous trouvez au milieu d'une maison.
Imaginez maintenant que le mur à votre gauche indique -x et que le mur devant vous indique -z.
Le mur de droite est +x et le mur derrière vous est +z.
Si toute la maison est tournée de 90 degrés vers la droite, mais que vous ne bougez pas, alors le mur devant sera en -x au lieu de -z.
Tous les autres murs bougent également. -z apparaît à droite, +z apparaît à gauche et +x apparaît derrière vous.
Êtes-vous fou? En faisant pivoter la scène, nous changeons l'orientation des plans x et z.
La deuxième ligne de code déplace une valeur positive le long de l'axe des x.
Habituellement, une valeur positive sur l'axe des x signifie un déplacement vers le côté droit de l'écran (c'est-à-dire la direction positive habituelle de l'axe des x).
Mais ici, puisque nous faisons pivoter le système de coordonnées autour de l’axe y, la direction positive de l’axe x peut être dans n’importe quelle direction.
Si nous le tournons à 180 degrés, les côtés gauche et droit de l'écran seront reflétés.
Ainsi, lorsque nous nous déplaçons le long de l’axe des x positif, cela peut être à gauche, à droite, en avant ou en arrière.
}
glRotatef(star[loop].angle, 0.0, 1.0, 0.0); //Rotation selon l'angle de l'étoile actuellement dessinée
glTranslatef(star[loop].dist, 0.0, 0.0); // Avancer le long de l'axe X
{
Le code suivant a une petite astuce.
Les étoiles sont en réalité une texture plate.
Maintenant, vous dessinez un quad plat au centre de l'écran et appliquez une texture, et ça a l'air bien.
Tout est comme vous l'imaginiez. Mais lorsque vous faites une rotation de 90 degrés le long de l'axe y,
Les deux seuls côtés de la texture sur l’écran qui vous font face sont les côtés droit et gauche. Cela ressemble à une fine ligne.
Ce n'est pas ce que nous voulons. Nous voulons que les étoiles soient toujours face à nous, quelle que soit la façon dont l'écran est tourné ou incliné.
Nous y parvenons en annulant toutes les rotations effectuées sur l'étoile avant de la dessiner.
Vous pouvez inverser la rotation pour contrecarrer la rotation. Lorsque nous inclinons l’écran, nous faisons pivoter l’étoile selon son angle actuel.
En inversant l'ordre, on "anti-tourne" l'étoile à son angle actuel. Autrement dit, l’étoile pivote d’une valeur négative de l’angle actuel.
c'est,
Si nous faisons pivoter l’étoile de 10 degrés, nous la faisons pivoter de -10 degrés pour que l’étoile soit à nouveau face à l’écran sur cet axe.
La première ligne ci-dessous annule la rotation le long de l'axe y. Ensuite, nous devons également décaler l’inclinaison de l’écran le long de l’axe des x.
Pour ce faire, il suffit de faire pivoter à nouveau l'écran et de l'incliner.
Après avoir annulé la rotation sur les axes x et y, l’étoile nous fait à nouveau complètement face.
}
glRotatef(-star[loop].angle, 0.0, 1.0, 0.0); // Annule l'angle de l'étoile actuelle
glRotatef(-tilt, 1.0, 0.0, 0.0); // Annuler l'inclinaison de l'écran
{Si le scintillement est VRAI, nous dessinons d'abord une étoile sans rotation sur l'écran :
Soustrayez le nombre actuel d'étoiles (boucle) du nombre total d'étoiles (num), puis soustrayez 1.
pour extraire les différentes couleurs de chaque étoile (ceci est fait car la plage de la boucle va de 0 à num-1).
Par exemple, lorsque le résultat est 10, on utilise la couleur de l'étoile n°10.
De cette façon, les couleurs des étoiles adjacentes sont toujours différentes. Ce n'est pas une bonne idée, mais ça marche.
La dernière valeur est le composant du canal alpha. Plus la valeur est petite, plus l'étoile est sombre.
Puisque le scintillement est activé, chaque étoile finira par être dessinée deux fois.
Le programme s'exécutera plus lentement, en fonction des performances de votre machine.
Mais les couleurs des étoiles dessinées en deux passes se fondent les unes dans les autres et produisent un bel effet.
Dans le même temps, comme les étoiles lors du premier passage n'ont pas tourné, les étoiles après avoir activé le scintillement ressemblent à un effet d'animation.
(Si vous ne comprenez pas ici, allez simplement voir vous-même l’effet du programme.)
Il convient de noter que la coloration des textures est facile.
Même si la texture elle-même est en noir et blanc, elle prendra la couleur que nous avons sélectionnée avant de la peindre.
De plus, il convient également de noter que la valeur de couleur que nous utilisons ici est de type octet,
au lieu des nombres à virgule flottante habituels. Même le composant du canal alpha est comme ça. }
If (scintillement) Alors // Activer l'effet scintillant
Commencer
// Spécifie une couleur en utilisant une valeur d'octet
glColor4ub(étoile[(50 - boucle) - 1].r, étoile[(50 - boucle) - 1].g,
étoile[(50 - boucle) - 1].b, 255);
glBegin(GL_QUADS); // Commence à dessiner des quads mappés par texture
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // Fin du dessin du quadrilatère
Fin;
{
Dessinez maintenant la deuxième passe des étoiles.
La seule différence par rapport au code précédent est que cette fois les étoiles seront définitivement dessinées, et cette fois les étoiles tourneront autour de l'axe z.
}
glRotatef(spin, 0.0, 0.0, 1.0); // Fait pivoter l'étoile autour de l'axe z
// Spécifie une couleur en utilisant une valeur d'octet
glColor4ub(étoile[boucle].r, étoile[boucle].g, étoile[boucle].b, 255);
glBegin(GL_QUADS); // Commence à dessiner des quads mappés par texture
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // Fin du dessin du quadrilatère
{Le code ci-dessous représente le mouvement des étoiles.
Nous augmentons la valeur de spin pour faire tourner toutes les étoiles (révolution).
Ensuite, augmentez l'angle de rotation de chaque étoile de boucle/numéro.
Cela fait que les étoiles plus éloignées du centre tournent plus rapidement. Réduisez enfin la distance de chaque étoile par rapport au centre de l’écran.
On dirait que les étoiles sont constamment aspirées au centre de l’écran. }
spin := spin + 0.01; // La révolution de l'étoile
star[loop].angle := star[loop].angle + Trunc(loop) / 50 // Changer l'angle de rotation de l'étoile
star[loop].dist := star[loop].dist - 0.01; // Change la distance de l'étoile par rapport au centre
{Les lignes suivantes vérifient si l'étoile a touché le centre de l'écran.
Lorsque l'étoile atteint le centre de l'écran, nous lui donnons une nouvelle couleur et la déplaçons de 5 unités vers l'extérieur.
La star reprendra son voyage de retour au centre de l’écran. }
If (star[loop].dist < 0.0) Then // L'étoile a-t-elle atteint le centre ?
Commencer
star[loop].dist := star[loop].dist + 5.0; // Déplacement de 5 unités vers l'extérieur
star[loop].r := random(256); // Attribuer un nouveau composant rouge
star[loop].g := random(256); // Attribuer un nouveau composant vert
star[loop].b := random(256); // Attribue un nouveau composant bleu
Fin;
Fin;
Fin;
{
Maintenant, nous ajoutons le code pour surveiller le clavier.
Descendez jusqu’à WinMain(). Recherchez la ligne SwapBuffers(hDC).
Nous ajouterons le code de surveillance du clavier après cette ligne.
Le code vérifiera si la touche T a été enfoncée.
Si la touche T est enfoncée et relâchée, le code du bloc if sera exécuté.
Si twinkle est FAUX, il deviendra VRAI.
vice versa. Tant que la touche T est enfoncée, tp devient TRUE.
Cela empêche le code du bloc d'être exécuté à plusieurs reprises si vous continuez à appuyer sur la touche T.
}
If (keys[ord('T')] And Not tp) Then // Si la touche T a été enfoncée et que la valeur tp est FALSE
Commencer
tp := TRUE; // Si oui, définissez tp sur TRUE
twinkle := Pas de scintillement ; // Inverse la valeur de twinkle
Fin;
{
Le code ci-dessous vérifie si la touche T a été relâchée.
Si tel est le cas, définissez tp=FALSE.
Sauf si la valeur de tp est FAUX,
Sinon, rien ne se passera si vous maintenez la touche T enfoncée. Cette ligne de code est donc importante.
}
If (Not keys[Ord('T')]) Then // La touche T a-t-elle été libérée ?
Commencer
tp := FALSE; // Si oui, tp est FALSE
Fin;
{Le code restant vérifie si les touches fléchées haut et bas, la touche page précédente ou la touche page suivante sont enfoncées. }
If (keys[VK_UP]) Then // La touche fléchée vers le haut est-elle enfoncée ?
tilt := tilt - 0.5; // Incline l'écran vers le haut
If (keys[VK_DOWN]) Then // La touche fléchée vers le bas est-elle enfoncée ?
tilt := tilt + 0.5; // Incline l'écran vers le bas
If (keys[VK_PRIOR]) Then // La touche page précédente est-elle enfoncée ?
zoom := zoom - 0,2; // Zoom arrière
If (keys[VK_NEXT]) Then // La touche page suivante est-elle enfoncée ?
zoom := zoom + 0,2; // Zoom avant
{
Dans cette leçon, je fais de mon mieux pour expliquer comment charger une texture bitmap en niveaux de gris,
Après avoir supprimé sa couleur de fond (en utilisant des couleurs mélangées), coloriez-le à nouveau, et enfin faites-le bouger dans la scène 3D.
Je vous ai montré comment créer de superbes effets de couleurs et d'animation.
Le principe de mise en œuvre est de superposer une copie bitmap sur le bitmap original.
Jusqu'à présent, tant que vous comprenez bien tout ce que je vous ai appris,
Vous devriez pouvoir créer votre propre démo 3D sans aucun problème.
Toutes les bases couvertes ! }
//========myling :
//Les cours 1 à 9 ont été traduits. Comme l'a dit NEHE, les connaissances de base ont été essentiellement expliquées.
// J'ai regardé les tutoriels suivants, et ils semblent avoir été écrits par d'autres personnes. S'il y a de bons exemples, je les suivrai de manière sélective.
//Renouvelé, je suis tellement fatigué, fais une sieste :), à la prochaine fois