Lesson 3 : Shadow Mapping

Au cours de cet tutoriel, vous implémenterez différentes variantes de l’algorithme du Shadow Mapping en OpenGL.

Consultez cette page pour récupérer le code de base, ou partez du code écrit pour la leçon précédente. L’algorithme peut s’implémenter aussi bien en Forward Shading qu’en Deferred Shading.

Shadow Mapping

Shadow Mapping

Rendre une shadow map

La technique du Shadow Mapping implique de comparer une profondeur ou depth stockée dans un depth buffer calculé dans l’espace de la lumière à une profondeur calculée dans l’espace écran, puis projetée dans l’espace de la lumière.

Construisez une scène de ce type, avec un seul spot light dirigé vers le sol.

shadowgen

Crée un nouveau Framebuffer Object

 

Créez un renderbuffer  de dimensions 512×512 et attachez le au framebuffer. On utilise ici un renderbuffer et non pas une texture car seule la depth sera utilisée pour le reste de la technique. Certains cartes graphiques ne supportent pas encore le fait d’avoir un framebuffer sans GL_COLOR_ATTACHMENT0.

Créez une texture de depth de dimensions 512×512. On utilise le paramètre  GL_CLAMP_TO_BORDER pour que le fait de lire la texture en dehors des coordonnées normalisées renvoie une couleur noire.

 

On attache la texture au framebuffer.

 

On teste la validité du framebuffer, puis on revient au framebuffer par défaut

On crée un nouveau fragment shader minimal ou pass-through qui servira uniquement au rendu de la profondeur.

Pour le vertex shader utilisez le même que celui que vous utilisez pour rendre la scène. Pensez au fait que la scène vue par la lumière doit correspondre à celle vue par la caméra. Créez le program object et préparez les uniform nécessaires pour votre scène.

Il faut maintenant rendre la scène du point de vue de la lumière. Cette passe de rendu doit bien évidemment avoir lieu avant la passe de calcul de l’illumination.

On calcule les matrices.

Rendez la scène en utilisant les matrices calculées.

 

Affichez la texture de depth  en overlay avec un  shader de blit. Modifiez la position de la lumière pour vérifier votre résultat.

 

Utiliser une shadow map

Ajoutez un uniform sampler2D dans le shader qui calcule l’illumination du spot.

Utilisez la shadow map calculée comme texture dans la phase d’illumination.

Affichez la dans le shader pour vérifier votre progression.

shadowviz

Vous avez calculé une matrice permettant de passer de l’espace monde à l’espace écran de la texture de profondeur.  Passez cette matrice au shader calculant l’illumination.

Dans le shader, appliquez cette matrice à la position, et affichez la coordonnée z. calculée lP.z.

depthlight

Utilisez les coordonnées xy de lP pour lire dans la texture de profondeur. Affichez le résultat.

shadowdepth

Affichez la différence entre le z projetée lP.z et la valeur lue dans la texture de profondeur.

shadowdiff

Vous pouvez à présent comparer les deux valeurs pour illuminer ou non la scène. Identifiez la provenance de l’artefact qui apparaît.

shadowcomp

Pour corriger cet artefact, il est possible d’appliquer un bias à la comparaison des deux valeurs. Ce biais dépend de la précision de la texture de profondeur, et donc de la distance surface/camera. Testez plusieurs valeurs, utilisez un uniform pour le faire varier.

shadowbias

Faites varier la résolution de la texture de profondeur de 128×128 à 4096×4096 comparez les différences de qualité et de performance. Observez le comportement sur les bords des ombres dans le cas d’une lumière ou d’une scène animée.

2×2 Percentage Closer Filtering

L’API OpenGL et les cartes graphiques modernes proposent un filtrage dédié aux shadow maps.

Rajoutez les deux paramètres suivants à la texture de profondeur. Attention une fois ces paramètres rajoutés vous ne pouvez plus récupérer la valeur de la texture en glsl.

Modifiez le sampler2D de la texture dans la passe d’illumination.

Vous ne pouvez plus lire dans la texture avec la fonction texture(). Il faut à la place utiliser la fonction textureProj. Cette fonction renvoie une valeur entre 0 et 1.

Arbitrary Percentage Closer Filtering

Pour améliorer la qualité des ombres, une solution possible est de tester la visibilité en plusieurs endroits pour chaque fragment. Utilisez les échantillons précalculés fournis pour calculer l’ombre en plusieurs endroits.

Un fragment pourra donc être dans la pénombre, s’il n’est pas occulté dans tous les échantillons. Faites varier les paramètres 0 <SampleCount < 16 et 0.0 < Spread < 1000.0 .

shadowpcf

Leave a Reply