Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Sombras Volumétricas

Iniciado por marcode, 01 de Marzo de 2006, 11:11:36 PM

« anterior - próximo »

marcode

 Tengo implementado un sistema de sombras volumétricas mediante el z-fail, y va perfecto, pero falla cuando la cámara está dentro del volumen, he cerrado el volumen totalmente poniéndole "las tapas" como creo que debe hacerse, pero sigue fallando.

He de reseñar que el volumen no está proyectado al infinito si no a una distancia determinada (pero suficiente para atravesar los muros y el suelo). ¿puede ser por eso?.

A ver si alguien se le ocurre a que puede deberse, o le ha pasado algo parecido.  
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

Yoshi.css

 ¿Puedes poner el código que genera las sombras?, más que nada por tener algo que comprobar.

Hace un par de meses me tuve que pelear con sombras en OpenGL para la asignatura de Informática Gráfica, quizás te pueda ayudar.

MrSickman

 Informatica Grafica... me suena mucho esa asignatura... y en OpenGL...
No estudiaras en Salamanca...
a href='http://gpufever.blogspot.com/' target='_blank'>GPUFever blog

Yoshi.css

 Nop, en la Complutense ( Madrid )  :D  

marcode

 Esta es la parte donde se dibuja el volumen de la sombra, la he visualizado con color y está bien cerrada.


// se activan los estados necesarios

glColorMask(false, false, false, false);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GREATER);
glDepthMask(false);

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0);

glVertexPointer(3, GL_FLOAT, 0, Vertex);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_INDEX_ARRAY);

// Se dibuja las caras traseras y se incrementa el stencil si el test de profundidad falla
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
glCullFace(GL_FRONT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, nVertex);
glDrawElements(GL_TRIANGLE_FAN, nIndex, GL_UNSIGNED_SHORT, IndNear);
glDrawElements(GL_TRIANGLE_FAN, nIndex, GL_UNSIGNED_SHORT, IndFar);

// Luego las delanteras, pero decrementando
glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
glDrawArrays(GL_TRIANGLE_STRIP, 0, nVertex);
glDrawElements(GL_TRIANGLE_FAN, nIndex, GL_UNSIGNED_SHORT, IndNear);
glDrawElements(GL_TRIANGLE_FAN, nIndex, GL_UNSIGNED_SHORT, IndFar);


// se restablecen los estados
glDisable(GL_STENCIL_TEST);
glColorMask(true, true, true, true);
glDepthMask(true);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_INDEX_ARRAY);

size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

Yoshi.css

 La generación de sombras con stencil-buffer usando zFail lo entendí en su día como:

1.- Primero dibujamos la escena en el buffer de profundidad (z-buffer ). NO dibujamos en el de color, NI hacemos el stencil-test.
2.- Activamos el stencil-test y lo configuramos para que siempre lo supere e incremente en 1 el valor del stencil del pixel cuando falle la comparación de profundidad con el z-buffer. Desactivamos el dibujado en el z-buffer, pero NO el buffer en sí.
3.- Dibujamos las caras traseras del volúmen de la sombra.
4.- Configuramos para que decremente en 1 el valor del stencil cuando falle el test con la z.
5.- Dibujamos las caras delanteras del volúmen de la sombra.
6.- Configuramos ahora el stencil-test para que pasen el test todos aquellos píxeles cuyo valor de stencil sea igual a cero.
7.- Dibujamos la escena tal cual.

Faltan cosas, como el tratamiento de la iluminación, etc... que no contemplo para no sobrecargarlos, pero creo que los pasos para generar sombras utilizando stencil y zFail son éstos. No se si hay otra forma de hacerlo, el tiempo apremiaba, las prácticas se acumulaban y lo único que pude sacar en claro con toda la información recopilada se resumen más o menos en éstos 7 puntos.

Comprobando tu código con éstos, hay algunos que te saltas, así que pienso que lo mejor es que compares con el código que utilicé, y ver si así puedes sacar algo en claro.

Citar...Algo de código por aquí arriba...

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

glEnable(GL_DEPTH_TEST); //Habilita el test de profundidad.
glDepthFunc(GL_LEQUAL); //Ecuación de comparación.
glDepthMask(GL_TRUE); //Indicamos que queremos dibujar en el buffer de profundidad.

glDisable(GL_STENCIL_TEST); //No queremos test de stencil.
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); //No queremos dibujar en el buffer de color.

//Dibujamos fondo y objetos que van a producir sombras. Solo actualiza el buffer de profundidad.
DibujarObjetos();

//Ahora dibujamos las sombras.
glEnable(GL_CULL_FACE);

