Texel
Liens | Index | Contact





















Introduction au Bump Mapping:
Part 1
L'Emboss Bump Mapping


La technique du bump mapping permet d'ajouter du relief aux surfaces des objets sans avoir à augmenter le nombre de polygones de la scène. Il existe plusieurs techniques de Bump mapping. Nous allons voir ici la plus simple. Elle produit des résultats intéressants, pas toujours parfaits, mais fonctionne sur toutes les cartes graphiques, même anciennes. Cette technique est appelée Emboss bump mapping. Nous ne rentrerons pas dans le code, mais vous en trouverez sur les sites en lien en bas de cette page.

  Discussion:
OpenGL éclaire les polygones des objets 3d en faisant, pour chaque vertex, le produit scalaire entre la normale du vertex et le vecteur direction de la lumière. Le résultat de cette opération représente une intensité qui multipliée par la couleur de l'objet et de la lumière détermine la couleur de chaque vertex. Pour éclairer ce qui se trouve entre chaque vertex (la surface des polygones), OpenGL fait une interpolation. La couleur de chaque texel est multipliée par une intensité lumineuse égale à la moyenne de l'intensité lumineuse des vertices de la face considérée. Cette technique est appelée Per Vertex Ligthing.

Cf = (L•N) x Dl x Dm

L : Vecteur direction de la lumière.
N : Normale du vertex.
Dl: Couleur diffuse de la lumière.
Dm: Couleur diffuse du material appliqué au fragment.

Malheureusement, cette technique d'illumination, bien que rapide à calculer, a de gros défauts. Une interpolation reste une interpolation. La lumière est calculée de manière exacte, uniquement au niveau des vertices. Prenons un exemple. Si la source lumineuse se trouve au dessus du centre d'un triangle. On a la surprise de constater que plus la source de lumière s'éloigne de la face, plus celle-ci est éclairée.


Sur le schéma ci-dessus, l'angle entre la normale et le vecteur reliant les vertices à la source de lumière diminut lorsque cette dernière s'éloigne. Le résultat du produit scalaire est alors plus grand.

Pour obtenir une illumination plus proche de la réalité, il serait préférable de faire les produits scalaires (L•N) au niveau de chaque fragment. C'est possible grâce aux shaders. On parle de Per Pixel Lighting. Mais dans ce chapitre nous allons considérer que notre carte graphique ne gère pas les shaders parce qu'on est curieux et qu'on a envie de s'amuser :) Alors comment faire ?

  L'emboss Bump-Mapping:

L'idée de l'emboss bumpmappin est d'approximer le produit scalaire (L•N) au niveau des texels des textures appliquées aux faces. On ne se limite donc plus aux vertices. A l'intensité lumineuse Fd calculée (interpolée) par OpenGL au niveau de chaque texel, on ajoute une valeur m positive ou négative représentant la variation de l'intensité lumineuse due à une variation du relief.

Cf = (Fd + m) x Dl x Dm

Fd: Intensité lumineuse diffuse
m : Variation du relief (H1 - H0)

Sur le schéma ci-contre est représenté les hauteurs du relief sur une face (en noir), la variation du relief "m" (en rouge) et l'intensité lumineuse diffuse "Fd" calculée par OpenGL (en bleu)(le schéma n'est pas très réaliste, mais l'idée est que la luminosité augmente lorsqu'on se rapproche de la lumière).



La valeur de "m" est calculée à partir d'une texture en dégradé de gris appelée HeightMap qui représente la hauteur de relief sur la surface à texturer (photo de gauche). Cette texture va être ajoutée à la texture "de base" qui applique les couleurs aux faces (à droite). Plus la couleur d'un pixel de le texture de height map est claire, plus la hauteur de la surface est sensée être élevée.



