[OpenGL] shadow volume

Le côté programmation du développement d'un jeu vidéo.

Messagepar yoyonel » 11 Aoû 2008, 22:43

Yo man !

Je vais reprendre en gros le tuto de nehe, étape après étape, en essayant d'être le plus explicite possible :-)

Initialisation :
Code: Tout sélectionner
// Sauvegarde de l'état opengl
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT );

glDisable( GL_LIGHTING );                    // Turn Off Lighting

glDepthMask( GL_FALSE );                    // Turn Off Writing To The Depth-Buffer
glDepthFunc( GL_LEQUAL );

glEnable( GL_STENCIL_TEST );                    // Turn On Stencil Buffer Testing
glStencilFunc( GL_ALWAYS, 1, 0xFFFFFFFFL );

glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );        // Don't Draw Into The Colour Buffer
Donc phase d'init., tu mets en place l'état pour le rendu des ombres : pas de lumière, pas d'écriture dans le buffer couleur, pour les phases de remplissage du stencil buffer on écrit tout le temps et sans mask.

On passe ensuite à la phase 1 de remplissage du stencil, avec les faces "avant" des shadow-quads, ils remplissent le stencil (ou l'incrémente plus précisement) que s'ils passent le test de profondeur (Z-Pass) :
Code: Tout sélectionner
// First Pass. Increase Stencil Value In The Shadow
glFrontFace( GL_CCW );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
// On dessine les shadow-quads
// => DrawShadowQuadScene(scene3D, light, ...);
La seconde phase décrémente le stencil buffer avec les faces "arrières" des shadow-quads quand ils passent le test de profondeurs (Z-Pass toujours :p) :
Code: Tout sélectionner
// Second Pass. Decrease Stencil Value In The Shadow
glFrontFace( GL_CW );
glStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
// On dessine les shadow-quads
// => DrawShadowQuadScene(scene3D, light, ...);
La dernière phase (3ème) met à jour le buffer de couleur pour retranscrire les informations contenues dans le stencil :

Code: Tout sélectionner
// re-activation du culling face dans le "bon" sens
glFrontFace( GL_CCW );
// on reactive l'écriture dans le buffer de couleur
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );    // Enable Rendering To Colour Buffer For All Components

// desactivation du test de profondeur
glDepthTest(GL_FALSE);

// on dessine un quad qui recouvre tout l'écran
// je fais faire ici une version "propre" mais pas forcément
// optimisée
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-1, +1, -1, +1); // (gauche, droite, haut, bas)

// Activation du blend pour sur-impression de l'ombre à l'écran
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

// Couleur de l'ombre (définit par le canal alpha)
glColor4f( 0.0f, 0.0f, 0.0f, 0.4f );

// Config du stencil test, tout les texels possèdant une valeur
// stencil différent de 0, sont des texels d'ombre (<= important
// à comprendre pourquoi c'est vrai !!!!)
glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); // <= on précise qu'on ne modifie plus le stencil buffer

// on dessine le quad qui recouvrira tout l'écran (voir matrix modelview/projection)
glBegin( GL_TRIANGLE_STRIP );
glVertex2f(-1.f,+1.f);
glVertex2f(-1.f,-1.f);
glVertex2f(+1.f,+1.f);
glVertex2f(+1.f,-1.f);
glEnd();

glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

