Dans cette première partie de notre examen plus approfondi du rendu de jeu 3D, nous nous concentrerons entièrement sur l’étape du sommet du processus. Cela signifie traîner nos manuels de mathématiques, brosser une tache d’algèbre linéaire, de matrices et de trigonométrie – oh ouais!

Nous expliquerons comment les modèles 3D sont transformés et comment les sources de lumière sont prises en compte. Les différences entre les vertex et les shaders de géométrie seront explorées en détail, et vous pourrez voir où se situe la tesselation. Pour vous aider dans les explications, nous utiliserons des diagrammes et des exemples de code pour montrer comment les mathématiques et les nombres sont traités dans un jeu. . Si vous n’êtes pas prêt pour tout cela, ne vous inquiétez pas – vous pouvez commencer avec notre Rendu de jeu 3D 101. Mais une fois que vous êtes prêt, lisez notre pour notre premier examen plus approfondi du monde des graphiques 3D.

À quoi ça sert?

Dans le monde des mathématiques, un point est simplement un emplacement dans un espace géométrique. Il n’y a rien de plus petit qu’un point, car il n’a pas de taille, ils peuvent donc être utilisés pour définir clairement où les objets tels que les lignes, les plans et les volumes commencent et se terminent.

Pour les graphiques 3D, ces informations sont cruciales pour définir l’apparence de tout, car tout ce qui est affiché est une collection de lignes, d’avions, etc. L’image ci-dessous est une capture d’écran de la version 2015 de Bethesda Fallout 4:

Il peut être un peu difficile de voir comment tout cela n’est qu’un gros tas de points et de lignes, nous allons donc vous montrer à quoi ressemble la même scène en mode «filaire». Défini comme ceci, le moteur de rendu 3D ignore les textures et les effets effectués à l’étape des pixels et ne dessine que les lignes colorées reliant les points entre eux.

Tout semble très différent maintenant, mais nous pouvons voir toutes les lignes qui vont ensemble pour constituer les divers objets, l’environnement et l’arrière-plan. Certains ne sont qu’une poignée de lignes, comme les rochers au premier plan, tandis que d’autres ont tellement de lignes qu’elles semblent solides.

Chaque point au début et à la fin de chaque ligne a été traité en faisant tout un tas de calculs. Certains de ces calculs sont très rapides et faciles à faire; d’autres sont beaucoup plus difficiles. Il y a des gains de performances importants à réaliser en travaillant ensemble sur des groupes de points, en particulier sous la forme de triangles, alors commençons par y regarder de plus près.

Alors, qu’est-ce qui est nécessaire pour un triangle?

Le nom Triangle nous indique que la forme a 3 angles intérieurs; pour cela, nous avons besoin de 3 coins et 3 lignes joignant les coins. Le nom propre d’un coin est un sommet (les sommets étant le pluriel) et chacun est décrit par un point. Puisque nous sommes basés dans un monde géométrique 3D, nous utilisons le système de coordonnées cartésiennes pour les points. Ceci est généralement écrit sous la forme de 3 valeurs ensemble, par exemple (1, 8, -3), ou plus généralement (x, y, z).

De là, nous pouvons ajouter deux sommets supplémentaires pour obtenir un triangle:

Notez que les lignes montrées ne sont pas vraiment nécessaires – nous pouvons simplement avoir les points et dire au système que ces 3 sommets forment un triangle. Toutes les données de sommet sont stockées dans un bloc de mémoire contigu appelé tampon de sommet; les informations sur la forme qu’ils créeront sont soit directement codées dans le programme de rendu, soit stockées dans un autre bloc de mémoire appelé tampon d’index.

Dans le cas du premier, les différentes formes qui peuvent être formées à partir des sommets sont appelées primitives et Direct3D propose une liste, des bandes et des ventilateurs sous la forme de points, de lignes et de triangles. Utilisées correctement, les bandes triangulaires utilisent des sommets pour plus d’un triangle, ce qui contribue à améliorer les performances. Dans l’exemple ci-dessous, nous pouvons voir que seulement 4 sommets sont nécessaires pour faire 2 triangles joints ensemble – s’ils étaient séparés, nous aurions besoin de 6 sommets.

