Anuncios Google

Lecciones 23-24 y Practicas 09-10

Tutoriales de Programaciones

23.- No se vayan todavía aún hay más... Buffers:

Pues sí, aún hay más. Ya vimos anteriormente los buffers de color y de profundidad, pues aún nos quedan otros dos más, el "Buffer de Estarcido" y el "Buffer de Acumulación".

El buffer de estarcido es muy útil para limitar zonas espaciales donde poder dibujar. Como OpenGL no proyecta sombras, las tenemos que dibujar nosotros y si no tenemos cuidado podemos dibujar una sombra fuera del suelo u a travesando una pared.

Así que dibujando primero el suelo en el buffer de estarcido y en el de color, podemos crear un área espacial donde sólo en ella podamos dibujar las sombras. Luego dibujamos las sombras proyectadas por los objetos verificando que estén dentro del área espacial que delimita el buffer de estarcido. Y por último pintamos los objetos que proyectan las sombras.

 // -- HACER LA MÁSCARA DEL SUELO --
  glClearStencil( 0 );
  glClear( GL_STENCIL_BUFFER_BIT );
  glDisable( GL_DEPTH_TEST );
  glEnable( GL_STENCIL_TEST );
  glStencilFunc( GL_ALWAYS, 1, 1 );
  glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
// -- DIBUJAR EL SUELO [ FALTA CÓDIGO ]--
// -- TERMINAR LA MASCARA DEL SUELO --
  glStencilFunc( GL_EQUAL, 1, 1 );
  glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
// -- APAGAR LA LUZ Y ACTIVAR LAS TRANSPARENCIAS --
  glPushAttrib( GL_LIGHTING_BIT );
  glDisable( GL_LIGHTING );
  glEnable( GL_BLEND );
// -- DIBUJAR LAS SOMBRAS [ FALTA CÓDIGO ] --
// -- DESACTIVAR LAS TRANSPARENCIAS Y ENCENDER LA LUZ --
  glDisable( GL_BLEND );
  glPopAttrib();
  glEnable( GL_DEPTH_TEST );
  glDisable( GL_STENCIL_TEST );
// -- DIBUJAR LOS OBJETOS QUE PROYECTAN SOMBRAS [ FALTA CÓDIGO ] -- 

glStencilMask( 1 );    // Permite escribir en el Stencil Buffer.
glStencilMask( 0 );    // No permite escribir en el Stencil Buffer.
glClearStencil( GLint s );        // Valor para limpiar el Stencil Buffer.
glClear( GL_STENCIL_BUFFER_BIT ); // Limpia el Stencil Buffer.
glEnable( GL_STENCIL_TEST );      // Activa el Stencil Buffer.
glDisable( GL_STENCIL_TEST );     // Desactiva el Stencil Buffer.
glStencilFunc( GLenum funcion, GLint referencia, GLuint mascara );
  funcion:
    - GL_NEVER Siempre falla (no se dibuja).
    - GL_LESS     Pasa si ( referencia & mascara ) < ( estarcido & mascara )
    - GL_EQUAL    Pasa si ( referencia & mascara ) == ( estarcido & mascara )
    - GL_LEQUAL   Pasa si ( referencia & mascara ) <= ( estarcido & mascara )
    - GL_GREATER  Pasa si ( referencia & mascara ) > ( estarcido & mascara )
    - GL_NOTEQUAL Pasa si ( referencia & mascara ) != ( estarcido & mascara )
    - GL_GEQUAL   Pasa si ( referencia & mascara ) >= ( estarcido & mascara )
    - GL_ALWAYS   Siempre pasa (siempre dibuja). 
glStencilOp( GLenum fallo, GLenum zfallo, GLenum zpasa );
  fallo:  Si Stencil Falla.
  zfallo: Si Stencil Pasa y Depth Test Falla.
  zpasa:  Si Stencil Pasa y Depth Test Pasa.
  funciones para los tres:
    - GL_KEEP    No modifica el buffer de estarcido.
    - GL_ZERO    Pone cero en el buffer de estarcido.
    - GL_REPLACE Pone el valor de referencia en el estarcido.
    - GL_INCR    Incrementa el valor actual del buffer de estarcido.
    - GL_DECR    Decrementa el valor actual del buffer de estarcido.
    - GL_INVERT  Invierte el orden binario del buffer estarcido. 

