[Tutorial] III.9 - Buffer de profundidad (DEPTH) y modo tijera (SCISSOR)
2 participantes
Página 1 de 1.
[Tutorial] III.9 - Buffer de profundidad (DEPTH) y modo tijera (SCISSOR)
III.9 - Buffer de profundidad (DEPTH) y modo tijera (SCISSOR)
Novedades:
La profundidad es algo realmente básico en el 3D, no tanto en el 2D. Pasaremos al 3D en el bloque IV, pero antes quiero inciarlo aquí. El buffer color guardaba el color de cada pixel que se mostraría en pantalla, y ahora tenemos dos de color con GLUT_DOUBLE. Añadamos un buffer más a nuestra lista, el GLUT_DEPTH, es un buffer aparte que guarda, pixel a pixel, a cuánta profundidad (en el eje Z) está el último pixel de color dibujado. Como siempre, es mejor ver primero el ejemplo, que es muy sencillo. (El buffer de profundidad es algo que se puede usar sin entenderlo, pero recomiendo entender todo lo que haces).
Esta es la salida del programa si se aplica la profundidad y el test de tijera.
Por partes, primero hay que explicar el buffer de profundidad, para ello uso estos cuadrados superpuestos:
El funcionamiento real del buffer es: cada vez que dibujas algo, se calcula en que pixeles se dibujaría, y se realiza un test, si este dibujo nuevo tiene un valor en Z menor o igual que el de la última figura dibujada, se verá, si está más lejos, el valor es mayor en Z, y por lo tanto no se vería. Tan simple como eso.
Ahora veamos el código para tenerlo más claro, primero veamos las novedades en IniciarGLUT():
En cuanto a glDepthRange(-1,1), simplemente sirve para cambiar (si quieres) el rango de datos de profundidad normalizada en la que deseas trabajar (la coordenadas normalizadas quiere decir que OpenGL trabaja con una distancia en Z de -1 como mínimo a 1 como máximo, pasando por todos los decimales, por defecto). De momento déjalo así.
Dentro de la función PintarEscena(), simplemente hacemos que se active GL_DEPTH_TEST si lo activas o no con la letra Z para que veas la diferencia. Los cuadrados que se dibujan, si no se activa la profundidad, se dibujan uno sobre el otro, empezando por la izquierda abajo hasta la derecha arriba, por lo que el último cuadrado de arriba a la derecha se superpone al anterior a pesar de estar más lejos en Z. Esto camiará cuando activemos la profundidad, ya dará igual cuando lo mandes pintar, como está por detrás solo se pintará la parte que no vaya a ser tapada por el anterior cuadrado.
Solo queda explicar el modo tijera, GL_SCISSOR_TEST se activará pulsando T, si hacemos esto se reducirá la zona donde se pintará según indiquemos con glScissor(100,100,ventana[0]-200,ventana[1]-200);. Indicando el punto desde el que empieza la zona que si es dibujable, y luego indicando el ancho y alto de esa zona. Si ya tienes práctica, te preguntarás que direfencia tiene esto con glViewport, pues muy sencillo, aunque dificil de explicar, pero lo intentaré. imagina que tienes un espacio que empieza en 0 en X e Y, y acaba en 5 en X e Y. Y mandas pintar un cuadrado en el centro de 1 de longitud de lado. Si aplicas glViewport()[i] para que no se pinte ni arriba ni abajo (como si vieses una peli panorámica en una pantalla cuadrada), las dimensiones de 5x5 del espacio virtual se moldearán al nuevo Viewport, y se achatará, y con el, el cuadrado resultante. Pero, si usas la tijera para que no se vea la zona de arriba ni de abajo, solo haces que no se vea de 0 a 1 en Y y de 4 a 5 en Y, pero no se achata, porque solo has recortado el dibujo resultante. Lo mejor es emperimentar, como siempre. Aparte de para esto, la tijera, se suele usar para ahorrar cálculos, mandando cortar justo en el borde de la ventana, tú no lo notas, pero evitas que se dibuje en una zona donde nada se llegaría a ver nunca, porque se sale de la pantalla. Como si tratas de ver un triángulo que no cabe en pantalla, se calcula el triángulo entero, y se manda dibujar (si se puede) entero, con la tijera no hace falta ni comprobar si hay algo que pintar fuera de la ventana, porque ya se deja claro que no. Asi que desde ahora, al igual que se hacia [i]glViewport(0,0,w,h), recomiendo añadir a tu función de Reshape un: glScissor(0,0,w,h).
Una cosa más: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT), ahora tienes dos bufferes que limpiar cada vez que re-pintes. O aquello empezará a sumarse y sería un caos, como si no limpias el buffer de color antes de pintar de nuevo la escena.
Novedades:
- Uso de GL_DEPTH_TEST en glEnable()
- Uso de GL_SCISSOR_TEST en glEnable()
- Uso de nuevo buffer: GLUT_DEPTH en glutInitDisplayMode()
- glDepthRange()
- glDepthFunc()
- glScissor()
La profundidad es algo realmente básico en el 3D, no tanto en el 2D. Pasaremos al 3D en el bloque IV, pero antes quiero inciarlo aquí. El buffer color guardaba el color de cada pixel que se mostraría en pantalla, y ahora tenemos dos de color con GLUT_DOUBLE. Añadamos un buffer más a nuestra lista, el GLUT_DEPTH, es un buffer aparte que guarda, pixel a pixel, a cuánta profundidad (en el eje Z) está el último pixel de color dibujado. Como siempre, es mejor ver primero el ejemplo, que es muy sencillo. (El buffer de profundidad es algo que se puede usar sin entenderlo, pero recomiendo entender todo lo que haces).
- Código:
#include <GL/glut.h>
int tijera, profundidad;
int ventana[2];
void IniciarGLUT() {
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600,600);
glutInitWindowPosition(100,100);
glutCreateWindow("Practica III,9 de OpenGL");
glDepthFunc(GL_LEQUAL);
glDepthRange(-1,1);
}
void PintarEscena() {
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
if (tijera) glEnable(GL_SCISSOR_TEST);
if (profundidad) glEnable(GL_DEPTH_TEST);
glScissor(100,100,ventana[0]-200,ventana[1]-200);
float i;
glBegin(GL_QUADS);
for (i=-10; i<9; i++) {
glColor3f((i+10)/20,0,0);
glVertex3i(i,i,-i);
glVertex3i(i+2,i,-i);
glVertex3i(i+2,i+2,-i);
glVertex3i(i,i+2,-i);
}
glEnd();
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glutSwapBuffers();
}
void ReProyectar(int w, int h) {
GLfloat formato;
ventana[0] = w;
ventana[1] = h;
if(h == 0) h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
formato = (GLfloat)w / (GLfloat)h;
if (w <= h) glOrtho (-10.0f, 10.0f, -10.0f / formato, 10.0f / formato, -10.0f, 10.0f);
else glOrtho (-10.0f * formato, 10.0f * formato, -10.0f, 10.0f, -10.0f, 10.0f);
}
void Teclado(unsigned char key, int x, int y) {
switch (key) {
case 'z': profundidad = !profundidad; break;
case 't': tijera = !tijera; break;
}
}
int main(int argc, char **argv) {
glutInit(&argc,argv); //Solo necesario en Linux
IniciarGLUT();
glutReshapeFunc(ReProyectar);
glutDisplayFunc(PintarEscena);
glutIdleFunc(PintarEscena);
glutKeyboardFunc(Teclado);
glutMainLoop();
return 0;
}
Esta es la salida del programa si se aplica la profundidad y el test de tijera.
Por partes, primero hay que explicar el buffer de profundidad, para ello uso estos cuadrados superpuestos:
- Código:
glBegin(GL_QUADS);
for (i=-10; i<9; i++) {
glColor3f((i+10)/20,0,0);
glVertex3i(i,i,-i);
glVertex3i(i+2,i,-i);
glVertex3i(i+2,i+2,-i);
glVertex3i(i,i+2,-i);
}
glEnd();
El funcionamiento real del buffer es: cada vez que dibujas algo, se calcula en que pixeles se dibujaría, y se realiza un test, si este dibujo nuevo tiene un valor en Z menor o igual que el de la última figura dibujada, se verá, si está más lejos, el valor es mayor en Z, y por lo tanto no se vería. Tan simple como eso.
Ahora veamos el código para tenerlo más claro, primero veamos las novedades en IniciarGLUT():
- Código:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
....
glDepthFunc(GL_LEQUAL);
glDepthRange(-1,1);
En cuanto a glDepthRange(-1,1), simplemente sirve para cambiar (si quieres) el rango de datos de profundidad normalizada en la que deseas trabajar (la coordenadas normalizadas quiere decir que OpenGL trabaja con una distancia en Z de -1 como mínimo a 1 como máximo, pasando por todos los decimales, por defecto). De momento déjalo así.
Dentro de la función PintarEscena(), simplemente hacemos que se active GL_DEPTH_TEST si lo activas o no con la letra Z para que veas la diferencia. Los cuadrados que se dibujan, si no se activa la profundidad, se dibujan uno sobre el otro, empezando por la izquierda abajo hasta la derecha arriba, por lo que el último cuadrado de arriba a la derecha se superpone al anterior a pesar de estar más lejos en Z. Esto camiará cuando activemos la profundidad, ya dará igual cuando lo mandes pintar, como está por detrás solo se pintará la parte que no vaya a ser tapada por el anterior cuadrado.
Solo queda explicar el modo tijera, GL_SCISSOR_TEST se activará pulsando T, si hacemos esto se reducirá la zona donde se pintará según indiquemos con glScissor(100,100,ventana[0]-200,ventana[1]-200);. Indicando el punto desde el que empieza la zona que si es dibujable, y luego indicando el ancho y alto de esa zona. Si ya tienes práctica, te preguntarás que direfencia tiene esto con glViewport, pues muy sencillo, aunque dificil de explicar, pero lo intentaré. imagina que tienes un espacio que empieza en 0 en X e Y, y acaba en 5 en X e Y. Y mandas pintar un cuadrado en el centro de 1 de longitud de lado. Si aplicas glViewport()[i] para que no se pinte ni arriba ni abajo (como si vieses una peli panorámica en una pantalla cuadrada), las dimensiones de 5x5 del espacio virtual se moldearán al nuevo Viewport, y se achatará, y con el, el cuadrado resultante. Pero, si usas la tijera para que no se vea la zona de arriba ni de abajo, solo haces que no se vea de 0 a 1 en Y y de 4 a 5 en Y, pero no se achata, porque solo has recortado el dibujo resultante. Lo mejor es emperimentar, como siempre. Aparte de para esto, la tijera, se suele usar para ahorrar cálculos, mandando cortar justo en el borde de la ventana, tú no lo notas, pero evitas que se dibuje en una zona donde nada se llegaría a ver nunca, porque se sale de la pantalla. Como si tratas de ver un triángulo que no cabe en pantalla, se calcula el triángulo entero, y se manda dibujar (si se puede) entero, con la tijera no hace falta ni comprobar si hay algo que pintar fuera de la ventana, porque ya se deja claro que no. Asi que desde ahora, al igual que se hacia [i]glViewport(0,0,w,h), recomiendo añadir a tu función de Reshape un: glScissor(0,0,w,h).
Una cosa más: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT), ahora tienes dos bufferes que limpiar cada vez que re-pintes. O aquello empezará a sumarse y sería un caos, como si no limpias el buffer de color antes de pintar de nuevo la escena.
Re: [Tutorial] III.9 - Buffer de profundidad (DEPTH) y modo tijera (SCISSOR)
Buenas,
Primero que nada queria agradecerte por estos tutoriales, son muy buenos y estan muy bien explicados por eso te animo a seguir con los tutos y a pasar al 3d, quiero 3d!! xD
Saludos,
Dani.
Primero que nada queria agradecerte por estos tutoriales, son muy buenos y estan muy bien explicados por eso te animo a seguir con los tutos y a pasar al 3d, quiero 3d!! xD
Saludos,
Dani.
nosek159- Cantidad de envíos : 1
Fecha de inscripción : 23/12/2010
Temas similares
» [Tutorial] II.4 - glutKeyboardFunc()
» [Tutorial] II.2 - glutReshapeFunc()
» [Tutorial] II.5 - glutSpecialFunc()
» [Tutorial] II.6 - glutMouseFunc()
» [Tutorial] II.3 - glutTimerFunc()
» [Tutorial] II.2 - glutReshapeFunc()
» [Tutorial] II.5 - glutSpecialFunc()
» [Tutorial] II.6 - glutMouseFunc()
» [Tutorial] II.3 - glutTimerFunc()
Página 1 de 1.
Permisos de este foro:
No puedes responder a temas en este foro.
|
|