Explicación de obj_pos_rot (Cómo posicionar y rotar un objeto en 3d en OpenGL) - 25/05/2007, 01:27

Hace algunos días publiqué en un mensaje pequeño en el blog, que había logrado ya sacar el procedimiento definitivo para posicionar y rotar un objeto en OpenGL en base a direcciones vectoriales.

Aunque no parezca algo especialmente complicado (de hecho parece bastante bobo el asunto), a mí me costó mucho trabajo, no porque el procedimiento sea especialmente complejo sino por comprender cómo funcionan las cosas (es medio contra-intuitivo :P).

Así que comencemos:

Primero que nada, veremos cómo se dibuja normalmente un objeto en C++/OpenGL, un cubo.

Dibujar un cubo es bastante sencillo -- pensemos que queremos una función cubo() (qué nombre tan original) y no reciba ningún parámetro. El cubo que trazará será entonces de tamaño unitario en todas las dimensiones y tendrá su centro en el origen.

Basta con sacar los 8 vértices alrededor del centro:

Primero los 4 de arriba ( v[1 a 4].y = 0.5 , v1.x = -0.5, v1.z = -0.5, v2.x = -0.5, v2.z = 0.5, v3.x = 0.5, v3.z = 0.5, v4.x = 0.5, v4.z = -0.5 ).
Luego duplicamos los vértices de la parte de arriba, y les cambiamos la "y", a fin de que queden abajo (v[5 a 8] = v[1 a 4] , v[5 a 8].y = -0.5) y finalmente unimos los vértices con GL_QUADs, teniendo cuidado de hacerlo siempre con los vértices en orden anti horario.

El siguiente archivo contiene el procedimiento en c/OpenGL:

lidsol/cubos.c

Bueno. continuaré el mensaje mañana porque me estoy cayendo de sueño (el examen de control fue de casa y no dormí anoche más que media hora, por hacerlo)

edit: Continuando...

Tenemos entonces un procedimiento que dibuja un cubo unitario, con centro en el origen.

Supongamos que queremos desplazar el cubo a la posición (0, 0, -10), es decir, 10 unidades hacia enfrente (que el cubo esté a 10 unidades de nosotros).

¿Por qué no pusimos un parámetro para la posición, por ejemplo?

La razón es que es mucho más eficiente (y fácil) utilizar transformaciones, que implementar, por ejemplo, una rotación a mano. Además, si varios vértices deben sufrir la misma transformación, es más rápido utilizar transformaciones de OpenGL porque los cálculos tardados (generalmente los que involucran cálculos trigonométricos) son realizados una sola vez, y su resultado puede ser reutilizado muchas veces. Por otro lado, es posible acumular fácilmente transformaciones, cosa que podría ser complicada para implementar de manera equivalente a mano.

De esta manera, para desplazar el cubo como queremos, usaremos la función glTranslatef(0,0,-10) y luego usaríamos la subrutina que dibuja el cubo.

Después de una transformación, si no se altera la matriz de modelo de OpenGL (con más transformaciones, reiniciándola con glLoadIdentity() o con un pop), todos los vértices que se dibujen a partir de ese momento sufrirán también dicha transformación.

Pero, ¿qué sucede si en realidad lo que queremos es "alejarnos" del cubo? Supongamos que queremos desplazarnos a la posición (0,0,10). ¿Cómo se verá el cubo? Pues el cubo se verá exactamente igual que cuando decidimos desplazarlo a la posición (0,0,-10): se alejará 10 unidades hacia enfrente. Esto ocurre porque todo movimiento es relativo; es lo mismo alejar al cubo que alejarse del cubo. Por lo tanto, la rutina para posicionar la cámara, debe consistir de dos partes: una traslación, con las coordenadas a donde se quiere desplazar la cámara, con las medidas con el signo cambiado, y una rotación que permita a la cámara mirar hacia cualquier dirección que se quiera.

Por ejemplo, si se quiere que la cámara mire hacia la dirección izquierda con un ángulo de 45 ° (por ejemplo, la cámara está en el origen y se desea mirar la dirección (-1,0,-1), se efectuará primero la rotación y luego la traslación. ¿Qué efecto aparente tendrá esto? El efecto será que los vértices a dibujar, aparecerán "corridos" ligeramente hacia la derecha.

De esta manera podemos observar que también se se está efectuando la rotación al revés cuando se trata de posicionar y rotar la cámara.

La función gluLookAt hace justamente eso: rotar y posicionar la cámara, pero con direcciones vectoriales, y muy eficientemente, ya que opera directamente sobre la matriz de OpenGL (crea su matriz propia a la combinación de ambas transformaciones y luego la multiplica con la existente en OpenGL) sin utilizar funciones trigonométricas. El procedimiento matemático de gluLookAt se encuentra detallado en la siguiente página: http://pyopengl.sourceforge.net/documentation/manual/gluLookAt.3G.html.

Al ver un procedimiento tan eficiente y conveniente (ya que la mayor parte de los cálculos se efectúan de manera vectorial, por ser infnitamente más fáciles de comprender en esta forma, además de, en la mayoría de los casos, más eficientes), y tener en cuenta que posicionar y rotar la cámara es lo inverso de posicionar y rotar un objeto, era de esperarse que un procedimiento modificado que fuera muy parecido gluLookAt sirviera para posicionar y orientar objetos.

Ahora, si quisiéramos rotar el cubo además de haberlo trasladado, digamos, horizontalmente, 45 grados en la dirección contraria a las manecillas del reloj, aplicaríamos primero la traslación y después usaríamos la función glRotatef(45,0,1,0), finalmente usaríamos la subrutina que dibuja el cubo.

Con estas observaciones en mente, después de mucho hacerme bolas y probar muchos otros caminos, erróneos e ineficientes, logré entender cómo formular la subrutina.:

- Se realiza la traslación (sin invertir coordenadas).
- Se crea una matriz, la cual es actualizada con los procedimientos. Los cálculos se generan invirtiendo el orden de los vectores durante el producto cruz para no tener que invertir elemento por elemento.
- Se realiza el glMultMatrix.

La implementación de la función está en el siguiente enlace. Sin embargo, si se desea hacer uso de esas funciones, hay que obtener adicionales.cpp/h del Repositorio de Lidsol.

lidsol/pos_rot_obj.c





< Back to blog

This site doesn't use cookies, does not log IPs and does not track you in any way.