6. Proyeccion en perspectiva |
![]() |
![]() |
Videojuegos - Curso de Programación de juegos | ||||||||||||||||||||||||||
Escrito por Vicengetorix | ||||||||||||||||||||||||||
![]() Empezamos por aclarar la proyeccion en perspectiva (si tenemos buena memoria nos acordaremos de las clases de dibujo donde aprendimos a dibujar en perspectiva conica). El concepto es parecido a la proyeccion ortogonal de la entrega anterior pero los puntos de la escena se proyectan sobre el plano de proyeccion (la pantalla) siguiendo una linea que pasa por un punto detras de este plano, el punto de vista (donde estamos situados para ver la escena). Graficamente: ![]() A OpenGL se le puede decir que vamos a usar esta proyeccion de dos formas: Con glFulstrum(...). Veamos el grafico: ![]() Y la funcion con sus parametros correspondientes: - glFrustum(xwmin, xwmax, ywmin, ywmax, pcerca,plejos); Con gluPerpespective(...). El grafico sera: ![]() Y la funcion con sus parametros correspondientes: - gluPerpective(apertura, aspect, pcerca, plejos); El parametro apertura corresponde al angulo marcado en el grafico con un maximo de 180. El parametro aspect sera la relacion entre largo y alto del plano de corte cercano (largo/alto). El parametro pcerca sera la distancia minima al punto de vista a partir de la cual se pintaran los ojetos. El parametro plejos sera la distancia maxima al punto de vista. A partir de esta distancia no se pintaran los objetos. Como el lector cuidadoso habra notado, esta funcion comienza por glu en vez de gl. Efectivamente es la primera funcion que usamos de la libreria glu.h que hemos incluido en nuestro codigo, ya en anteriores versiones del programa. Ahora llegamos a un punto crucial para entender multitud de cosas en el futuro. ¡¡¡Atencion!!!. Coordenadas homogeneas: Veremos en muchas ocasiones (y lo usaremos nosotros) que un punto en tres dimensiones se representa por cuatro coordenadas ... ¿? Tranquilos tiene su explicacion. Un ejemplo: El punto (3,2,5) se representara como (3,2,5,1). Sencillamente le añadimos un 1 como cuarta coordenada. Y ¿para que?. Pues para que cuando OpenGL lo multiplique por una matriz de 4x4 para rotarlo, moverlo, escalarlo y calcular donde de la pantalla hay que pintarlo, no tenga problemas. En realidad OpenGL añade este cuarto 1 internamente si usamos tres coordenadas con una funcion como glVertex3f(...). Dicho esto, (creo que ha sido facil) nos preguntamos  ¿¿¿ matrices ... ???. Pues si. OpenGL y todos los motores graficos usan matrices para modificar las coordenadas de los puntos de los objetos que van a dibujar porque es el metodo mas facil de implementar y mas rapido para un ordenador y permite muchas cosas. Como siempre, un ejemplo: Un objeto formado por muchos puntos en el espacio delimitando sus caras. Uno de estos puntos es (a,b,c,1) -coordenadas homogeneas- y lo queremos mover (a este punto y todos los demas del objeto) pues lo multiplicamos por una matriz determinada con los valores de cuanto lo queremos mover y ya esta. O rotarlo o escalarlo. Y ¿como decirle a OpenGL que lo haga? facil. En OpenGL hay dos matrices principales que determinan como se pintara un punto en pantalla. La primera es la MODELVIEW que transforma los puntos en el espacio tridimensional, los traslada, rota, escala, y vete_a_saber_que_mas se puede hacer con ella. Se le dice a OpenGL que es la que vas a modificar con la funcion glMatrixMode(GL_MODELVIEW); Los mas habituales contenidos de esta matriz son: La matriz identidad que es la que no transforma el punto. si multiplicas un punto por esta matriz da el mismo punto. En OpenGL es la que hay si no dices lo contrario a OpenGL: ![]() Se le dice a OpenGL que es la que queremos con la funcion glLoadIdentity(); La matriz para mover un objeto: ![]() En las posiciones de la X, Y y Z se pone la distancia que queremos mover el objeto en cada eje (positivo o negativo). La funcion para cargar esta matriz es glTranslatef(x,y,z); (vemos que no tenemos mas que decir la distancia en cada eje). La matriz para escalar un ojeto si lo aplicamos a todos sus puntos es: ![]() Escala con un factor por cada eje (o el mismo en todos si se lo ponemos). La funcion para hacerlo es glScalef(x,y,z); Las matrices para rotar un objeto dependen del eje de rotacion. Las mas comunes son alrededor de cada eje de coordenadas: ![]() Un ejemplo de funcion para girar 30 grados en sentido contrario a las agujas del relog y alrededor del eje y es glRotatef(30,0,1,0); Si queremos rotar un objeto y moverlo tendremos que multiplicar las matrices correspondientes y obtendremos una matriz con los datos nacesarios para que si la multiplicamos por los puntos de nuestro objeto, los rote y los mueva. Pero cuidado, las matrices A y B multiplicadas no son igual que las matrices B y A multiplicadas, el orden en que multiplicamos cambia el resultado. Tranquilos OpenGL multiplica matrices solo. Cuando usamos glTranslate, glScale o glRotate, en realidad estamos multiplicando la actual MODELVIEW por la de la correspondiente transformacion. Otro ejemplo, esta vez de lo que tenemos que hacer para pintar un objeto donde y como queremos: - Cargamos la matriz identidad para asegurarnos de donde empezamos: glLoadIdentity(); - Decimos a OpenGL que lo siguiente a pintar va movido de sitio: glTranslatef(0,0,-10); - Lo mismo pero girado alrededor del eje y: glRotatef(30,0,1,0); - Ahora pintamos el objeto: glBegin(...); glVertex3f(...); ... glEnd(); - Podriamos cargar otra vez la matriz identidad para pintar despues otros objetos en otros lugares: glLoadIdentity(); - Y seguimos moviendo, girando, escalando y pintando mas cosas ... La segunda matriz es la PROJECTION, y es la encargada de definir la proyeccion que vamos a usar. OpenGL antes de pintar un punto en la pantalla, lo multiplica primero por la matriz MODELVIEW y luego por la PROJECTION. A OpenGL se le dice que vas a modificar esta matriz con la funcion glMatrixMode(GL_PROJECTION); Esta matriz se modifica cuando vas a definir el tipo de proyeccion que vas a usar con las funciones glOrtho(...), glFulstrum(...) y gluPerspective(...). Por fin toca modificar nuestro programa y lo primero que cambiaremos sera la funcion IniciaGL(), donde borraremos lo primero la funcion glOrtho(...), ya que es la que definia la proyeccion ortogonal, y la cambiaremos por la funcion gluPerspective(...) correspondiente. Antes indicamos al motor grafico que vamos a cambiar la matriz de proyeccion:
Despues cambiaremos la funcion Pinta() para dibujar un cubo donde queramos. Primero cambio a la matriz modelview (para la transformacion en el espacio de nuestros vertices del cubo) y luego cargo la matriz identidad para empezar de 0 (es como inicializar la matriz):
Luego ya puedo poner mi cubo donde y como quiera del espacio tridimensional modificando la matriz modelview con funciones como glTranslate y glRotate:
Por ultimo borro lo que pintabamos en lecciones anteriores y pongo mi nuevo cubo:
Compilamos, ejecutamos y si tenemos suerte veremos esto: ![]() Como siempre sugiero cambiar parametros, funciones, ... para experimentar. El codigo completo seria: usw6.cpp ¡Sólo los usuarios registrados pueden escribir comentarios!
3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved." |