A partir de la texture de height map, on affiche l'objet en trois passes:

  • On affiche l'objet en lui appliquant la texture height map. Mais au préalable, on a diminué de moitié la luminosité de la texture.

  • On affiche de nouveau l'objet par dessus le précédant rendu par transparence en lui appliquant la texture de height map avec des valeurs de couleurs inversées. La luminosité est encore une fois diminuée de moitié mais on a aussi légèrement décalé les coordonnées de textures vers la position de la lumière.

  • On affiche encore une fois l'objet (en transparence) mais en lui appliquant sa texture de couleur.

    + + =

    C'est le décalage des coordonnées de textures de la 2ème passe qui permet de calculer "m". En effet, de cette façon, les texels contiennes la valeur de la couleur normale (sans bumpmapping) + une intensité égale à la variation de la hauteur du relief par rapport au décalage.

    Ce décalage est calculer de la façon suivante, pour chaque vertex:
  • on calcule les coordonnées du vecteur "V" reliant le vertex à la source de lumière.
  • on projette le vecteur "V" sur la face contenant le vertex. On nomme ce vecteur "D".
  • on additionne aux coordonnées de texture du vertex (u,v), les coordonnées du vecteur "D" lui même multiplié par un facteur qui accentuera plus ou moins le bump mapping (u = u + D*Facteur; v = v + D*Facteur).

    Ca paraît simple, mais comment projeter le vecteur "V" sur le plan de la face ?
    Et de quelle façon additionne t'on ce vecteur, qui appartient au repère de la scène, aux coordonnées de texture qui appartiennent à un autre repère local à la face ?

    On va déjà commencer par calculer le vecteur V. Pour une source de lumière directionnel (comme le soleil), on connaît ce vecteur (c'est celui de la lumière). Pour une lumière omni-directionnelle, une simple soustraction entre les coordonnées de la position de la lumière et la position du vertex considéré suffit. Mais attention: Si vous connaîssez la position de la lumière dans le repère du monde (world space) mais que vous connaîssez la position des vertices de vos objets dans leur repère local (object space), vous devez transformer la position de la lumière dans le repère de l'objet pour pouvoir faire vos calculs dans le même repère.
    Il ne reste plus qu'à projeter le vecteur.

    Rappel: Pour transformer un vecteur d'un repère à un autre, on multiplie le vecteur avec la matrice du repère orthonormé de destination.

    Maintenant, on transforme le vecteur "V" dans le repère de la texture au niveau de chaque vertex avec une matrice appelée matrice TBN:
    ( Sx Sy Sz )
    ( Tx Ty Tz )
    ( Nx Ny Nz )

    Cette matrice est calculée à partir de 3 vecteurs:
  • "N": La normale de la face.
  • "S" et "T": Les vecteurs orthogonaux appartenant au plan de la face, par rapport auxquelles les coordonnées de texture sont exprimées (u,v).

    Sur le schéma ci-dessous, une face triangulaire est représentée. La zone grise représente la texture qui est appliquée sur la face et dont les coordonnées de textures sont exprimé selon les vecteurs "s" et "t".
    "s", "t" et "n" (la normale) définissent le repère de l'espace tangent. C'est dans cette espace que l'on peut faire le décalage.

    On veut projeter notre vecteur "V" sur la face. Pour cela, après avoir transformé "V" dans l'espace tangent, il suffira d'ignoré ses coordonnées selon "N" (que l'on mettera à zéro) pour avoir ce qu'on cherche.

    Il faut pour cela trouver les vecteurs S et T :)

    Le calcul des vecteurs N, S et T qui définissent le repère de l'espace tangent peut donner des résultats exacts pour des objets composés de sphères, torus, cylindres,...(On utilise les propriétés de leur forme et non pas leurs polygones). Mais pour des polygones, c'est un peu plus compliqué. Car si un vertex est utilisé par plusieurs faces (ce qui est plus que souvent le cas), la normale du vertex est "la moyenne des normales de ces faces". Pour obtenir S et T il faut alors aussi calculer "la moyenne des vecteurs S et T". Pour cela on additionne les vecteurs N, S et T calculés pour chaques faces attachées au vertex et on normalise les vecteurs. C'est pas très précis mais ça marche.

    Calcul du vecteur normal:

    On utilise la technique habituelle. On fait le produit vectoriel entre les deux vecteurs adjacents aux arrêtes du triangle qui sont en contacte avec le vertex considéré.

    Calcul des vecteurs "s" et "t":

    On prend les deux vecteurs non normalisés issues du vertex considéré et adjacents aux arrêtes du triangle (ceux déjà utilisés pour calculer la normale). On calcule les vecteur S et T à partir de la variation des coordonnées de textures le long de ces deux vecteurs. Soit pour le vertex 1 d'un triangle (ayant trois vertices 0,1 et 2):

    VECTOR3D vect10= v0.position-v1.position;
    VECTOR3D vect12 = v2.position - v1.position;
    
    float deltaT10 = v0.texCoords.y - v1.texCoords.y;
    float deltaT12 = v2.texCoords.y - v1.texCoords.y;
    sTangent = deltaT12 * vect10 - deltaT10 * vect12;
    
    float deltaS10 = v0.texCoords.x - v1.texCoords.x; float deltaS12 = v2.texCoords.x - v1.texCoords.x; tTangent = - deltaS12 * vect10 + deltaS10 * vect12;

    Bien sûr les vecteurs "n", "s" et "t" doivent être normalisés ensuite.

    Le calcul de "D" à partir de "V" est alors très simple:

    
    (Dx)   (Sx Sy Sz) (Vx)   (Sx*Vx + Sy*Vy + Sz*Vz)
    (Dy) = (Tx Ty Tz) (Vy) = (Tx*Vx + Ty*Vy + Tz*Vz)
    (Dz)   (Nx Ny Nz) (Vz)   (Nx*Vx + Ny*Vy + Nz*Vz)
    



  •   Avec OpenGL:
    L'inversion de la texture de height map peut se faire avec un logiciel de retouche d'image, ou directement dans l'application, lors de la création de la texture en manipulant les pointeur de l'image:
    CouleurInverse = 255 - CouleurOriginale;
    De même pour diminuer la luminosité des textures de moitié. On peut aussi utiliser la fonction OpenGL glPixelTransfer().
    glPixelTransferf(GL_RED_SCALE  ,0.5f); // Composante rouge multipliée par 0.5
    glPixelTransferf(GL_GREEN_SCALE,0.5f); // Composante verte multipliée par 0.5
    glPixelTransferf(GL_BLUE_SCALE ,0.5f); // Composante bleu multipliée par 0.5
    glTexParameteri(...);
    glGenTextures(...);
    Pour la transparence, on utilise glBlendFunc() et pour décaler les textures, il suffit d'additionner les coordonnées (u,v) avec le vecteur D multiplié par un vecteur.
    Pour le reste consultez les liens de la section OpenGL de ce site qui pointent vers de nombreux codes sources.

      Conclusion:
    Après la lecture de cet article, vous avez maintenant quelques éléments pour comprendre d'autres techniques de rendu de bump mapping donnant de bien meilleurs résultats (dot3 bump mapping avec ou sans shaders par exemple).

      Références:
  • Jens Schneider et Jeff Molofee, NeHe Productions - Lesson 22 (nehe.gamedev.net)
  • An Overview Of Bump Mapping Techniques (http://www.delphi3d.net)
  • Paul Baker, Simple Bump Mapping (http://www.paulsprojects.net)
  • ATI (www.ati.com)
  • NVidia (www.nvidia.com)


  • Version originale: Août 2006
    Dernière mise à jour: Février 2007
    Par Grégory Smialek

    Site hébergé par free




















    www.texel.fr.fm