// On restaure l'état opengl initial
glPopAttrib();
Une bonne idée pour débugger (comme le fait nehe d'ailleurs), serait d'isoler une fonction qui affiche le quad a la fin pour recouvrir l'écran et l'appeler (éventuellement) a chaque étape pour voir ce que fait les étapes et être sure que tout se passe bien. Pense a bien encapsuler tes méthodes avec des glPushAttrib dans tous les sens en debug pour etre sur de ne rien dérégler au fur et à mesure !


Bon je n'ai pas testé, donc il y a peut être des grosses bourdes, mais globalement ça reprend le tuto de nehe donc ça devrait tourner !

Tiens moi au courant,

YoYo
Avatar de l’utilisateur
yoyonel
Hello World, I'm new !
 
Messages: 105
Inscription: 12 Avr 2005, 21:25
Localisation: Lyon

Messagepar wishtchoco » 12 Aoû 2008, 11:30

Salut, et encore mille merci pour le coup de main! :00000025:

j'ai repris le code que tu m'as donné, et j'ai corrigé mon plan pour la dernière phase. J'ai essayé d'isoler un max de fonction avec des glPushAttrib( GL_ALL_ATTRIB_BITS ) et glPopAttrib() dans tous les sens, et rien n'y fait:

La première phase seule, me donne bien un volume d'ombre.
la deuxième phase seule, me donne une scène toute grise (couleur que j'ai choisie).

Si je compare au tuto de NEHE, j'ai les même résultats.

Remarque: Je ne dessine pas le sol lors de mes phases du stencil.
Est ce que ca peut jouer contre moi? Pourtant j'ai regardé dans le tuto, et eux non plus ne le dessine pas. Il trace le sol, puis l'objet, et demande l'ombre.
wishtchoco
Hello World, I'm new !
 
Messages: 32
Inscription: 18 Juil 2008, 10:27

Messagepar yoyonel » 12 Aoû 2008, 18:08

PfFffFFFf ...
je ne sais plus trop man ... j'ai comme qui dirait épuisé mon savoir lol

Essaie a tout hasard de régler manuellement (si c'est pas déjà fait),la couleur de clear du stencil :
Code: Tout sélectionner
glClearStencil( 0 );
et vérifie bien de l'effacer a chaque fois :
Code: Tout sélectionner
// Clear Color Buffer, Depth Buffer, Stencil Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
Bon juste au cas ou aussi,
ton point de vue (la caméra de visualisation) doit être en dehors d'un volume d'ombre avec cette méthode (z-pass) sinon ca bug, pour corriger ce problème plus tard tu passera au z-fail, mais c'est pas encore à l'ordre du jour vu ton avancement.

Second truc, essai de dessiner les volumes d'ombre de la phase 1 et 2 (CW et CCW) avec des couleurs transparentes (vert transparent et rouge transparent par exemple) pour voir ce que ca donne (pour cela tu dois desactiver les tests/ecriture dans le stencil (glStencilFunc, glStencilOp), et réactiver l'écriture dans le buffeur couleur (glColorMask(1, 1, 1, 1)).
Envoie des screenshots de tes résultats pour voir ce que ca donne :-)

DarkYoYo

ps : nan tu dois faire comme dans le tuto, le sol est ce qu'on peut appeler un shadow-receiver-only, donc il ne rentre pas dans la phase de mise à jour du stencil (il n'intervient que dans la phase du mise à jour du depthbuffer, ce qui est déjà le cas si tu l'affiches avant de traiter les ombres).

ps2 : dessine en mode fill de fer le dernier plan qui recouvre l'écran, avec un ... euhhh ... glPolygonMode(GL_FRONT_AND_BACK, GL_LINE), oublie pas de restaurer cet état après (avec GL_FILL), histoire d'être sur que tout est recouvert, mais à priori ca devrait être bon.
Avatar de l’utilisateur
yoyonel
Hello World, I'm new !
 
Messages: 105
Inscription: 12 Avr 2005, 21:25
Localisation: Lyon

Messagepar wishtchoco » 13 Aoû 2008, 09:33

Salut Yoyo,

Je suis désolé de chez désolé de t'emm.....é avec tout ca! :00000025:

Mais j'ai une presque bonne nouvelle (une demi bonne nouvelle!) J'ai rajouté un glEnable(GL_CULL_FACE) lorsque je crée mon plan...et "pop!" j'ai une "presque ombre" ! :p

Bon alors, je viens de faire ce que tu m'as demandé et ca fait ressortir le pourquoi "j'ai une ombre bizarre".

J'ai l'impression que je gère mal les facettes lorsque je leurs attributs des voisins....

A ton avis maître des ombres?
Fichiers joints
Presque_Bon.jpg
wishtchoco
Hello World, I'm new !
 
Messages: 32
Inscription: 18 Juil 2008, 10:27

Messagepar yoyonel » 13 Aoû 2008, 11:53

Yo !

J'adore les écrans de débug, ché pas ... ça donne une impression de compréhension en plus c'est zoli visuellement :p

Enfin bon, avec un screen comme ça de tes shadow-quads colorés, c'est normal que ton ombre ne soit pas correcte à la fin.

Je pense que tu as un problème d'orientation de tes shadow-quads ... par contre, c'est bizarre, j'ai lu ton code de génération des shadow-quads ça devrait fonctionner ...

Bon dans un 1er temps, je vais tenter d'expliquer la "philosophie" shadow-volume :

Le shadow volume est (à mon sens) une implémentation "astucieuse" du ray-tracing utilisant partiellement le GPU (rasterisation). Le but du shadow-volume via l'utilisation du stencil buffer est de compter le nombre de fois qu'un rayon de visualisation (un rayon partant de la caméra de visualisation) intercepte des volumes d'ombres avant d'intercepter un objet de la scène (théoriquement cet objet pour ce rayon de vue précis sera un receiver-only (comme ton plan support qui support les objet de ta scène)).

(1) Un rayon part de l'œil avec une valeur stencil de 0 (initialisation du stencil à 0), quand le rayon rencontre un shadow-quad orienté "avant" (CW ou CCW) la valeur stencil est incrémentée (+1), tant que le rayon reste à "l'intérieur" du volume d'ombre, sa valeur stencil reste à +1. S'il rencontre un nouveau volume d'ombre (face "avant" des shadow-quad), il continue a être incrémenté (+2, +3, etc ...).
Cette étape correspond normalement à la phase 1 de la mise à jour du stencil buffer.

(2) Ensuite, on compte le nombre de fois qu'il sort d'un volume d'ombre, ce qui est équivalent à compter le nombre de fois qu'on intercepte un shadow-quad orienté "arrière". A chaque fois, on décrémente la valeur du stencil (-1).

(3) Le processus s'arrête quand on rencontre un objet de la scene 3d (cet objet a inscrit son z dan le Z-Buffer, d'ou un Z-Fail à un moment donné), on doit alors regarder la valeur du stencil :
  1. si la valeur est > 1 : on est rentré dans au moins plus d'un volume d'ombre sans en ressortir (rencontre de faces "avant" de shadow-quads et non interception des faces "arrières" qui referment les volumes d'ombre). On doit alors ombrer le texel correspondant.
  2. si la valeur est == 0 : 2 cas possibles. On est soit rentré et sortie de tous les volumes d'ombre rencontrés ((entré +1, sortie -1) * nombre_de_volume_d_ombre_rencontrés = 0). Le second correspond à aucune interception de volume d'ombre donc on reste avec la valeur initiale.
  3. si la valeur < 0 (impossible techniquement (clamp des valeurs stencil) mais possible théoriquement) : là on est dans un bug lié à la méthode, ça signifie que le rayon est sortie plus de fois qu'il est rentré. Le seul cas possible est la caméra de visualisation à l'intérieur au départ d'un plusieurs volumes d'ombre. Ce cas sera traité par une extension de la méthode Z-Fail (à voir quand tu auras résolu tes autres problèmes :-)).
Bon ceci étant dit, qu'est ce que tu aurais du avoir dans ton screenshot (du post précédent) ???

Avec la sphère (bon choix d'objet simple à analyser ;-)), tu devrais avoir tout un coté rouge (shadow-quad orienté "avant" (par ex.)) et tout un coté vert (shadow-quad orienté "arrière").
Les bandes alternées ... c'est vraiment pas bon !

A priori, le problème doit venir de l'orientation des shadow-quads construis à partir des edges (arêtes de contour) du shadow_caster.

Une idée que tu peux utiliser pour débugger :
Affiche dans un screenshot les arêtes de contour calculées en mode ligne (glBegin(GL_LINES)), en associant deux couleurs différentes pour le début et la fin du segment : Segment (Edge) AB, tu associes bleu au vertex A et jaune au vertex B.
Ca te permettra d'observer si il y a une cohérence d'orientation des edges : pour un cycle d'arêtes de contour, tu dois toujours avoir une succession de couleurs : Bleu - Jaune - Bleu - Jaune - Bleu - Jaune ... etc...
Si il y a un souci de ce coté, règles le et ça devrait (ENFIN) fonctionner !

Tiens moi au courant,

!DarkMasterYoYo!

ps : tu ne m'emmerdes pas ! Je ne suis pas obligé de t'aider, je le fais de bon coeur, ça me permet de réfléchir en même temps et d'évaluer mon coté pédagogue :p
ps2 : je pense que tu n'es vraiment pas loin pour le shadow-volume, après il te restera la technique de shadow-map à faire fonctionner lol
Avatar de l’utilisateur
yoyonel
Hello World, I'm new !
 
Messages: 105
Inscription: 12 Avr 2005, 21:25
Localisation: Lyon

Messagepar wishtchoco » 13 Aoû 2008, 21:23

Salut Man! :p

Ca marche, ca y est!!!!!!!

Comme tu me l'as dit j'ai vérifié l'ordre de calcul de la frontière puis des shadow quads.

En utilisant des couleurs différentes pour chaque point, j'ai bien vu que je construisais des shadow quads dans un mauvais sens. Ceci était lié à un mauvais odre d'appel de la fonction de tracé des shadow quads.
Je mettrais les screen shots demain sur le forum.

Tu avais trop raison!

Encore mille mercis man! T'es le roi des ombres! :p
wishtchoco
Hello World, I'm new !
 
Messages: 32
Inscription: 18 Juil 2008, 10:27

Messagepar yoyonel » 13 Aoû 2008, 23:11

Ah bin voila une bonne nouvelle ! Enfin ! :p

Bon au vu de tes screens ça se sentait trop ce problème d'orientation des edges, il n'y a pas de magie après tout, mais c'est cool que je sois tombé direct sur le problème (et c'est cool que tu n'es finalement que ce problème à résoudre pour faire fonctionner cet algo !).

Bon, fait péter les screens demain (avec les debugs et tout ! :-D), et après on passera à l'extension Z-Fail si tu le souhaites.

A peluche, jeune padawan !

!YoYoDa!
Avatar de l’utilisateur
yoyonel
Hello World, I'm new !
 
Messages: 105
Inscription: 12 Avr 2005, 21:25
Localisation: Lyon

Messagepar valentin » 18 Aoû 2009, 18:57

Image

helphelp

yo yoyonel (ou autre),

visiblement tu es l'expert shadow.
donc voila mon pb,
comme on le voit jveux faire de shadow volume , ici jai affiché betement le volume.

mais qd maintenant je fais :
Code: Tout sélectionner

// Sauvegarde de l'état opengl
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT );

glDisable( GL_LIGHTING );                    // Turn Off Lighting

glDepthMask( GL_FALSE );                    // Turn Off Writing To The Depth-Buffer
glDepthFunc( GL_LEQUAL );

glEnable( GL_STENCIL_TEST );                    // Turn On Stencil Buffer Testing
glStencilFunc( GL_ALWAYS, 1, 0xFFFFFFFFL );

glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); 



      glFrontFace( GL_CCW );
      glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
      for(int i=2;i<4;i++)
      {
         for(int j=2;j<4;j++)
         {
            vaisseau->render_shadow(6.f*i,6.f*j,0,10,0,0,position[0],position[1],position[2]);
         }
      }

      glFrontFace( GL_CW );
      glStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
      for(int i=2;i<4;i++)
      {
         for(int j=2;j<4;j++)
         {
            vaisseau->render_shadow(6.f*i,6.f*j,0,10,0,0,position[0],position[1],position[2]);
         }
      }

