08 — Transformer les objets
Ce que tu vas apprendre
- Pourquoi on ne transforme pas les triangles, mais le rayon
- La matrice objet-vers-monde et son inverse
- Comment intersecter en espace local et revenir au monde
- Le bonus : les instances, pour dupliquer un objet sans le copier
Prérequis
- Les matrices de transformation, l'inverse et la transformation des normales
Un maillage est modélisé dans son propre repère (son espace objet), centré sur lui-même. Pour le placer dans la scène — le déplacer, le tourner, le redimensionner —, on dispose de sa matrice objet-vers-monde. Mais comment l'appliquer quand on ray trace ? La réponse, contre-intuitive et élégante, est de ne pas toucher à l'objet du tout.
Le réflexe naïf, et pourquoi il est mauvais
L'idée évidente serait de transformer tous les sommets du maillage par la matrice objet-vers-monde, puis de ray tracer le résultat dans l'espace monde. Ça marche, mais c'est coûteux : un maillage d'un million de sommets demande un million de multiplications matrice-vecteur à chaque fois qu'on le bouge. Et si l'objet est animé, c'est à refaire à chaque image.
L'astuce : transformer le rayon
On inverse le problème. Plutôt que d'amener l'objet dans le monde, on amène le rayon dans l'espace de l'objet. On transforme le rayon (origine et direction) par la matrice monde-vers-objet — l'inverse de la matrice objet-vers-monde :
cppVec3f O_local = worldToObject * ray.O; // origine : point → translation incluse
Vec3f D_local = worldToObject.transformDir(ray.D); // direction : pas de translation
(Rappel des séries maths : un point subit la translation, une direction non.) On intersecte alors le rayon transformé contre le maillage dans son espace local d'origine, sans avoir bougé un seul sommet. Un seul rayon à transformer, au lieu d'un million de sommets : l'économie est gigantesque.
naïf : transformer 1 000 000 de sommets vers le monde
malin : transformer 1 rayon vers l'espace objet
Le retour au monde
Une fois l'intersection trouvée en espace local, deux valeurs doivent revenir dans le monde :
- le point d'impact se retransforme par la matrice objet-vers-monde (directe) ;
- la normale se retransforme par l'inverse-transposée de la matrice objet-vers-monde — exactement la règle de l'article 07 de la série maths, sans laquelle l'éclairage serait faux dès que l'objet est mis à l'échelle non uniformément.
rayon (monde) ──worldToObject──► rayon (objet)
│ intersection en local
▼
point, normale (monde) ◄──objectToWorld / inverse-transposée── point, normale (objet)
La distance t, elle, mérite attention : si la matrice contient une mise à l'échelle, t n'a pas la même valeur dans les deux espaces. En pratique, on compare les distances dans un espace cohérent, ou on garde une direction non normalisée en local pour préserver le paramètre.
Le bonus : les instances
Cette approche débloque une fonctionnalité précieuse : les instances. Comme l'objet n'est jamais déformé — on ne fait que transformer les rayons —, on peut afficher mille fois le même maillage à des positions et orientations différentes, en ne stockant ses triangles qu'une seule fois en mémoire. Chaque instance n'est qu'une matrice. Une forêt de mille arbres identiques coûte un arbre en géométrie, plus mille matrices. C'est ainsi que les moteurs affichent des scènes énormes sans exploser la mémoire.
Le moteur est complet : il génère des rayons, intersecte des maillages transformés, et les ombre joliment. Reste l'éléphant dans la pièce — la performance. L'article suivant ouvre la porte des structures d'accélération.
Sources
- Scratchapixel. Transforming Objects using Matrices. scratchapixel.com
- Pharr, M., Jakob, W., & Humphreys, G. (2023). Physically Based Rendering (4ᵉ éd.), chap. « Transformations » et « Primitives and Intersection Acceleration » (instances). pbr-book.org
- Shirley, P. Ray Tracing: The Next Week, section « Instances ». raytracing.github.io