Si vous souhaitez gérer une plus grande collection de sommets, par exemple un modèle de PNJ en jeu, il est préférable d’utiliser quelque chose appelé engrener – c’est un autre bloc de mémoire mais il se compose de plusieurs tampons (vertex, index, etc.) et des ressources de texture pour le modèle. Microsoft fournit une introduction rapide à l’utilisation de ce tampon dans leur documents en ligne Ressource.

Pour l’instant, concentrons-nous sur ce qui est fait à ces sommets dans un jeu 3D, chaque fois qu’une nouvelle image est rendue (si vous n’êtes pas sûr de ce que cela signifie, refaites une rapide analyse de notre rendu 101). En termes simples, une ou deux choses leur sont faites:

  • Déplacer le sommet dans une nouvelle position
  • Changer la couleur du sommet

Prêt pour des maths? Bien! Parce que c’est ainsi que ces choses se font.

Entrez le vecteur

Imaginez que vous avez un triangle sur l’écran et que vous appuyez sur une touche pour le déplacer vers la gauche. Vous vous attendriez naturellement à (x, y, z) les nombres pour chaque sommet à changer en conséquence et ils le sont; cependant, Comment cela peut sembler un peu inhabituel. Plutôt que de simplement changer les coordonnées, la grande majorité des systèmes de rendu graphique 3D utilisent un outil mathématique spécifique pour faire le travail: nous parlons vecteurs.

Un vecteur peut être considéré comme une flèche qui pointe vers un emplacement particulier dans l’espace et peut être de n’importe quelle longueur requise. Les sommets sont en fait décrits à l’aide de vecteurs, basés sur les coordonnées cartésiennes, de cette manière:

Remarquez comment la flèche bleue commence à un endroit (dans ce cas, la origine) et s’étend jusqu’au sommet. Nous avons utilisé ce qu’on appelle cnotation des colonnes pour décrire ce vecteur, mais rangée la notation fonctionne aussi bien. Vous aurez remarqué qu’il y a aussi une valeur supplémentaire – le 4ème nombre est communément étiqueté comme le composant w et il est utilisé pour indiquer si le vecteur est utilisé pour décrire l’emplacement d’un sommet (appelé vecteur de position) ou décrivant une orientation générale (un direction vecteur). Dans le cas de ce dernier, cela ressemblerait à ceci:

Ce vecteur pointe dans la même direction et a la même longueur que le vecteur de position précédent, donc le (x, y, z) les valeurs seront les mêmes; Cependant, le w-Le composant est nul, plutôt que 1. Les utilisations des vecteurs de direction deviendront claires plus loin dans cet article, mais pour l’instant, faisons simplement le point sur le fait que tous les sommets de la scène 3D seront décrits de cette façon. Pourquoi? Parce que dans ce format, il devient beaucoup plus facile de commencer à les déplacer.

Mathématiques, mathématiques et plus de mathématiques

N’oubliez pas que nous avons un triangle de base et que nous voulons le déplacer vers la gauche. Chaque sommet est décrit par un vecteur de position, donc les «calculs en mouvement» que nous devons faire (appelés transformations) doit travailler sur ces vecteurs. Entrez dans l’outil suivant: matrices (ou matrice pour l’un d’eux). Il s’agit d’un tableau de valeurs écrit un peu comme une feuille de calcul Excel, en lignes et en colonnes.

Pour chaque type de transformation que nous voulons faire, il y a une matrice associée pour aller avec, et il s’agit simplement de multiplier la matrice de transformation et le vecteur de position ensemble. Nous ne détaillerons pas comment et pourquoi cela se produit, mais nous pouvons voir à quoi cela ressemble.

Le déplacement d’un sommet dans un espace 3D est appelé Traduction et le calcul requis est le suivant:

le X0, etc. les valeurs représentent les coordonnées d’origine du sommet; le deltaX les valeurs représentent la quantité de déplacement du sommet. Le calcul matriciel-vecteur fait que les deux sont simplement additionnés (notez que le w reste intact, donc la réponse finale est toujours un vecteur de position).

En plus de déplacer des choses, nous pourrions vouloir faire pivoter le triangle ou le mettre à l’échelle plus ou moins grande – il y a des transformations pour les deux.

Nous pouvons utiliser l’outil graphique optimisé par WebGL au Site Web de rendu en temps réel pour visualiser ces calculs sur une forme entière. Commençons par un cuboïde dans une position par défaut:

