TP3 : Shaders avancés
Détection des silhouettes
Nous allons réaliser la détection des silhouettes par un traitement d'image, puis compositer le résultat obtenu avec le rendu toon du TP1. Le principe est d'utiliser un filtre détecteur de contour comme celui de Sobel :
H =
-1 -2 -1
0 0 0
1 2 1
V =
1 0 -1
2 0 -2
1 0 -1
résultat = sqrt(H² + V²)
Un tel filtre va détecter la différence d'intensité entre deux pixels consécutifs. Plus la différence entre la valeur du pixel considéré et les valeurs des pixels l'entourant est grande, plus le contour sera marqué. Dans notre cas, pour détecter les silhouettes, ce ne sont pas les variations de couleur qui nous intéressent, mais celles de profondeur. Ainsi, il faut appliquer le filtre sur le depth buffer pour que les changements de profondeur soient marqués par un contour.
Cependant, la convolution d'une image (de couleur ou de profondeur) avec un filtre nécessite d’accéder à plusieurs pixels de l’image, ce qui est impossible en une seule passe de rendu. Nous allons donc utiliser la technique du "deferred shading" pour dessiner dans des textures le rendu toon et la carte de profondeur, avant d'appliquer une seconde passe sur les images 2D obtenues pour en extraire les silhouettes et les compositer avec le toon shading. Il faut pour cela utiliser un FrameBufferObject (FBO) et l'attribut gl_FragCoord du fragment shader pour connaitre la position du fragment courant dans l'image.
Modifier la valeur du seuil du filtre. Quelles sont les limitations de cette approche ?
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. L'environement map peut être vu comme une sphère ou une boîte englobant toute la scène. Il existe plusieurs façons de représenter un environnement : textures sphériques, textures paraboidales, textures cubiques... Cette dernière représentation est la plus simple à utiliser avec OpenGL et de nombreuses "cube maps" sont disponible sur le net (ici par exemple et sur la page de Paul Debevec).
Dans le fragment shader, utilisez un samplerCube pour lire la couleur de l'environnement dans la direction de réflexion fonction GLSL reflect) et/ou de refraction (refract) du vecteur de vue. Vous pourrez alors combiner les deux couleurs obtenues en fonction de l'approximation de Schlick de l'équation de Fresnel :
F = f + (1 - f) (1 - V • N)5 avec f = (1 - n1 / n2)² / (1 + n1 / n2)²
Images à grande dynamique
Le viewer OpenGL fournis vous permet de charger des cartes d'environnement HDR (au format RADIANCE). Vous pouvez les visualiser et éditer en utilisant le logiciel libre et multi-plateformes Luminance HDR.
Contrairement au 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 defaut un mapping linéaire non contrôlable est effectué.
Nous allons tout d'abord permettre à l'utilisateur de contrôler uniformément l'exposition et le gamma de la scène. Pour cela, effectuons à nouveau le rendu principal dans un FBO (floattant) et modifions la texture obtenue en la multipliant par une constante pour changer l'exposition et en l'élevant à la puissance pour modifier le gamma.
exposition=0.75 / gamma=0.8 | exposition=1 / gamma=1 | exposition=1.5 / gamma=1.2 |
Pour permettre une meilleure reproduction de la tonalité de l'image, vous pouvez implémenter un opérateur de "tone mapping" plus avancé (quelques références).
Ombres
Nous allons implémenter la technique de "shadow mapping" présentée en cours. Pour cela, il nous faut réaliser deux passes de rendu :
- la première, dans un buffer, depuis la lampe, pour obtenir la carte de profondeur (comme pour l'extraction des silhouettes),
- la seconde depuis la caméra en comparant la profondeur courante à celle du précédent depth buffer (sampler de texture GLSL sampler2DShadow).