domingo, 4 de marzo de 2012

Proyección ortogonal y proyección en perspectiva

Proyección ortogonal
Una proyección ortogonal es cuadrada en todas sus caras. Esto produce una proyección paralela, útil para aplicaciones de tipo CAD o dibujos arquitectónicos, o también para tomar medidas, ya que las dimensiones de lo que representan no se ven alteradas por la proyección.

Una aproximación menos técnica pero mas comprensible de esta proyección es imaginar que se tiene un objeto fabricado con un material deformable, y se aplasta literalmente como una pared. Se obtendría el mismo objeto, pero plano, liso. Pues eso es lo que se vería por pantalla.

Para definir la matriz de proyección ortográfica y multiplicarla por la matriz activa (que debería ser en ese momento la de proyección, GL_PROJECTION), se utiliza la función glOrtho, que se define de la siguiente forma:

glOrtho(limiteIzquierdo, limiteDerecho, limiteAbajo, limiteArriba, znear, zfar)

siendo todos flotantes. Los valores de znear y zfar no son las posiciones de esos planos en el espacio 3D. Representan la distancia desde el centro de proyección, con valor positivo hacia delante y negativo hacia atrás. Con esto simplemente se acota lo que será el volumen de visualización (un cubo).

Por ejemplo, la ilustración 4.5 es un render de un coche con proyección ortográfica, visto desde delante.





  Proyecciones perspectivas
Una proyección en perspectiva reduce y estirar los objetos más alejados del observador. Es importante saber que las medidas de la proyección de un objeto no tienen por qué coincidir con las del objeto real, ya que han sido deformadas.
El volumen de visualización creado por una perspectiva se llama frustum. Un frustum es una sección piramidal, vista desde la parte afilada hasta la base (ilustración 4.6).

Se puede definir esta proyección utilizando la función glFrustum. Pero existe otra función de la librería GLU llamada gluPerspective que hace el proceso más sencillo. Se define de la siguiente forma:
Void gluPerspective(angulo, aspecto, znear, zfar);
Los parámetros de gluPerspective son flotantes y definen las características mostradas en la ilustración 4.7, el ángulo para el campo de visión en sentido vertical, el aspecto que es la relación entre la altura (h) y la anchura (w) y las distancias znear y zfar de los planos que acotan el fustrum al observador. Los valores de znear y zfar no son las posiciones de esos planos en el espacio 3D, representan la distancia desde el centro de proyección, con valor positivo hacia delante y negativo hacia atrás.

Ilustración 4 .7
La ilustración 4.8 muestra la escena del coche de la sección anterior, esta vez con una proyección en perspectiva:


CODIGO #1


#include <GL/glut.h>



GLfloat anguloCuboX = 0.0f;

GLfloat anguloCuboY = 0.0f;

GLfloat anguloEsfera = 0.0f;



GLint ancho=400;

GLint alto=400;



int hazPerspectiva = 0;



void reshape(int width, int height)

{

    glViewport(0, 0, width, height);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

   

    if(hazPerspectiva)

                gluPerspective(60.0f, (GLfloat)width/(GLfloat)height, 1.0f, 20.0f);

    else



                glOrtho(-4,4, -4, 4, 1, 10);



    glMatrixMode(GL_MODELVIEW);



    ancho = width;

    alto = height;

}



void drawCube(void)

{

    glColor3f(1.0f, 0.0f, 0.0f);

    glBegin(GL_QUADS);       //cara frontal

    glVertex3f(-1.0f, -1.0f,  1.0f);

    glVertex3f( 1.0f, -1.0f,  1.0f);

    glVertex3f( 1.0f,  1.0f,  1.0f);

    glVertex3f(-1.0f,  1.0f,  1.0f);



    glEnd();



    glColor3f(0.0f, 1.0f, 0.0f);



    glBegin(GL_QUADS);       //cara trasera

    glVertex3f( 1.0f, -1.0f, -1.0f);

    glVertex3f(-1.0f, -1.0f, -1.0f);

    glVertex3f(-1.0f,  1.0f, -1.0f);

    glVertex3f( 1.0f,  1.0f, -1.0f);



    glEnd();



    glColor3f(0.0f, 0.0f, 1.0f);

    glBegin(GL_QUADS);       //cara lateral izq

    glVertex3f(-1.0f,-1.0f, -1.0f);

    glVertex3f(-1.0f,-1.0f,  1.0f);

    glVertex3f(-1.0f, 1.0f,  1.0f);

    glVertex3f(-1.0f, 1.0f, -1.0f);

    glEnd();



    glColor3f(1.0f, 1.0f, 0.0f);

    glBegin(GL_QUADS);       //cara lateral dcha

    glVertex3f(1.0f, -1.0f,  1.0f);

    glVertex3f(1.0f, -1.0f, -1.0f);

    glVertex3f(1.0f,  1.0f, -1.0f);

    glVertex3f(1.0f,  1.0f,  1.0f);

    glEnd();

    glColor3f(0.0f,      1.0f, 1.0f);

    glBegin(GL_QUADS);       //cara arriba

    glVertex3f(-1.0f, 1.0f,  1.0f);

    glVertex3f( 1.0f, 1.0f,  1.0f);

    glVertex3f( 1.0f, 1.0f, -1.0f);

    glVertex3f(-1.0f, 1.0f, -1.0f);

    glEnd();



    glColor3f(1.0f, 0.0f, 1.0f);

    glBegin(GL_QUADS);       //cara abajo

    glVertex3f( 1.0f,-1.0f, -1.0f);

    glVertex3f( 1.0f,-1.0f,  1.0f);

    glVertex3f(-1.0f,-1.0f,  1.0f);

    glVertex3f(-1.0f,-1.0f, -1.0f);

    glEnd();

}