Dans cet outil en ligne, le point de modèle fait référence au vecteur de position, la matrice mondiale est la matrice de transformation et le point espace-monde est le vecteur de position du sommet transformé.

Appliquons maintenant une variété de transformations au cuboïde:

Dans l’image ci-dessus, la forme a été traduit par 5 unités dans toutes les directions. Nous pouvons voir ces valeurs dans la grande matrice au milieu, dans la dernière colonne. Le vecteur de position d’origine (4, 5, 3, 1) reste le même, comme il se doit, mais le sommet transformé a maintenant été traduit en (9, 10, 8, 1).

Dans cette transformation, tout a été mis à l’échelle par un facteur 2: le cuboïde a maintenant des côtés deux fois plus longs. Le dernier exemple à regarder est un point de rotation:

Le cuboïde a été tourné d’un angle de 45 ° mais la matrice utilise le sinus et cosinus de cet angle. Une vérification rapide de n’importe quelle calculatrice scientifique nous montrera que péché (45 °) = 0,7071 … qui arrondit à la valeur de 0,71 indiquée. Nous obtenons la même réponse pour le cosinus valeur.

Les matrices et les vecteurs n’ont pas à être utilisés; une alternative courante, en particulier pour gérer des rotations complexes, implique l’utilisation de nombres complexes et quaternions. Ce calcul est une étape importante par rapport aux vecteurs, nous allons donc passer des transformations.

La puissance du vertex shader

À ce stade, nous devons faire le point sur le fait que tout cela doit être compris par les gens qui programment le code de rendu. Si un développeur de jeux utilise un moteur tiers (tel que Unity ou Unreal), cela aura déjà été fait pour eux, mais quiconque crée le sien, à partir de zéro, devra déterminer les calculs à effectuer pour quels sommets.

Mais à quoi cela ressemble-t-il, en termes de code?

Pour vous aider, nous utiliserons des exemples de l’excellent site Web Braynzar Soft. Si vous voulez vous lancer dans la programmation 3D, c’est un excellent endroit pour apprendre les bases, ainsi que des choses plus avancées …

Cet exemple est une «transformation tout-en-un». Il crée les matrices de transformation respectives sur la base d’une entrée au clavier, puis l’applique au vecteur de position d’origine en une seule opération. Notez que cela se fait toujours dans un ordre défini (échelle – rotation – traduction), car toute autre façon gâcherait totalement le résultat.

Ces blocs de code sont appelés vertex shaders et ils peuvent varier énormément en termes de ce qu’ils font, de leur taille et de leur complexité. L’exemple ci-dessus est aussi basique qu’ils viennent et sans doute seulement juste un vertex shader, car il n’utilise pas la nature entièrement programmable des shaders. Une séquence plus complexe de shaders pourrait peut-être la transformer dans l’espace 3D, déterminer comment tout cela apparaîtra à la caméra de la scène, puis transmettre ces données à l’étape suivante du processus de rendu. Nous examinerons d’autres exemples au fur et à mesure de la séquence de traitement des sommets.

Ils peuvent être utilisés pour bien plus encore, bien sûr, et chaque fois que vous jouez à un jeu rendu en 3D, n’oubliez pas que tout le mouvement que vous pouvez voir est élaboré par le processeur graphique, en suivant les instructions des vertex shaders.

Mais ce n’était pas toujours le cas. Si nous remontons dans le temps jusqu’au milieu à la fin des années 1990, les cartes graphiques de cette époque n’avaient pas la capacité de traiter les sommets et les primitives elles-mêmes, tout cela était entièrement fait sur le CPU.

L’un des premiers processeurs à fournir une accélération matérielle dédiée à ce type de processus a été La GeForce originale de Nvidia sortie en 2000 et cette capacité a été étiquetée Transformation matérielle et éclairage (ou Hardware TnL, pour faire court). Les processus que ce matériel pouvait gérer étaient très rigides et fixes en termes de commandes, mais cela a rapidement changé à mesure que de nouvelles puces graphiques étaient publiées. Aujourd’hui, il n’y a pas de matériel séparé pour le traitement des vertex et les mêmes unités traitent tout: points, primitives, pixels, textures, etc.

