viernes, 21 de septiembre de 2012

Conceptos orthogonal y perspectiva con ejemplos


Proyección en opengl (ortogonal y perspectiva)

Una proyección ortogonal define un volumen de la vista de tipo paralelepipédico tal y como se muestra en la siguiente figura. La principal característica de esta proyección es que el tamaño de los objetos es independiente de la distancia a la que estén del observador, por ejemplo, dos cilindros del mismo tamaño, uno a cinco unidades y el otro a diez unidades de distancia del observador se proyectarán con el mismo tamaño.

Aunque OpenGL dispone de pilas para

Las matrices GL_MODELVIEW y GL_PROJECTION, sólo se suele utilizar la pila de

GL_MODELVIEW.

 

Para definir una proyección ortogonal en OpenGL hay que dar los siguiente pasos:

glMatrix(GL_PROJECTION); /* Voy a manejar la matriz de proyección */
glLoadIdentity(); /* Cargo inicialmente la identidad */
/* Y ahora defino la proyección ortogonal */
void glOrtho(izquierda, derecha, abajo, arriba, cerca, lejos);

Si lo que deseamos es trabajar con una proyección ortogonal 2D:

void gluOrtho2D(izquierda, derecha, abajo, arriba);

que no es más que una proyección ortogonal donde el plan delantero está en -1 y el trasero en 1.
Por ejemplo, la ilustración 1.2 es un render de un coche con proyección ortográfica, visto desde delante.
                                                             Imagen 1.2
 
