J'ai décidé d'écrire un peu sur l'aspect programmation et comment les composants communiquent entre eux. Peut-être que cela vous éclairera sur certains points.
La présentation
Que faut-il pour que la seule image que vous avez affichée dans votre question soit dessinée à l'écran ?
Il existe de nombreuses façons de dessiner un triangle à l'écran. Pour simplifier, supposons qu'aucun tampon de sommets n'a été utilisé. (A Tampon de vertex est une zone de la mémoire où vous stockez les coordonnées). Supposons que le programme indique simplement au pipeline de traitement graphique tous les sommets (un sommet est simplement une coordonnée dans l'espace) d'une rangée.
Mais Avant de pouvoir dessiner quoi que ce soit, nous devons d'abord mettre en place un échafaudage. Nous allons voir pourquoi plus tard :
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Drawing Using Triangles
glBegin(GL_TRIANGLES);
// Red
glColor3f(1.0f,0.0f,0.0f);
// Top Of Triangle (Front)
glVertex3f( 0.0f, 1.0f, 0.0f);
// Green
glColor3f(0.0f,1.0f,0.0f);
// Left Of Triangle (Front)
glVertex3f(-1.0f,-1.0f, 1.0f);
// Blue
glColor3f(0.0f,0.0f,1.0f);
// Right Of Triangle (Front)
glVertex3f( 1.0f,-1.0f, 1.0f);
// Done Drawing
glEnd();
Alors, qu'est-ce que ça a fait ?
Lorsque vous écrivez un programme qui veut utiliser la carte graphique, vous choisissez généralement une sorte d'interface avec le pilote. Certaines interfaces bien connues du pilote sont :
Pour cet exemple, nous nous en tiendrons à OpenGL. Maintenant, votre interface avec le pilote est ce qui vous donne tous les outils dont vous avez besoin pour faire de votre programme parler à la carte graphique (ou au pilote, qui alors discussions à la carte).
Cette interface va certainement vous donner certaines outils . Ces outils prennent la forme d'un API que vous pouvez appeler depuis votre programme.
C'est cette API que nous voyons utilisée dans l'exemple ci-dessus. Regardons de plus près.
L'échafaudage
Avant de pouvoir réellement dessiner, vous devez effectuer une vérification de l'état des lieux. configuration . Vous devez définir votre fenêtre d'affichage (la zone qui sera effectivement rendue), votre perspective (le point de vue de l'utilisateur) et le point de vue de l'utilisateur. caméra dans votre monde), quel anticrénelage vous utiliserez (pour lisser les bords de votre triangle)...
Mais nous ne regarderons pas tout cela. Nous allons juste jeter un coup d'oeil sur les choses que vous aurez à faire chaque cadre . Comme :
Effacer l'écran
Le pipeline graphique ne va pas nettoyer l'écran pour vous à chaque image. Vous devrez lui dire. Pourquoi ? Voici pourquoi :
Si vous ne dégagez pas l'écran, vous allez simplement tirer sur à chaque image. C'est pourquoi nous appelons glClear
avec le GL_COLOR_BUFFER_BIT
réglé. L'autre bit ( GL_DEPTH_BUFFER_BIT
) indique à OpenGL d'effacer l'indicateur profondeur Tampon. Cette mémoire tampon est utilisée pour déterminer quels pixels se trouvent devant (ou derrière) d'autres pixels.
Transformation
Source de l'image
La transformation est la partie où nous prenons toutes les coordonnées d'entrée (les sommets de notre triangle) et appliquons notre matrice ModelView. Il s'agit de la matrice qui explique comment notre modèle (les sommets) sont tournés, mis à l'échelle et translatés (déplacés).
Ensuite, nous appliquons notre matrice de projection. Cela déplace toutes les coordonnées pour qu'elles fassent correctement face à notre caméra.
Maintenant, nous transformons une fois de plus, avec notre matrice Viewport. Nous faisons cela pour mettre à l'échelle notre modèle à la taille de notre écran. Nous avons maintenant un ensemble de sommets qui sont prêts à être rendus !
Nous reviendrons sur la transformation un peu plus tard.
Dessin
Pour dessiner un triangle, nous pouvons simplement dire à OpenGL de commencer un nouveau fichier liste de triangles en appelant glBegin
avec le GL_TRIANGLES
constant.
Il existe également d'autres formes que vous pouvez dessiner. Comme un bande triangulaire ou un ventilateur triangulaire . Il s'agit principalement d'optimisations, car elles nécessitent moins de communication entre le CPU et le GPU pour dessiner la même quantité de triangles.
Ensuite, nous pouvons fournir une liste d'ensembles de 3 sommets qui devraient constituer chaque triangle. Chaque triangle utilise 3 coordonnées (puisque nous sommes dans un espace 3D). De plus, je fournis également un couleur pour chaque sommet, en appelant glColor3f
antes de en appelant glVertex3f
.
L'ombre entre les 3 sommets (les 3 coins du triangle) est calculée par OpenGL automatiquement . Il interpolera la couleur sur toute la face du polygone.
Interaction
Maintenant, quand vous cliquez sur la fenêtre. L'application n'a plus qu'à capturer le message de la fenêtre qui signale le clic. Ensuite, vous pouvez exécuter n'importe quelle action dans votre programme que vous voulez.
Cela donne un lot plus difficile une fois que vous voulez commencer à interagir avec votre scène 3D.
Vous devez d'abord savoir clairement à quel pixel l'utilisateur a cliqué sur la fenêtre. Ensuite, en prenant votre perspective en compte, vous pouvez calculer la direction d'un rayon, à partir du point de clic de la souris dans votre scène. Vous pouvez alors calculer si un objet de votre scène intersecte avec ce rayon . Maintenant vous savez si l'utilisateur a cliqué sur un objet.
Alors, comment le faire tourner ?
Transformation
Je connais deux types de transformations qui sont généralement appliquées :
- Transformation matricielle
- Transformation osseuse
La différence est que ossements affecter simple sommets . Les matrices affectent toujours tous les sommets dessinés de la même manière. Prenons un exemple.
Exemple
Plus tôt, nous avons chargé notre matrice identité avant de dessiner notre triangle. La matrice d'identité est une matrice qui fournit simplement pas de transformation du tout. Donc, tout ce que je dessine, n'est affecté que par ma perspective. Donc, le triangle ne sera pas tourné du tout.
Si je veux le faire tourner maintenant, je peux soit faire les calculs moi-même (sur le CPU) et simplement appeler glVertex3f
con autre (qui subissent une rotation). Ou je pourrais laisser le GPU faire tout le travail, en appelant glRotatef
avant de dessiner :
// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);
amount
est, bien sûr, juste une valeur fixe. Si vous voulez animer vous devrez garder la trace de amount
et l'augmenter à chaque image.
Alors, attendez, qu'est-il arrivé à toute la discussion sur la matrice plus tôt ?
Dans cet exemple simple, nous n'avons pas à nous soucier des matrices. Nous appelons simplement glRotatef
et il s'occupe de tout ça pour nous.
glRotate
produit une rotation de angle
degrés autour du vecteur x y z . La matrice de courant (voir glMatrixMode ) est multipliée par une matrice de rotation, le produit remplaçant la matrice courante, comme si glMultMatrix ont été appelés avec la matrice suivante comme argument :
x 2 1 - c + c x y 1 - c - z s x z 1 - c + y s 0 y x 1 - c + z y 2 1 - c + c y z 1 - c - x s 0 x z 1 - c - y s y z 1 - c + x s z 2 1 - c + c 0 0 1
Eh bien, merci pour ça !
Conclusion
Ce qui devient évident, c'est qu'il y a beaucoup de discussions à OpenGL. Mais il ne dit pas nous n'importe quoi. Où est la communication ?
La seule chose qu'OpenGL nous dit dans cet exemple est que quand c'est fait . Chaque opération prend un certain temps. Certaines opérations sont incroyablement longues, d'autres sont incroyablement rapides.
Envoi d'un sommet vers le GPU sera si rapide que je ne saurais même pas comment l'exprimer. L'envoi de milliers de sommets du CPU vers le GPU, à chaque image, ne posera probablement aucun problème.
Effacer l'écran peut prendre une milliseconde ou pire (n'oubliez pas que vous ne disposez généralement que d'environ 16 millisecondes pour dessiner chaque image), en fonction de la taille de votre fenêtre. Pour l'effacer, OpenGL doit dessiner chaque pixel dans la couleur que vous voulez effacer, ce qui peut représenter des millions de pixels.
En dehors de cela, nous ne pouvons demander à OpenGL que les capacités de notre carte graphique (résolution maximale, anticrénelage maximal, profondeur de couleur maximale, ...).
Mais on peut aussi remplir une texture avec des pixels qui ont chacun une couleur spécifique. Chaque pixel contient donc une valeur et la texture est un "fichier" géant rempli de données. Nous pouvons charger ce fichier dans la carte graphique (en créant un buffer de texture), puis charger un fichier nuanceur Pour cela, il faut dire à ce shader d'utiliser notre texture comme entrée et d'exécuter des calculs très lourds sur notre "fichier".
Nous pouvons ensuite "rendre" le résultat de notre calcul (sous la forme de nouvelles couleurs) dans une nouvelle texture.
C'est ainsi que vous pouvez faire travailler le GPU pour vous d'une autre manière. Je suppose que CUDA a des performances similaires à cet aspect, mais je n'ai jamais eu l'occasion de travailler avec.
Nous n'avons vraiment qu'effleuré le sujet. La programmation graphique 3D est une sacrée bête.
Source d'image