L'objectif est de programmer un lancer de rayons
afin d'afficher une surface déformée par une carte de
profondeur / d'altitude. Les parties suivantes présentent les
différentes étapes.
Partie 1 : première version, repère tangent et parallax mapping
L'idée du parallax mapping est
d'améliorer la perception du relief en utilisant la parallaxe,
c'est à dire le fait que les objets proches de la caméra se
déplacent différement des objets plus
éloignés. En transposant l'idée au lancer de
rayon, on obtient une méthode relativement simple.
Au lieu d'afficher la texture de l'objet
directement, il suffit de déplacer les coordonnées de
texture le long du rayon associé à chaque pixel.
L'illustration suivante devrait être plus parlante :
Il faut donc utiliser une texture donnant l'altitude
de chaque point à la surface du triangle. Les valeurs
stockés sont normalisées, il sera donc nécessaire
de les remettre dans le bon intervalle de valeurs.
L'application directe de la texture afficherait le
point Ta, l'idée du parallax mapping est de décaler la
lecture de la texture au point Tb. Il suffit de calculer le vecteur
offset qui connecte le point a sur la surface (l'altitude du point a
est obtenu en lisant la texture aux coordonnées Ta) au point b
situé sur le rayon à la même altitude.
Il reste un petit détail à
régler, le shader travaille à la surface du triangle en
cours d'affichage, et il faut déterminer les coordonnées
du rayon dans ce même repère. Connaissant la normale du
triangle, il ne reste plus qu'à déterminer une tangente
sur le triangle. Une produit vectoriel de plus permettra de caluler le
troisième vecteur nécessaire à la
définition du repère tangent. Il y a plusieurs solutions
pour choisir un vecteur tangent, la plus pratique est d'utiliser
l'arête du triangle qui a la plus forte variation sur la
coordonnée s (ou u, selon la notation) de texture. De cette manière, le
repère tangent reste aligné avec la texture appliquée au
triangle.
Quelques explications et illustrations
supplémentaires sur la construction d'un repère tangent :
"Messing with Tangent Space"
Un résumé complet sur le parallax mapping et une petite amélioration :
"Parallax Mapping with Offset Limiting"
Partie 2 : relief mapping
La qualité du parallax mapping est
très variable selon le point de vue. Pour éliminer ce
défaut, il n'y a pas beaucoup de solutions : il faut calculer
réellement l'intersection de la surface et du rayon.
Compte tenu des limitations des shaders actuels, la
solution est très simple : il suffit de tester tous les texels
le long du rayon et de vérifier à chaque fois si le point
le long du rayon est au-dessus ou au-dessous de la surface.
Les explications complètes, accompagnées d'illustrations se trouvent dans
"Real-Time Relief Mapping on Arbitrary Polygonal Surfaces"
Partie 3 : normal mapping
Les résultats du relief mapping sont plus
convaincants, mais le triangle semble toujours plat. Il suffit de
connaitre la normale au point d'intersection pour améliorer la
perception du relief. Il est possible de calculer directement la
normale à partir de la carte d'altitude, mais le plus simple est encore de la stocker dans une texture
supplémentaire. Les normales seront exprimées dans le
repère tangent afin de pouvoir être utilisées sur
tous les triangles d'un objet.
Comment calculer l'éclairement d'un point, connaissant sa normale dans le repère tangent ??
Partie subsidiaire : relief mapping + normal mapping + shadow map
Intégrez tous vos shaders, le rendu devrait
être plus convaincant qu'un simple phong texturé ...
Pour les curieux, une discussion et des exemples sur
les avantages et les inconvénients liés à
l'utilisation d'un repère tangent :
"Let
There Be Light! a unified lighting technique for a new generation of
games"
Partie subsidiaire : réduction du nombre de calculs / accélération
Il est possible de limiter le nombre de tests et
surtout d'accès à la texture pour calculer l'intersection
rayon / surface. Les explications tiennent sur 2 pages, bien
rédigées :
"Interval Mapping"
Une présentation plus complète chez ati : "Dynamic Parallalax Mapping with Self-Soft Shadows"