glEnable(GL_STENCIL_TEST); //Activamos el test de stencil.
glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); //Hacemos que siempre supere el test.
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); //Si falla en el test de profundidad, incrementamos en 1                                             
//el valor del stencil para los píxeles que no lo pasen.

glDepthMask(GL_FALSE); //No queremos dibujar en el buffer de profundidad, pero queremos acceder
//a sus valores, de ahí que no se deshabilite el test de profundidad.

glCullFace(GL_FRONT); //Recortar caras delanteras del volúmen sombra.
DibujarSombras(); //Dibujar el volúmen sombra.

glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); //Si falla el test de profundidad, decrementamos en 1                                                 
//el valor del stencil para los píxeles que no lo pasen.

glCullFace(GL_BACK); //Recortamos las caras traseras.
DibujarSombras(); //Dibujamos el volúmen de sombra.

glDepthMask(GL_TRUE); //Volvemos a dibujar en el buffer de profundidad.
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); //Ya queremos dibujar en el buffer de color.

//Dibujamos los objetos. No se dibujan las zonas alcanzada por el volúmen de la sombra.
glStencilFunc(GL_EQUAL, 0, 0xFFFFFFFF); //Condición del test stencil. Todos los píxeles que sean igual a cero pasan el test.
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); //No hacemos nada en los valores del stencil.
glColor3f( 0.8, 0.8, 0.8 );
DibujarObjetos();

//OPCIONAL: Dibujamos la zona alcanzada por la sombra con un color diferente. No se si es la mejor forma, pero no tenía mucho tiempo por delante para probar otras cosas :D
glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColor3f( 0.2, 0.2, 0.2 );
DibujarObjetos(); //Dibuja los objetos con el color de la sombra.

... código para dejar los estados con los valores deseados para seguir con el programa...

Y para que veas que funciona :rolleyes:


Fuera del volúmen sombra.



Dentro del volúmen sombra.

Espero que te sirva de algo.

Salu2.

marcode

 Yo lo que hago (más o menos) es:

1. Dibujar la escena sólo con luz ambiente

2. Obtener la geometría del volumen de la sombra de cada objeto.

3. Dibujar los volumenes para determinar las zonas sombreadas con el stencil

4. Dibujar la escena de nuevo con luz difusa y especular donde no esté sombreado, con el test de profundidad a GL_EQUAL

Funciona muy bien, no se ve ningún defecto, perfecto, y va muy rápido (o eso me parece), pero cuando la cámara entra en la sombra falla.

Creo que es por las tapas del volumen que no se hacia donde tienen que estar orientadas, o si tengo que poner solo una o las dos, pero he probado de todo y nada.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

Yoshi.css

 En el triángulo que utilizo, las "tapas" apuntan hacia afuera. Así, cuando haces la primera pasada con el recortado de las caras frontales se dibuja la "tapa" inferior.

CitarFunciona muy bien, no se ve ningún defecto, perfecto, y va muy rápido (o eso me parece), pero cuando la cámara entra en la sombra falla.
Leyendo en la wikipedia Stencil Shadow Volume, lo que estarías haciendo es generar sombras a través del modo z-Pass ( o Depth Pass ), en vez del z-Fail, de ahí que te falle cuando entres en el volúmen.

Espera, que pongo los dibujos que utilicé para el trabajo:

1.- Tenemos esta escena. Un cuadrado y la luz.

En primer lugar se dibuja la escena tal cual, sin iluminación, en el z-buffer.

2.- Calculamos el volúmen de la sombra. Las "tapas" hacia afuera.


3.- Dibujar las caras traseras del volúmen de la sombra ( stencil-test activado, dibujar en z-buffer desactivado ).

Ahora bien, el z-Fail lo que hacemos es que siempre pase el test de stencil ( que siempre se dibuje ), pero incrementando en 1 el stencil del píxel cuando falle el test con la Z de ése píxel. En otras palabras, todo lo que esté por detrás ( atraviese el suelo, en éste ejemplo ) adquiere en el valor del stencil un valor distínto de cero ( inicialmente al borrar el stencil-buffer el valor es cero ).

4.- Dibujar las caras delanteras del volúmen.

Igual que en el paso anterior, salvo que ahora todos los píxeles que fallen el z-test, se decrementan en 1. Si solo hay una sombra, el nuevo valor vuelve a quedar en cero.

5.- Solo queda dibujar la escena teniendo en cuenta solo aquellos píxeles cuyo stencil valga 0.


Salu2.

Pogacha

 Que buena explicación.
Saludos.

marcode

 Y tan buena que ya lo he resuelto.  (ole)

Resulta que tenía el volumen con las caras frontales por dentro, y como ponía el Depth a GL_GREATER daba como resultado una especie de z-fail invertido que funcionaba como un z-pass.

Lo he resuelto fácil cambiando la dirección del strip.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.