En parlant de éclairage, il convient de noter que tout ce que nous voyons, bien sûr, est dû à la lumière, alors voyons comment cela peut être géré au stade du sommet. Pour ce faire, nous utiliserons quelque chose que nous avons mentionné plus haut dans cet article.

Lumière, caméra, action!

Imaginez cette scène: le joueur se tient dans une pièce sombre, éclairé par une seule source lumineuse éteinte à droite. Au milieu de la pièce, il y a une théière géante, flottante et épaisse. D’accord, nous aurons probablement besoin d’un peu d’aide pour visualiser cela, alors utilisons le Site Web de rendu en temps réel, pour voir quelque chose comme ça en action:

Maintenant, n’oubliez pas que cet objet est une collection de triangles plats cousus ensemble; cela signifie que le plan de chaque triangle sera orienté dans une direction particulière. Certains sont orientés vers la caméra, certains dans l’autre sens et d’autres sont de travers. La lumière de la source frappera chaque plan et rebondira sous un certain angle.

Selon l’endroit où la lumière se dirige, la couleur et la luminosité de l’avion varient, et pour garantir que la couleur de l’objet semble correcte, tout cela doit être calculé et pris en compte.

Pour commencer, nous devons savoir de quel côté l’avion fait face et pour cela, nous avons besoin du vecteur normal de l’avion. Ceci est une autre flèche mais contrairement au vecteur de position, sa taille n’a pas d’importance (en fait, ils sont toujours réduits après le calcul, de sorte qu’ils ont exactement 1 unité de longueur) et il est toujours perpendiculaire (à angle droit) par rapport à l’avion.

La normale du plan de chaque triangle est calculée en calculant le produit vectoriel des deux vecteurs de direction (p et q ci-dessus) qui forment les côtés du triangle. Il est en fait préférable de le calculer pour chaque sommet plutôt que pour chaque triangle individuel, mais étant donné qu’il y aura toujours plus de premier par rapport au second, il est plus rapide de le faire pour les triangles.

Une fois que vous avez la normale d’une surface, vous pouvez commencer à prendre en compte la source de lumière et la caméra. Les lumières peuvent être de différents types dans le rendu 3D, mais pour les besoins de cet article, nous ne considérerons que directionnel lumières, par ex. un coup de projecteur. Comme le plan d’un triangle, le projecteur et la caméra pointent dans une direction particulière, peut-être quelque chose comme ceci:

Le vecteur de la lumière et le vecteur normal peuvent être utilisés pour déterminer l’angle auquel la lumière frappe la surface (en utilisant la relation entre le produit scalaire des vecteurs et le produit de leurs tailles). Les sommets du triangle porteront des informations supplémentaires sur leur couleur et leur matériau – dans le cas de ce dernier, il décrira ce qui arrive à la lumière lorsqu’elle frappe la surface.

Une surface lisse et métallique réfléchira la quasi-totalité de la lumière entrante sous le même angle que celui auquel elle est entrée et changera à peine la couleur. En revanche, un matériau rugueux et terne diffusera la lumière d’une manière moins prévisible et changera subtilement la couleur. Pour tenir compte de cela, les sommets doivent avoir des valeurs supplémentaires:

  • Couleur de base d’origine
  • Attribut de matériau ambiant – une valeur qui détermine la quantité de lumière «d’arrière-plan» que le sommet peut absorber et refléter
  • Attribut de matériau diffus – une autre valeur mais cette fois indiquant à quel point le sommet est « rugueux », ce qui affecte à son tour la quantité de lumière diffusée absorbée et réfléchie
  • Attributs de matériaux spéculaires – deux valeurs nous donnant une mesure de la «brillance» du sommet

Différents modèles d’éclairage utiliseront diverses formules mathématiques pour regrouper tout cela ensemble, et le calcul produit un vecteur pour la lumière sortante. Ceci est combiné avec le vecteur de la caméra, l’apparence globale du triangle peut être déterminée.

Nous avons sauté la plupart des détails les plus fins ici et pour cause: prenez n’importe quel manuel sur le rendu 3D et vous verrez des chapitres entiers dédiés à ce processus unique. Cependant, les jeux modernes effectuent généralement la majeure partie des calculs d’éclairage et des effets de matériaux au stade du traitement des pixels, nous reviendrons donc sur ce sujet dans un autre article.