El código utilizado para esta proyección ha sido
glOrtho(-0.5f, 0.5f, -0.5f, 0.5f, 0.01f, 20.0f

Proyección perspectiva

La proyección ortogonal no da sensación de profundidad porque el tamaño de los objetos no depende de su distancia al observador. Para conseguir este efecto necesitamos definir una proyección perspectiva. Esta proyección define un volumen de la vista que es una prisma truncado de base rectangular, como el de la siguiente figura:

 

 

la función OpenGL que establece este tipo de perspectiva es:

void glFrustum(izquierda, derecha, abajo, arriba, cerca, lejos);

este modo de definir la proyección perspectiva no es demasiado intuitivo, es más sencillo establecerla con un esquema como el que se muestra en la siguiente figura:

y la función OpenGL que la establece es:

La función OpenGL que establece el tamaño del vierport es:

void glViewport(GLint x, GLint y, GLsizei ancho, GLsizei alto);

La ilustración 1.3 muestra la escena del coche de la sección anterior, esta vez con una proyección en perspectiva:

                                                          Ilustracion 1.3
 

El código utilizado para definir la proyección ha sido:

gluPerspective(45.0f,(GLfloat)(width/height),0.01f,100.0f);

Se usan 45º de ángulo, la relación entre el ancho y alto de la pantalla (width y height son el ancho y alto actual de la ventana) y las distancias a los planos de corte znear y zfar son 0.01 y 100 respectivamente.
Un poco mas complejo es este





// 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();
 
 


Transformaciones Geométricas (EJEMPLOS DE TRASLACION, ROTACION Y ESCALADO)


Traslacion

void dibujar_triangulo(){

glBegin(GL_TRIANGLES)

glVertex3f(0,0,0);

glVertex3f(1,0,0);

glVertex3f(0,1,0);

glEnd();

}

// dibuja el triangulo en la posición original

Dibujar_triángulo();

// dibuja el triangulo desplazado

glTranslate(10,0,0);


Dibujar_triángulo();
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

Rotacion y escalacionglMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glRotate(45,0,0,1);

glTranslate(10,0,0)

glScale(2,2,2)

Dibujar_triangulo();

glLoadIdentity();

glRotate(45,0,0,1);

glTranslate(0,10,0)

glScale(2,2,2)
Dibujar_cuadrado();
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

Manejo de matrices en opengl para Para proyeccion y para modelado

Proyeccion

La matriz de proyección especifica el tamaño y la forma del volumen de visualización. El volumen de visualización es aquel cuyo contenido es el que se representa en pantalla. Está delimitado por una serie de planos de trabajo. De estos planos, los más importantes son los planos de corte, que son los que nos acotan el volumen de visualización por delante y por detrás. En el plano más cercano a la cámara (znear) es donde se proyecta la escena para luego pasarla a la pantalla.


Modelado

La matriz del modelador es una matriz 4x4 que representa el sistema de coordenadas transformado que se está usando para colocar y orientar los objetos. Si se multiplica la matriz del vértice (de tamaño 1x4) por ésta se obtiene otra matriz 1x4 con los vértices transformados sobre ese sistema de coordenadas.

RESUMEN

PIla de Matrices
En la función display() se encuentran las llamadas a dos funciones de matrices que todavía no han sido comentadas. Se trata de glPushMatrix() y glPopMatrix(). Para comprender su funcionamiento, primero se va a experimentar que es lo que ocurre cuando no están dichas llamadas. Para ello se comentan en la función display() ambas llamadas:

void display(void) {

// glPushMatrix();

glTranslatef(0.0, 0.0, .5);

...

// glPopMatrix();

glutSwapBuffers();

}

 
La razón de este movimiento es que en la función display está incluida una llamada a glTranslatef() que se utiliza para posicionar uno de los objetos. Como se ha explicado anteriormente, las funciones de traslación multiplican la matriz actual por una matriz de traslación creada con los argumentos que se le pasan, por tanto, sucesivas llamadas a la función display() provocan sucesivas multiplicaciones de la matriz actual con el efecto que se observa de incrementar la traslación. Para solucionar este problema OpenGL dispone de unos stacks o pilas de matrices, que permiten almacenar y recuperar una matriz anterior. aunque opengl dispone de pilas para las matrices gl_modelview y gl_projection, sólo se suele utilizar la pila de gl_modelview. Una pila es un almacén con funcionamiento LIFO, el último en entrar es el primero en salir, por lo que suele comparar a una pila de platos en la que sólo se puede dejar uno encima de la pila o coger el superior que es el último depositado. La pila de matrices tiene el mismo funcionamiento sustituyendo los platos por matrices. La matriz superior de la pila es sobre la que se aplican las distintas transformaciones, multiplicándola por la matriz que generan las disntintas funciones.

La función glpushmatrix() realiza una copia de la matriz superior y la pone encima de la pila, de tal forma que las dos matrices superiores son iguales.. Las siguientes transformaciones que se realizan se aplican sólo a la matriz superior de la pila, quedando la anterior con los valores que tenía en el momento de llamar a la función glpushmatrix(). La función glpopmatrix() elimina la matriz superior, quedando en la parte superior de la pila la matriz que estaba en el momento de llamar a la función glpushmatrix().
 
Necesitaremos realizar tres operaciones: calcular la coordenadas donde se encuentra la tortuga, almacenar dicha coordenada y dibujar el rastro. Para almacenar los puntos se utiliza una variable para indicar el número de puntos y tres vectores para las coordenadas x, y, z.
int np = 0;
float px [10000];
float py [10000];
float pz [10000];
Para calcular las coordenadas de la tortuga es necesario conocer la matriz de transformación de modelado. Debido a que en OpenGL, la matriz de modelado se almacena junto con la de visualización en la matriz GL_MODELVIEW, es necesario guardar de modo independiente esta matriz de modelado. Para ello definimos la variable mModel, como una variable global, ya que va a ser accedida en distinos puntos de la aplicación.
glmatrixmode(gl_modelview);
glpushmatrix();
glLoadIdentity();
glgetdoublev (gl_modelview_matrix, mmodel);
glPopMatrix();
En este código se realizan las siguientes operaciones:
<!--[if !supportLists]-->· <!--[endif]-->œ se indica primeramente sobre que matriz se van a realizar las opereraciones con glMatrixMode();
<!--[if !supportLists]-->· <!--[endif]-->œ se crea una nueva matriz con glPushMatrix();
<!--[if !supportLists]-->· <!--[endif]-->œ se carga la matriz identidad con glLoadIdentity();
<!--[if !supportLists]-->· <!--[endif]-->œ se almacena la matriz superior de la pila en el vector mModel con la función glGetDoublev();
<!--[if !supportLists]-->· <!--[endif]-->œ y finalmente se elimina la matriz superior de la pila con glPopMatrix() para dejar la
que estaba antes de este proceso.

En realidad todo este proceso lo que ha hecho ha sido inicializar la matriz que represena
mModel con la matriz identidad. La función glMultMatrixd() multiplica la matriz superior de la pila por la matriz que tiene como argumento. Al multiplicar en este caso por la matriz identidad, la matriz que queda en la posición superior de la pila es mModel. La llamada a addPointToTrace() se introduce despues de las llamadas a gltranslatef() en las instrucciones correspondientes al forward y back. addPointToTrace();
La llamada a displayTrace() se realiza en la función display(). El dibujo del objeto que representa la tortuga se debe realizar despues de multiplicar la matriz actual (la matriz de visualización) por la matriz de modelado que se almacena en mModel. Dibujar un rastro que consista en unas superficie en lugar de una línea. Para ello se puede utilizar glBegin(GL_QUAD_STRIP) que dibuja una sucesión de rectángulos para cada pareja de puntos que recibe.
 
Mostrar el texto
Las instrucciones introducidas se muestran en la ventana MSDOS. Se pueden mostrar en la ventana gráfica. Para ello es necesario cambiar las matrices de transformación. La siguiente función realiza la representación del texto:
void text(GLuint x, GLuint y, GLfloat scale, char* format, ...) {
va_list args;
char buffer[255], *p;
GLfloat font_scale = 119.05f + 33.33f;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, glutGet(GLUT_WINDOW_WIDTH), 0,
glutGet(GLUT_WINDOW_HEIGHT));
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glTranslatef(x, y, 0.0);
glScalef(scale/font_scale, scale/font_scale, scale/font_scale);
for(p = buffer; *p; p++)
glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
glPopAttrib();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
Para mostrar el texto se llama desde la función display() con la sentencia:
if (command) {
glColor3f(1.0,1.,0.0) ;
text(5, 5, 20, "->%s", strCommand);
PUNTOS A REALIZAR
Utilizando los comandos de logo representar una esfera compuesta por un
conjunto de circunferencias en el espacio.
Utilizando los comandos de logo
realizar la representación de una
helicoidal.


La transformación de puerto de vista:

Esta transformación define el tamaño y la posición de la imagen final (como la impresión de una fotografía), se usa el comando glViewPort() y es necesario modificar el puerto de vista cada que la ventana se modifica.

Una vez que todas estas transformaciones son aplicadas a cada uno de los vértices, la imagen puede ser desplegada dentro de la ventana.

La sintaxis de los comandos de transformación es la siguiente:

glTranslate {fd} (TYPE x, TYPE y TYPE z);

glRotate {fd} (TYPE ángulo,TYPE x, TYPE y, TYPE z);

glScale {fd} (TYPE x, TYPE y, TYPE z);

En donde TYPE es float o int, dependiendo del comando que se escogió.

10.- Normales, Color e Iluminación:

glColor3 {b,s,i,f,d} (TYPE rojo, TYPE verde, TYPE azul)
 
 
Un ejemplo de esto es el siguiente:

glBegin(GL_POLYGON);

        glNormal3fv(n0);        /* n0 es un arreglo que contiene los datos */

        glVertex3fv(v0);

        glNormal3fv(n1);

        glVertex3fv(v1);

        glNormal3fv(n2);

        glVertex3fv(v2);

glEnd();

 
__________________________________________________________________________________
Cubo y Piramide Modificada

#include <GL/glut.h>

GLfloat anguloCuboX = 0.0f;
GLfloat anguloCuboY = 0.0f;
GLfloat anguloEsfera = 0.0f;

GLint ancho=600;
GLint alto=600;

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);
glTranslatef(-3,0,0);
glRotatef(anguloCuboX, 1.0f, 0.0f, 0.0f);
glRotatef(anguloCuboY, 0.0f, 1.0f, 0.0f);
glScalef(0.5f, 0.5f, 0.5f);
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 = 600;
alto = 600;
}


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(display);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}


Corrida






No hay comentarios:

Publicar un comentario