TD2 - Maillage triangulaire

Téléchargez l'archive mds3d_td2.zip contenant une correction du TD précédent ainsi qu'une nouvelle classe Mesh représentant un maillage triangulaire.

Un maillage de la classe Mesh consiste en une liste de sommets m_vertices et une liste de faces m_faces. Chaque sommet est un structure contenant une position ainsi que, optionnellement, une normale et des coordonnées de texture. Une face est simplement un triplet d'indices vers trois éléments dans la liste des sommets. La méthode mesh::vertexOfFace retrourne le vertex d'index vertexId $\in \{0,1,2\}$ de la face d'index faceId.

Initialement, vous devriez obtenir l'image suivante avec le fichier de scène "tw.scn" :

Maillage
Boîte alignée sur les axes (AABB)

1. Calcul d'intersection

Pour calculer l'intersection d'un rayon avec un triangle, vous utiliserez la technique de Möller-Trumbore (référez-vous au cours). Implémentez celle-ci dans la méthode :

bool Mesh::intersectFace(const Ray& ray, Hit& hit, int faceId) const

faceId est l'index de la face à tester dans la liste m_faces.

Dans un premier temps, vous utiliserez la normale de la face comme normale au point d'intersection.

Pour raytracer un maillage complet, il vous suffit ensuite d'appeler la méthode d'intersection du triangle sur chacune des faces du maillage dans la méthode Mesh::intersect. Vous devriez obtenir le résultat suivant :

Maillage
Normales par face

Modifiez intersectFace pour calculer la normale au point d'intersection comme l'interpolation barycentrique des normales aux trois sommets (si elles sont disponibles), à l'aide des coordonnées de texture calculée par la technique de Möller-Trumbore. Vous devriez obtenir ce résultat :

Maillage
Normales par sommet avec "tw503.obj"

Dans le fichier de scène "tw.scn", remplacez le maillage "tw503.obj" par "tw.obj" :

<string name="filename" value="tw.obj"/>
comptant 12576 faces. Faites le rendu de l'image ; le coût de calcul devient clairement perceptible.

Maillage
Normales par sommet avec "tw.obj".

2. BVH

L'objectif de cette seconde partie est de mettre en œuvre une structure accélératrice pour le lancer de rayon. Plus précisément, vous implémenterez une hiérarchie de boîtes englobantes (BVH) pour accélérer le calcul des intersections avec un maillage.

La classe Mesh possède déjà un attribut m_BVH stockant une BVH. Remarquez la méthode publique Mesh::buildBVH() dont le rôle est de construire la BVH. Celle-ci devra être appelée au chargement de la scène, à la fin du constructeur (la ligne de construction de la BVH est pour l'instant commentée). Dans la fonction Mesh::intersect(), appelez m_BVH->intersect(ray, hit); si la BVH a bien été construite.

Le code d'intersection entre un rayon est une boîte englobante alignée sur les axes (AABB), vous est fourni dans le fichier ray.h :

static inline bool intersect(const Ray& ray, const Eigen::AlignedBox3f& box, float& tMin, float& tMax, Normal3f& normal)

Pour obtenir une BVH fonctionnelle, vous devez implémenter trois fonctions :

  • BVH::buildNode(),
  • BVH::intersect(),
  • BVH::intersectNode().
Ces fonctions sont largement commentées.

Notez les statistiques fournies sur la sortie standard (temps de calcul et nombre de calculs d'intersections avec des triangles). Voilà celles obtenues sur mon portable avec la scène "tw.scn" (en la modifiant pour utiliser le maillage haute résolution "tw.obj") :

Sans BVH:
  Raytracing time : 59.4484s  -  nb triangle intersection: 1581054720

Avec BVH
  Raytracing time : 0.372178s  -  nb triangle intersection: 1851579

Testez également avec les scènes "killeroo.scn" et "killerooGlass.scn" :

killeroo killeroo