Tout ce que nous avons couvert jusqu’à présent se fait à l’aide de vertex shaders et il peut sembler qu’ils ne peuvent presque rien faire; malheureusement, il y en a. Les shaders de sommet ne peuvent pas créer de nouveaux sommets et chaque shader doit fonctionner sur chaque sommet. Ce serait pratique s’il y avait un moyen d’utiliser un peu de code pour faire plus de triangles, entre ceux que nous avons déjà (pour améliorer la qualité visuelle) et avoir un shader qui fonctionne sur une primitive entière (pour accélérer les choses vers le haut). Eh bien, avec les processeurs graphiques modernes, nous pouvez fais ça!

S’il vous plaît monsieur, j’en veux plus (triangles)

Les dernières puces graphiques sont extrêmement puissantes, capables d’effectuer des millions de calculs matriciels-vecteurs chaque seconde; ils sont facilement capables d’alimenter un énorme tas de sommets en un rien de temps. D’un autre côté, la création de modèles très détaillés prend beaucoup de temps et si le modèle est éloigné de la scène, tous ces détails supplémentaires seront gaspillés.

Nous avons besoin d’un moyen de dire au processeur de diviser une primitive plus grande, comme le triangle plat unique que nous avons examiné, en une collection de triangles plus petits, tous liés à l’intérieur du grand original. Le nom de ce processus est tesselation et les puces graphiques sont capables de le faire depuis un bon moment maintenant; ce qui s’est amélioré au fil des ans, c’est la quantité de contrôle que les programmeurs ont sur l’opération.

Pour voir cela en action, nous allons utiliser Outil de référence Unigine’s Heaven, car cela nous permet d’appliquer différentes quantités de pavage à des modèles spécifiques utilisés dans le test.

Pour commencer, prenons un emplacement dans le repère et examinons sans pavage appliqué. Remarquez à quel point les pavés dans le sol semblent très faux – la texture utilisée est efficace mais elle ne semble pas juste. Appliquons une tessellation à la scène; le moteur Unigine ne l’applique qu’à certaines parties mais la différence est dramatique.

Le sol, les bords des bâtiments et la porte semblent tous beaucoup plus réalistes. Nous pouvons voir comment cela a été réalisé si nous réexécutons le processus, mais cette fois avec les bords des primitives tous mis en évidence (aka, mode filaire):

Nous pouvons voir clairement pourquoi le sol semble si étrange – il est complètement plat! La porte affleure également les murs et les bords du bâtiment ne sont rien d’autre que de simples cuboïdes.

Dans Direct3D, les primitives peuvent être divisées en un groupe de parties plus petites (un processus appelé subdivision) en exécutant une séquence en 3 étapes. Tout d’abord, les programmeurs écrivent un shader de coque – essentiellement, ce code crée quelque chose appelé patch de géométrie. Pensez à cela comme une carte indiquant au processeur où les nouveaux points et lignes vont apparaître à l’intérieur de la primitive de départ.

Ensuite, l’unité tesselator à l’intérieur du processeur graphique applique le patch à la primitive. Enfin, un ombrage de domaine est exécuté, qui calcule les positions de tous les nouveaux sommets. Ces données peuvent être réinjectées dans le tampon de sommet, si nécessaire, afin que les calculs d’éclairage puissent être effectués à nouveau, mais cette fois avec de meilleurs résultats.

Alors à quoi ça ressemble? Lançons la version filaire de la scène en mosaïque:

À vrai dire, nous avons fixé le niveau de tessellation à un niveau plutôt extrême, pour aider à l’explication du processus. Aussi bon que les puces graphiques modernes, ce n’est pas quelque chose que vous voudriez faire dans chaque jeu – prenez le lampadaire près de la porte, par exemple.

Dans les images non filaires, vous seriez poussé à faire la différence à cette distance, et vous pouvez voir que ce niveau de pavage s’est empilé sur tant de triangles supplémentaires, il est difficile de séparer certains d’entre eux. Bien utilisée, cependant, et cette fonction de traitement des sommets peut donner lieu à des effets visuels fantastiques, en particulier lorsque vous essayez de simuler des collisions de corps mous.

