TD5 : Carte d'environnement
1 - Environment mapping
L'environment mapping (carte d'environnement) est un procédé qui permet de générer les réflexions / réfractions d'un environnement sur un objet en temps réel en utilisant des textures. Calculer la réflexion consiste à calculer le vecteur $r$ qui est la réflexion du vecteur vue $v$ par rapport au plan orthogonal à la normale $n$. En supposant que $v$ et $n$ soient normalisés, cela se fait très facilement grâce à la fonction GLSL : r = reflect(-v, n)
Le vecteur $r$ représente la direction d'où vient la lumière réfléchie par la surface. L'idée est d'accéder à une texture représentant l'environnement (environement-map) grâce à ce vecteur. Jusque là, nous avons utilisé des texture bidimensionnelles (target GL_TEXTURE_2D
) accessibles avec une paire de coordonnées $(s,t)$. Bien qu'il soit possible de définir un mapping entre une direction (3D) et un point dans un espace 2D (sphere-mapping), le résultat est peu satisfaisant en raison des fortes déformations engendrées et de l'impossibilité de générer de telles image avec le pipeline OpenGL. C'est pourquoi le cube-mapping a été introduit.
Une cube-map (GL_TEXTURE_CUBE_MAP
) est une texture particulière qui combine 6 textures 2D, une pour chaque face d'un cube englobant. L'accès à une cube map se fait à l'aide d'un vecteur 3D : la couleur retournée est celle "pointée" par le vecteur. De nombreuses cube maps sont disponibles sur le net, par exemple sur la page de Paul Debevec). SOIL2 ne permet cependant pas de charger directement une cubemap en croix ; il faut soit charger chaque face du cube depuis un fichier séparé, soit concaténer les 6 faces verticalement (en voilà quelques exemples).

1. Chargez une carte d’environnement avec SOIL_load_OGL_single_cubemap
(l'ordre des faces est le suivant : "UNDSWE"). Dans le fragment shader, utilisez un samplerCube
pour lire la couleur de l'environnement dans la direction de réflexion (fonction GLSL reflect
)
2. Activez dans Viewer::init
le filtrage à l'aide de la fonction permettant de faire du seamless cube mapping filtering pour filtrer correctement la carte d'environnement aux bords du cube.
3. L'environnement réfléchi semble fixé à la caméra, alors que l'on souhaiterait plutôt que celui-ci soit fixé à la scène (repère monde). Comprendre pourquoi et corrigez le problème. Testez également avec différents modèles 3D.
Afin de mieux comprendre ce qu'il se produit, il faut afficher l'environnement comme arrière-plan. Pour ce faire, dans la méthode Viewer::init
:
- créez un nouveau shaders chargeant les fichiers background.vert/.frag qui se contenteront de lire la carte d'environnement à la position courante,
- créez une seconde sphère,
- appliquez-lui une mise à l'échelle afin de l'agrandir (100 fois, par exemple).
Viewer::display
, commencez par faire le dessin de la sphère qui affichera la texture d'arrière plan, en ayant désactivé le test de profondeur (GL_DEPTH_TEST
), puis réactiverez le pour effectuer alors le rendu de l'objet réfléchissant.
![]() |
![]() |
![]() |
réflection | réfraction | réflection + réfraction |
4. Au lieu de la réflexion, utilisez la fonction GLSL refract
pour aller chercher la valeur de l'environnement avec le vecteur réfracté.
5. Combinez réflexion et réfraction. Vous pondérerez la valeur de réflexion et de réfraction en utilisant l'approximation de Schlick qui est donnée par la formule suivante :
$$ F = f^2 + (1 - f^2) (1 - V \cdot N)^5 \hspace{1em} \mbox{avec} \hspace{1em} f = \frac{1 - n_1/n_2}{1 + n_1/n_2}$$Vous pouvez par exemple utiliser comme indices de réfraction ceux de l'air $n_1=1.0$ et du verre $n_2=1.33$.
Extensions possibles : effets d'aberration chromatique en réfractant différemment les 3 canaux de couleur, création de cartes d'environnement dynamiques pour gérer correctement les scènes animées, utilisation de diffuse maps pour étendre l'usage des cartes d'environnement à l'éclairage diffus.
2 - Images à grande dynamique
Vous pouvez charger des cartes d'environnement HDR (au format RADIANCE) avec la fonction SOIL_load_OGL_HDR_single_cubemap
. Contrairement aux textures habituelles, ces images HDR sont chargées dans des buffers floattants avec 32 bits par canal. Cependant, elles doivent être tone mappées pour pouvoir être affichées sur un écran LDR (8 bits par canal). Par défaut un mapping linéaire non contrôlable est effectué. L'objectif est de permettre à l'utilisateur de contrôler uniformément l'exposition $e$ et le gamma $\gamma$ de la scène :
Pour cela, il va vous falloir effectuer le rendu principal de la scène dans un FrameBuffer Object (FBO), configuré pour utiliser une texture flottante sur 32 bits.
1. Complétez la classe FBO
suivante (méthode init
). Créez une variable de type FBO
et initialisez-la dans Viewer::init
à la même taille que la fenêtre d'affichage. Au début de la fonction display
, activez ce FBO (méthode bind
) et mettez à zéro ses buffers avec glClear
. Tout ce que vous dessinerez ensuite sera stocké dans le FBO jusqu'à l'appel à FBO::unbind
.
2. Créez une nouvelle paire de shader tonemapping.vert/.frag. Relisez la texture renderedTexture
du FBO dans le fragment shader en utilisant l'attribut gl_FragCoord
pour connaître la position du fragment courant dans l'image. Modifiez la dynamique du fragment avec la formule précédente.
![]() |
![]() |
![]() |
$e=0.75$ / $\gamma=0.8$ | $e=1$ / $\gamma=1$ | $e=1.5$ / $\gamma=1.2$ |
Extensions possibles : Vous pouvez ajouter un effet de bloom par convolution de l'image HDR avant tone mapping et composition avec l'image originale. Pour permettre une meilleure reproduction de la tonalité de l'image, vous pouvez également implémenter un opérateur de tone mappin plus avancé (quelques références).