Este es parte de mi trabajo sobre la generación de Sombras con Stencill Buffer para la informática gráfica:

Con Stencil a la izquierda y sin Stencil a la derecha. A la derecha simplemente hay una esfera debajo, es la forma mas simple de crear reflejos.
Introducción.
No hace mucho tiempo en los inicios de juegos en 3 dimensiones la programación visual de los juegos era básicamente: aplicar texturas sobre polígonos, dibujarlos en la pantalla y que el buffer de profundidad haga el resto. Por eso quizás todos los juegos o básicamente su mayoría se parecían en mayor o menor medida. Seguramente tendrían diferencias en la jugabilidad, diseño, sonido o juego en red. Pero la mayor diferencia siempre esta en el aspecto visual y así seguirá hoy y en el futuro.
Dos efectos que hacen diferenciar y aumentar la calidad del aspecto visual del juego son reflexiones y sombras. Este trabajo esta enfocado en técnicas de creación de sombras usando Stencil Buffer.
Stencill Buffer es una memoria intermedia que analiza y actualiza píxeles (con sus operaciones) junto con “depth buffer” o buffer de profundidad. Añade planos de bits adicionales para cada píxel además de los bits de color y profundidad.
Para comprender mejor Stencil Buffer se puede pensar que simplemente etiqueta los píxeles en la interpretación o renderización de la escena en la pantalla para controlar las siguientes interpretaciones. Los pasos son siguientes:
- Dada una escena con una sombra fija. Los píxeles de la escena se podrían considerar con “dentro” de la sombra o “fuera”. Asumimos que podemos etiquetar cada píxel apropiadamente.
- Cuando los píxeles ya son etiquetados, actualizamos los píxeles etiquetados como “dentro” de la sombra. Y renderizamos la escena con la fuente de luz desactivada.
- Después actualizamos los píxeles etiquetados como “fuera” de la sombra. Activamos la luz y renderizamos otra vez.
Prueba “Stencil” por píxel.
Para explicar “Stenciling” debemos asumir la existencia de “Stencil buffer” así como explicar que es. Stencil buffer es similar al buffer de profundidad en que los dos son colección de planos de bit que no se pueden mostrar. Del mismo modo que el buffer de profundidad asocia a cada píxel de la ventana un valor de profundidad, el stencil buffer asocia su propio valor a cada píxel mostrado. Cuando el buffer de profundidad esta activado los valores de profundidad son usados para aceptar o rechazar fragmentos, del mismo modo los valores de Stencil buffer son usados para aceptar o rechazar fragmentos.
El primer paso para usar stencil buffer es inicializar la ventana que lo soporte. Mediante modulo GLAUX es fácil de hacer. Tenemos que inicializar ventana mediante esta función:
auxInitDisplayMode(AUX_DOUBLE | AUX_DEPTH | AUX_STENCIL);
Si lo hacemos mediante GLUT tenemos que usar esto:
glutInitDisplayString(“stencil>=1 rgb depth double”);
El valor “stencil” en si es un entero sin signo (unsigned int). Este entero se puede incrementar, decrementar, comparar y enmascarar. En comparación con buffer de profundidad el valor de profundidad que va de 0 a 1 no se puede decrementar, incrementar, ni enmascararlo.
Tipicamente en principio del renderizado de una escena, stencil buffer es liberado o se establece un valor por defecto. La liberación o despejado se hace junto al buffer de profundidad y de color.
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
Igual que el análisis de profundidad el “stencil test” se puede habilitar o deshabilitar, cuyo resultado es que los fragmentos son descartados o van mas adelante. Cuando esta habilitado los fragmentos o píxel son probados. Si esta habilitado y el test o la prueba falla entonces el píxel o fragmento es descartado. De otra manera si el stencil test esta deshabilitado el píxel sigue su curso de procesamiento.
glEnable(GL_STENCIL_TEST);
glDisable(GL_STENCIL_TEST);
Se puede pensar que el stencil test es un obstáculo, como prueba de profundidad (depth test) o prueba de transparencia (alpha test). El stencil test es realizado después del test de transparencia y antes del test de profundidad (Figura 1). El orden de estas operaciones parece a simple vista arbitrario, en realidad es un algoritmo crucial. Los tres test (depth, alpha y stencil) realizan una comparación.
Depth: Compara valores de píxel con los almacenados en el buffer.
Alpha: Compara valores de alpha de píxel con un valor de referencia. (No existe ningún apha buffer).
Stencil: Compara los pixeles del Stencil buffer con el valor de referencia.
Afortunadamente los tres comparten 8 funciones de comparación: Nunca, Siempre, <, <=, >, >=, =, ¬ =.
La funcion de comparación en OpenGL se establece asi:
glStencilFunc(GL_EQUAL, //Función de comparación.
0×1, //Valor de referencia.
0xff); //Mascara de comparación.
Cuando el test Alpha falla simplemente el fragmento es descartado. Cuando es aprobado simplemente sigue hacia delante. El test de profundidad es más complejo. Si el test de profundidad falla el fragmento es descartado sin ningún efecto. En el caso de que lo pasa entonces el valor de profundidad del píxel reemplaza al valor del almacenado en el buffer. El test Stencil es bastante mas complicado. Tiene tres efectos de actualización que dependen de:
- Stencil test falla.
- Stencil pasa pero depth falla.
- Stencil y depth pasan.
El programador puede configurar las tres operaciones dependiendo de los tres casos. Las 6 operaciones estándar (hay dos operaciones mas en realidad implementadas en direct3D) son las siguientes:
- GL_KEEP: deja el valor de stencil sin modificar.
- GL_REPLACE: actualiza el buffer con el valor actual.
- GL_ZERO: limpia el valor.
- GL_INCR: añade uno al valor del píxel y lo actualiza en el buffer.
- GL_DECR: resta uno al valor del píxel y lo actualiza en el buffer.
- GL_INVERT: invierte los bits del valor del stencil.
Cuando los valores stencil son actualizados, se aplica una mascara de escritura “Stencil bit-mask”. Las operaciones y la mascara se establecen asi en OpenGL:
glStencilOp(GL_KEEP, //Stencil falla
GL_DECR, //Stencil pasa, profundidad falla
GL_INCR); //Stencil pasa, profundidad pasa
glStencilMask(0xff);
Cuando limpiamos el Stencil buffer tenemos que entender que después se aplica la mascara a ese valor. Esto puede crear confusión cuando limpiamos los valores de pixels y obtenemos un resultado no deseado. En el caso de querer borrar los valores de todos los bit-planos de stencil tenemos que llamar a glStencilMask(~0) antes de llamar glClear.
Pero para que necesitamos el stencil buffer? Como he dicho antes para dar más realismo en los juegos intentamos introducir sombras y reflejos. Las dos cosas se pueden perfectamente hacer sin la ayuda del stencil buffer. Además es bastante mas simple hacerlo sin el. Pero mas simple no significa mejor, ya que todas con los métodos normales tenemos demasiadas deficiencias.

[...] Administrando. Administrador de red pez, haciendo de todo y en poco tiempo… « Generación de sombras y reflejos con stencil buffer parte 1. [...]