El buffer de acumulación sirve para capturar el buffer de color en un fotograma y aplicarle acumulaciones del color de otro fotograma/s. Esto básicamente sirve para simular el efecto de estela que deja un objeto cuando se mueve muy rápidamente en el encuadre de la cámara. También tiene alguna que otra aplicación pero en mis pruebas ralentiza demasiado y por eso no lo usaremos ni explicaré ejemplo alguno. Ver tabla inferior.

glAccum( GLenum func, GLfloat valor );
  funcion:
    - GL_LOAD   Copia el buffer de color al buffer de acumulación.
    - GL_RETURN Copia el buffer de acumulación al buffer de color. 
    - GL_ACCUM  Añade valores de color escalados al buffer de acumulación.
    - GL_ADD    Añade un color constante a los valores del buffer de acumulación.
    - GL_MULT   Multiplica el buffer de acumulación por un color dado.


24.- ¿Cómo hacer una sombra?:

El truco consiste en dibujar con la luz apaga la proyección de un objeto transparente en el suelo respecto a un punto de luz. Para ello necesitamos tres puntos del suelo, un objeto y la posición de la luz.

Con los tres puntos del suelo se calcula la ecuación del plano. Ahora se hace el producto mixto de la ecuación del plano por la posición del punto de luz y se calcula la matriz de la proyección de la sombra. Se multiplica la matriz de modelado por la matiz de la proyección de la sombra "glMultMatrixf( (const GLfloat *) Matriz_Sombra );" y se dibuja el objeto.

Ahora imagínate que tienes ocho luces, el suelo no es llano y quieres que los objetos se hagan sombra entre sí... La cantidad de cálculos sería impresionante para hacerlos en tiempo real, así que no te emociones mucho con las sombras. Normalmente vasta pintar dos o tres sombras simples para engañar al espectador y punto pelota. Empezamos por calcular la ecuación del plano:

// -----------------------------------------------------------
// -- Cálculo de la Ecuación del Plano -----------------------
// -----------------------------------------------------------
// -- Tres Puntos -> GLfloat Puntos[9], GLfloat *Plano[4] ----
// -----------------------------------------------------------
void Ecuacion_del_Plano( GLfloat *Puntos, GLfloat *Plano ) {
  GLfloat longitud;
  GLfloat v1[3], v2[3], v3[3];
  v1[0] = Puntos[3] - Puntos[0];
  v1[1] = Puntos[4] - Puntos[1];
  v1[2] = Puntos[5] - Puntos[2];
 
  v2[0] = Puntos[6] - Puntos[3];
  v2[1] = Puntos[7] - Puntos[4];
  v2[2] = Puntos[8] - Puntos[5];
 
  v3[0] = ( v1[1] * v2[2] ) - ( v1[2] * v2[1] );
  v3[1] = ( v1[2] * v2[0] ) - ( v1[0] * v2[2] );
  v3[2] = ( v1[0] * v2[1] ) - ( v1[1] * v2[0] );
  longitud = (GLfloat)sqrt( (v3[0]*v3[0]) + (v3[1]*v3[1]) + (v3[2]*v3[2]) );
  if( longitud == 0.0f ) longitud = 1.0f;
  v3[0] /= longitud; v3[1] /= longitud; v3[2] /= longitud;
 
  Plano[0] = v3[0];
  Plano[1] = v3[1];
  Plano[2] = v3[2];
  Plano[3] = - ( ( Plano[0] * Puntos[6] ) +
                 ( Plano[1] * Puntos[7] ) +
                 ( Plano[2] * Puntos[8] )    );
} 

Dibujamos el suelo ( con ya sabemos con el stencil buffer ) y calculamos la matriz de proyección de la sombra.