void display()

{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



    glLoadIdentity();



    glTranslatef(0.0f, 0.0f, -5.0f);



    glRotatef(anguloCuboX, 1.0f, 0.0f, 0.0f);

    glRotatef(anguloCuboY, 0.0f, 1.0f, 0.0f);



    drawCube();



    glLoadIdentity();



    glTranslatef(0.0f, 0.0f, -5.0f);

    glRotatef(anguloEsfera, 0.0f, 1.0f, 0.0f);

    glTranslatef(3.0f, 0.0f, 0.0f);



    glColor3f(1.0f, 1.0f, 1.0f);

    glutWireSphere(0.5f, 8, 8);



    glFlush();

    glutSwapBuffers();



    anguloCuboX+=0.1f;

    anguloCuboY+=0.1f;

    anguloEsfera+=0.2f;

}



void init()

{

    glClearColor(0,0,0,0);

    glEnable(GL_DEPTH_TEST);

    ancho = 400;

    alto = 400;

}





void idle()

{

    display();

}



void keyboard(unsigned char key, int x, int y)

{

    switch(key)

    {

    case 'p':

    case 'P':

                hazPerspectiva=1;

                reshape(ancho,alto);

                break;



    case 'o':

    case 'O':

                hazPerspectiva=0;

                reshape(ancho,alto);

                break;



    case 27:   // escape

                //exit(0);

      break;

    }

}



int main(int argc, char **argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

    glutInitWindowPosition(100, 100);

    glutInitWindowSize(ancho, alto);

    glutCreateWindow("Cubo 1");

    init();

    glutDisplayFunc(display);

    glutReshapeFunc(reshape);

    glutIdleFunc(idle);

    glutKeyboardFunc(keyboard);

    glutMainLoop();

    return 0;

}}



CODIGO #2

// Le digo a OpenGL que voy a cambiar la matriz de proyeccion
glMatrixMode(GL_PROJECTION);
// Le digo a OpenGL que use proyeccion perspectiva. Uso el ancho
// y alto de mi viewport para calcular el segundo parametro
gluPerspective(60.0f, (float)rect.right/(float)rect.bottom, 0.5f, 50.0f);

// Muevo para atras el objeto. El punto de vista esta
// en la posicion 0,0,0 porque no lo he cambiado, asi que
// alejo el objeto para poder verlo.
glTranslatef(0,0,-4.0f);
// Giro el objeto 30 grados en el eje x, luego otros
// 30 en el eje y. Es para que quede bonito.
glRotatef(30,1,0,0);
glRotatef(30,0,1,0);


// y pinto el objeto con coordenadas genericas alrededor
// del eje de coordenadas. Estas coordenadas que pongo
// ahora son modificadas por las modificaciones que
// hemos hecho en la matriz modelview (glTranslate, glRotate).

// Le digo a OpenGL que voy a pintar y con cuadrados:
glBegin(GL_QUADS);
// Cara de arriba
glColor3f(1,0,0); // rojo
glVertex3f( 1.0f, 1.0f,-1.0f);   
glVertex3f(-1.0f, 1.0f,-1.0f);   
glVertex3f(-1.0f, 1.0f, 1.0f);   
glVertex3f( 1.0f, 1.0f, 1.0f);   
// Cara de abajo
glColor3f(1,0,0); // rojo
glVertex3f( 1.0f,-1.0f, 1.0f);   
glVertex3f(-1.0f,-1.0f, 1.0f);   
glVertex3f(-1.0f,-1.0f,-1.0f);   
glVertex3f( 1.0f,-1.0f,-1.0f);   
// Cara frontal
glColor3f(0,0,1); // azul
glVertex3f( 1.0f, 1.0f, 1.0f);   
glVertex3f(-1.0f, 1.0f, 1.0f);   
glVertex3f(-1.0f,-1.0f, 1.0f);   
glVertex3f( 1.0f,-1.0f, 1.0f);
// Cara trasera
glColor3f(0,0,1); // azul
glVertex3f( 1.0f,-1.0f,-1.0f);   
glVertex3f(-1.0f,-1.0f,-1.0f);   
glVertex3f(-1.0f, 1.0f,-1.0f);   
glVertex3f( 1.0f, 1.0f,-1.0f);
// Cara izquierda
glColor3f(0,1,0); // verde
glVertex3f(-1.0f, 1.0f, 1.0f);    
glVertex3f(-1.0f, 1.0f,-1.0f);   
glVertex3f(-1.0f,-1.0f,-1.0f);   
glVertex3f(-1.0f,-1.0f, 1.0f);
// Cara derecha
glColor3f(0,1,0); // verde
glVertex3f( 1.0f, 1.0f,-1.0f);   
glVertex3f( 1.0f, 1.0f, 1.0f);   
glVertex3f( 1.0f,-1.0f, 1.0f);   
glVertex3f( 1.0f,-1.0f,-1.0f);
glEnd();