Dans les images non filaires, vous seriez poussé à faire la différence à cette distance, et vous pouvez voir que ce niveau de pavage s’est empilé sur tant de triangles supplémentaires, il est difficile de séparer certains d’entre eux. Voyons à quoi cela pourrait ressembler, en termes de code Direct3D; pour ce faire, nous utiliserons un exemple d’un autre grand site Web RasterTek.

Ici, un seul triangle vert est tessellé en beaucoup plus de triangles de bébé …

Le traitement des vertex se fait via 3 shaders séparés (voir exemple de code): un vertex shader pour configurer le triangle prêt à tesseller, un shader de coque pour générer le patch et un shader de domaine pour traiter les nouveaux sommets. Le résultat est très simple, mais l’exemple Unigine met en évidence les avantages et les dangers potentiels de l’utilisation de la tessellation partout. Bien utilisée, cependant, et cette fonction de traitement des sommets peut donner lieu à des effets visuels fantastiques, en particulier lorsque vous essayez de simuler des collisions de corps mous.

Elle ne peut pas s’en occuper, capitaine!

Rappelez-vous le point sur les vertex shaders et qu’ils sont toujours exécutés sur chaque sommet de la scène? Il n’est pas difficile de voir comment la tessellation peut en faire un vrai problème. Et il y a beaucoup d’effets visuels où vous voudriez gérer plusieurs versions de la même primitive, mais sans vouloir en créer beaucoup au début; les cheveux, la fourrure, l’herbe et les particules explosives en sont tous de bons exemples.

Heureusement, il existe un autre shader juste pour de telles choses – le shader de géométrie. Il s’agit d’une version plus restrictive du vertex shader, mais qui peut être appliquée à une primitive entière et associée à la tessellation, donne aux programmeurs un plus grand contrôle sur de grands groupes de sommets.

Direct3D, comme toutes les API graphiques modernes, permet d’effectuer une vaste gamme de calculs sur les sommets. Les données finalisées peuvent être envoyées à l’étape suivante du processus de rendu (pixellisation) ou réinjecté dans le pool de mémoire, afin qu’il puisse être traité à nouveau ou lu par le processeur à d’autres fins. Cela peut être fait sous forme de flux de données, comme le souligne Microsoft Documentation Direct3D:

le sortie de flux l’étape n’est pas requise, d’autant plus qu’elle ne peut renvoyer que des primitives entières (et non des sommets individuels) à travers la boucle de rendu, mais elle est utile pour les effets impliquant de nombreuses particules partout. La même astuce peut être effectuée en utilisant un dynamique vertex buffer, mais il est préférable de conserver les tampons d’entrée fixes car les performances sont affectées si elles doivent être «ouvertes» pour être modifiées.

Le traitement des sommets est un élément essentiel du rendu, car il définit la façon dont la scène est organisée du point de vue de la caméra. Les jeux modernes peuvent utiliser des millions de triangles pour créer leurs mondes, et chacun de ces sommets aura été transformé et éclairé d’une manière ou d’une autre.

La gestion de tous ces calculs et données peut sembler un cauchemar logistique, mais les processeurs graphiques (GPU) et les API sont conçus en tenant compte de tout cela – imaginez une usine qui fonctionne bien, tirant un article à la fois à travers une séquence d’étapes de fabrication et vous en aurez une bonne idée.

Expérimenté Rendu de jeu 3D les programmeurs ont une connaissance approfondie des mathématiques et de la physique avancées; ils utilisent tous les trucs et outils du métier pour optimiser les opérations, réduisant la phase de traitement des vertex en seulement quelques millisecondes. Et ce n’est que le début de la création d’un cadre 3D – il y a ensuite l’étape de pixellisation, puis le traitement extrêmement complexe des pixels et des textures, avant qu’il ne s’approche de votre moniteur.

Maintenant que vous avez atteint la fin de cet article, nous espérons que vous avez approfondi le parcours d’un sommet lors de son traitement pour un cadre 3D. Nous n’avons pas tout couvert (ce serait un énorme article!) et nous sommes sûrs que vous aurez beaucoup de questions sur les vecteurs, les matrices, les lumières et les primitives. Tirez-les à notre façon dans la section des commentaires et nous ferons de notre mieux pour y répondre.

Lire aussi
Raccourcis commerciaux:



Source link

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.