TD7 - Normal mapping

L'objectif de ce TP est de mettre en place la technique de normal mapping. Le principe de cette approche est de stocker dans une texture une carte des normales détaillées qui seront utilisées pour perturber le calcul d'éclairage. Vous procéderez en trois étapes : d'abord vous appliquerez le normal mapping sur un plan dont les normales perturbées seront exprimées en espace objet, ensuite vous calculerez le repère tangent aux sommets d'un maillage, et pourrez enfin l'appliquer à une sphère (ou tout autre maillage) dont les normales seront définies en espace tangent.

1. Normal mapping sur un plan

1. Comme son nom l'indique, une carte de normales contient des normales, encodées sous forme de couleurs. Téléchargez l'archive textures.zip et chargez la carte de normales "normals.png" à l'aide de SOIL2 (comme une texture classique) et passez-la à un sampler de texture dans le fragment shader. Utilisez la valeur lue dans cette texture à la place des normales interpolées passées par le vertex shader pour calculer l'éclairage. Testez avec un simple plan (fichier "plane.obj"). Pour bien visualiser la perturbation de l'éclairage, affichez d'abord le calcul de l'illumination en niveau de gris sans la texture de couleur.

Attention : les textures étant faites pour contenir des couleurs, leurs valeurs sont comprises dans l'intervalle $[0,1]$ alors que les normales sont comprises dans l'intervalle $[-1,1]$. Pensez à effectuer la transformation appropriée !

2. Chargez la texture de couleurs "diffuse.png". Passez-la à un second sampler de texture et utilisez-la pour définir la couleur diffuse de l'objet.

normalMap normalMap normalMap normalMap
texture diffuse carte de normales perturbation de l'éclairage résultat final

3. Appliquez une rotation à l'objet (et pas à la vue), que constatez-vous ? Que se passe-t-il si vous testez sur autre chose qu'un plan ?

2. Calcul du repère tangent

Le plan est placé de façon à ce que les normales contenues dans la carte de normales correspondent à l'espace objet. Ce n'est généralement pas le cas : la carte de normales est en réalité exprimée dans le repère tangent à la surface de l'objet. Il est défini par trois vecteurs : la normale $\vx{n}$, la tangente $\vx{t}$ et la bitangente $\vx{b}$.

Comme pour le calcul des normales lisses au TD5, il faut d'abord calculer la tangente et la bitangente par triangle, en utilisant ses coordonnées de textures, puis moyenner ces vecteurs pour obtenir un repère par sommet auquel vous appliquerez l'orthonormalisation de Gram-Schmidt afin de garantir que le triplet $[\vx{t},\vx{b},\vx{n}]$ forme un repère orthonormal. Complétez la méthode Mesh::computeNormals pour calculer également la tangent et la bitangente par sommet.

Passez les vecteurs $\vx{t}$ et $\vx{b}$ ainsi calculés au vertex shader comme nouveaux attributs vec3 vtx_tangent et vec3 vtx_bitangent. Testez avec le maillage "earth2.obj".

3. Normal mapping sur une sphère

1. Chargez la texture "earth_normal.jpg" dans une nouvelle unité de texture. Vous pouvez dans un premier temps visualiser directement cette texture à la surface de la sphère.

2. Les normales fournies par la texture sont exprimées dans un repère tangent à la surface de l'objet. Pour les utiliser, il est donc nécessaire d'exprimer les vecteurs de lumière et de vue dans ce repère ($l_t$ et $v_t$). Construisez ce repère en suivant les étapes suivantes :

  1. dans le vertex shader, transformez les vecteurs tangent, bitangent et normal du repère Model au repère View puis normalisez les pour obtenir les vecteurs $\vx{t_v}$, $\vx{b_v}$ et $\vx{n_v}$ respectivement,
  2. dans le fragment shader, re-normalisez les vecteurs interpolés obtenus et créez la matrice de transformation 3x3 tbnvMatrix dont chaque ligne est constituée des 3 composantes des vecteurs $\vx{t_v}$, $\vx{b_v}$ et $\vx{n_v}$. Si v_1 = vec2(a,b) et v_2 = vec2(c,d) alors m = mat2(v_1,v_2) représente la matrice 2x2 dont la première ligne sera (a,c) et la seconde (b,d)
  3. les vecteurs $\vx{l_t}$ et $\vx{v_t}$ sont obtenus en multipliant la matrice tbnvMatrix par $\vx{l_v}$ et $\vx{v_v}$ respectivement.

Utilisez la normale lue dans la normale map ainsi que $l_t$ et $v_t$ pour calculer l'éclairage diffus (voire le terme spéculaire du modèle de Blinn-Phong si vous l'aviez implémenté au TD5).

bump bump
perturbation de l'éclairage diffus résultat final avec la texture de couleurs

Vous pouvez désormais appliquer le normal mapping sur n'importe quel maillage possédant des coordonnées de texture, par exemple ce modèle Jerry the Ogre.

bump   bump
Éclairage calculé avec les normales du maillage et la normale map.