// -----------------------------------------------------------------------------
// -- Cálculo de la Matriz de Sombreado ----------------------------------------
// -----------------------------------------------------------------------------
// GLfloat Plano[4], GLfloat Luz_Pos[4]
// -----------------------------------------------------------------------------
const void Hacer_Sombra( GLfloat *Plano, GLfloat *Luz_Pos ) {
 
  GLfloat Dot;
  GLfloat Matriz_Sombra[4][4];
 
  // -- Producto mixto del plano y la posición de la luz --
  Dot = ( Plano[0] * Luz_Pos[0] ) +
        ( Plano[1] * Luz_Pos[1] ) +
        ( Plano[2] * Luz_Pos[2] ) +
        ( Plano[3] * Luz_Pos[3]      );
 
  // -- Ahora hace la proyección --------------------
  Matriz_Sombra[0][0] = Dot  - Luz_Pos[0] * Plano[0];
  Matriz_Sombra[1][0] = 0.0f - Luz_Pos[0] * Plano[1];
  Matriz_Sombra[2][0] = 0.0f - Luz_Pos[0] * Plano[2];
  Matriz_Sombra[3][0] = 0.0f - Luz_Pos[0] * Plano[3];
 
  Matriz_Sombra[0][1] = 0.0f - Luz_Pos[1] * Plano[0];
  Matriz_Sombra[1][1] = Dot  - Luz_Pos[1] * Plano[1];
  Matriz_Sombra[2][1] = 0.0f - Luz_Pos[1] * Plano[2];
  Matriz_Sombra[3][1] = 0.0f - Luz_Pos[1] * Plano[3];
 
  Matriz_Sombra[0][2] = 0.0f - Luz_Pos[2] * Plano[0];
  Matriz_Sombra[1][2] = 0.0f - Luz_Pos[2] * Plano[1];
  Matriz_Sombra[2][2] = Dot  - Luz_Pos[2] * Plano[2];
  Matriz_Sombra[3][2] = 0.0f - Luz_Pos[2] * Plano[3];
 
  Matriz_Sombra[0][3] = 0.0f - Luz_Pos[3] * Plano[0];
  Matriz_Sombra[1][3] = 0.0f - Luz_Pos[3] * Plano[1];
  Matriz_Sombra[2][3] = 0.0f - Luz_Pos[3] * Plano[2];
  Matriz_Sombra[3][3] = Dot  - Luz_Pos[3] * Plano[3];
 
  glPushAttrib( GL_LIGHTING_BIT ); // Guardamos la luz.
  glDisable( GL_LIGHTING );        // Apagamos la luz.
  glPushMatrix();                  // Guardamos la matriz.
  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable( GL_BLEND );   // Activamos las transparencias.
  glColor4f( 0.0, 0.0, 0.0, 0.2 );
  // -- Ahora Multiplica la Matriz --------------------
  glMultMatrixf( (const GLfloat *) Matriz_Sombra );
} 

Ahora dibujamos los objetos que proyecten sombra y usamos la función de abajo para restaurar diversas configuraciones.

const void Terminar_Sombra( void ) {
  glDisable( GL_BLEND ); // Quita las transparencias.
  glPopMatrix();         // Repone la proyección a normal
  glPopAttrib();         // Repone las iluminación
} 

Volvemos a dibujar los objetos que proyecten sombra y se acabó lo que se daba.


Práctica Nº 09 - Buffers

Usaremos los Buffers de Color, Profundidad y Estarcido. Hay otro llamado Buffer de Acumulación pero por mis pruebas no es válido para renderizar en tiempo real puesto que ralentiza demasiado.

El Buffer de Color es donde se dibuja, conviene vaciarlo con un color antes de dibujar el siguiente cuadro.

El Buffer de Profundidad sirve para no dibujar objetos delante de otros cuando no debe. Si primero dibujamos algo cerca de la cámara y después algo lejos, pues sin este buffer se dibujaría el objeto lejano encima del cercano.

Es Buffer de Estarcido vale para limitar la zona de dibujado. Esto es útil para dibujar agujeros en objetos, hacer cortinillas o limitar el dibujado de sombras y reflejos.

Descargar Practica nº09 (Solo usuarios registrados)


Práctica Nº 10 - Sombras

Dibuja la sombra de un objeto proyectada en el suelo por dos luces. Una direccional y la otra Puntual. Usa la Ecuación del Plano y STENCIL_BUFFER. Y para complicar un poco más la cosa, que las luces y el objeto estén en movimiento. Haz también su reflejo sobre el suelo.

Descargar Practica nº10 (Solo usuarios registrados)

4.62162
Tu voto: Ninguno Votos totales: 4.6 (37 votos)

Anuncios Google