// on dessine un quad qui recouvre tout l'écran
// je fais faire ici une version "propre" mais pas forcément
// optimisée
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-1, +1, -1, +1); // (gauche, droite, haut, bas)

// Activation du blend pour sur-impression de l'ombre à l'écran
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

// Couleur de l'ombre (définit par le canal alpha)
glColor4f( 255.0f, 0.0f, 0.0f, 0.4f );

// Config du stencil test, tout les texels possèdant une valeur
// stencil différent de 0, sont des texels d'ombre (<= important
// à comprendre pourquoi c'est vrai !!!!)
glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); // <= on précise qu'on ne modifie plus le stencil buffer

// on dessine le quad qui recouvrira tout l'écran (voir matrix modelview/projection)
glBegin( GL_TRIANGLE_STRIP );
glVertex2f(-1.f,+1.f);
glVertex2f(-1.f,-1.f);
glVertex2f(+1.f,+1.f);
glVertex2f(+1.f,-1.f);
glEnd();

glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

// On restaure l'état opengl initial
glPopAttrib();


surprise rien ne se passe, jme demandai si javai pas oublié d'initialiser un truc opengl...
pour linstant au début du programme j'initialise que ça:
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glAlphaFunc(GL_GREATER,1);
Avatar de l’utilisateur
valentin
Hello World, I'm new !
 
Messages: 494
Inscription: 20 Mai 2008, 16:10
Localisation: GRENOBLE

Messagepar valentin » 18 Aoû 2009, 19:25

oura cest bon, jai consulté le tuto de nehe, que je n'avais pas encore consulté honte à moi... ( jvai pouvoir faire des jolies choses maintenant) \o/
Avatar de l’utilisateur
valentin
Hello World, I'm new !
 
Messages: 494
Inscription: 20 Mai 2008, 16:10
Localisation: GRENOBLE

Précédente

Retourner vers Programmation

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 2 invités

cron