"Ningún juego dura tanto hasta que te lo terminas como el que te programas tú mismo,
ninguno te absorbe tanto y ninguno te produce tanta satisfacción cuando lo has acabado"
Programacion de videojuegos
Inicio Curso de programación de juegos 6. Proyeccion en perspectiva
Lunes 21 de Agosto del 2017

Menu principal
Colaborar (con PayPal)

Para continuar con el trabajo de esta Web y poder pagar el hosting, viene bien la ayuda que sea. Gracias a todos.

Importe: 

Ultimas descargas
19.Jan

Clase que permite dibujar texto en OpenGL con mucha facilidad.Usa FreeType2.Para ver que hace y c...


6. Proyeccion en perspectiva Imprimir Correo electrónico
Videojuegos - Curso de Programación de juegos
Escrito por Vicengetorix   
Por fin entramos en 3D, pero eso supone mas conceptos que hay que entender como por ejemplo el uso de matrices... pero no hay que preocuparse. Las entenderemos para saber que estamos haciendo, y los calculos los hara OpenGL para nosotros.



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:

1
2
3
4
5
// 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);

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):

1
2
3
4
5
6
// Le digo a OpenGL que voy a cambiar la matriz de modelo
glMatrixMode(GL_MODELVIEW);
// Cargo la matriz identidad en la modelview,
// con eso me aseguro de que ningun cambio anterior modifica
// lo que voy ha hacer despues con esta matriz. Empiezo de cero.
glLoadIdentity();

Luego ya puedo poner mi cubo donde  y como quiera del espacio tridimensional modificando la matriz modelview con funciones como glTranslate y glRotate:

1
2
3
4
5
6
7
8
// 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);

Por ultimo borro lo que pintabamos en lecciones anteriores y pongo mi nuevo cubo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 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();

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!
+/- Comentarios
Buscar
Nezumiwriter  - Fin del programa   |83.165.242.xxx |24-05-2012 13:12:05
Buenos días

Como puedes observar continué con el tutorial y llegué hasta
aquí, me encanto ver como el cubo se formo en la pantalla, pero no contento con
ello decidí moverlo. Fue fácil hacerlo, solo tuve que modificar los
parametros:
glTranslatef(0,0,z);
glRotatef(x,1,0,0
);
glRotatef(y,0,1,0);
Mediante una función que cambiaba los valores de x, y,
z.
Eso aún me gusto mas que ver el cubo así que decidí hacer el último
movimiento, ya que la VK_ESCAPE era la interrupción de la tecla ESC y cerraba
el programa, por que no intentar que si pulso UP rote en el eje x, etc... y así
lo hice, pero en cuanto lo ejecuto se me cierra pulsando cualquier tecla,
agradecería que me ayudases otra vez... El código esta
aquí:

http://pastebin.ca/2153348

Gracias de antemano
Un saludo
Vicengetorix   |87.221.169.xxx |24-05-2012 21:50:09
wParam en vez de lParam

Estas siguiendo el camino correcto, modificar al codigo
y experimentar es la mejor forma de aprender. Animo

3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved."

 


Banner
Spanish Chinese (Simplified) English French German Japanese Portuguese Russian