Proyección en perspectiva
La característica principal de la proyección en perspectiva es que cuanto más alejado está un objeto de la cámara, más pequeño aparece en la imagen final. Esto ocurre porque el volumen de visión para una proyección en perspectiva es un tronco de pirámide (una pirámide truncada a la cual se ha cortado el pico por un plano paralelo a la base). Los objetos que están dentro del volumen de visión son proyectados hacia la cúspide de la pirámide, donde estaría situada la cámara o punto de vista. Los objetos más cercanos al punto de vista aparecen más grandes porque ocupan proporcionalmente una cantidad mayor del volumen de visión que aquellos que están más alejados.
Para definir un volumen de visión de este tipo y por lo tanto crear una matriz de
transformación de proyección en perspectiva se utiliza la rutina gluPerspective() de la “Utility Library” y que se especifica a continuación:
void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ).
Proyección Ortogonal
Con una proyección ortogonal, el volumen de visión es un paralelepípedo, o más informalmente, una caja. A diferencia de la proyección en perspectiva, el tamaño del volumen de visión no cambia desde una cara a la otra, por lo que la distancia desde la cámara no afecta a lo grande que aparezca un objeto.
Para definir un volumen de visión de este tipo y por lo tanto crear una matriz de
transformación de proyección ortogonal se utiliza la rutina glOrtho(), perteneciente a la librería básica de OpenGL, y que se especifica a continuación:
void glOrtho( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,
GLdouble near, GLdouble far ).
OpenGL proporciona funciones para controlar la traslación, rotación y escalado. Estas tranformaciones se representan como matrices 4x4 ordenadas como vectores columna, tal y como se muestra en la siguiente figura:
Recuerda que en C, el primer elemento de un array tiene subíndice 0. La familia de funciones que implementan las transformaciones es: void glTranslate{fd}(TIPO x, TIPO y, TIPO z); void glTranslatef(float x, float y, float z); void glTranslated(double x, dluble y, double z); void glRotate{fd}(TIPO angulo_en_grados, TIPO x, TIPO y, TIPO z); void glScale{fd}(TIPO sx, TIPO sy, TIPO sz); |
Observa que la traslación modifica el último vector columna, miestras que el escalado y las rotaciones comparten los elementos de la submatriz 3x3 superior izquierda.
|
Has de tener en cuenta que las tranformaciones no son conmutativas entre sí, es decir, el resultado no es el mismo si sobre un objeto efectúas una rotación y luego una traslación, que si efectúas primero una traslación y luego una rotación. Es más, en general las rotaciones tampoco son conmutativas entre si. El orden de aplicación de las transformaciones es muy importante.
|
Otro detalle que has de tener muy en cuenta es el orden de aplicación de las transformaciones en OpenGL. Observa el siguiente fragmento de código:
glTranslatef(1.0f, 1.0f, 1.0f); glRotatef(45.0f, 1.0f, 0.0f, 0.0f); glScalef(2.0f, 2.0f, 2.0f); objeto(); |
Rotación.
Para rotar, tenemos también una función de alto nivel que construye la matriz de transformación y la multiplica por la matriz activa, glRotate. Lleva como parámetros el ángulo a rotar (en grados, sentido horario), y después x, y y z del vector sobre el cual se quiere rotar el objeto.
glRotatef(10, 0.0f, 1.0f, 0.0f);
TRASLADAR
Para trasladar un objeto de nuestra escena lo haremos mediante la función glTranslatef(x,y,z).
Por ejemplo si queremos desplazar un objeto en el eje de la x 100 unidades, escribiremos:
glTranslatedf(100,0,0)
y ahora dibujaríamos el o los objetos que queremos que se aplique este traslado.
Escalado.
Una transformación de escala incrementa el tamaño de nuestro objeto expandiendo todos los vértices a lo largo de los tres ejes por los factores especificados. La función glScale lleva como parámetros la escala en x, y y z, respectivamente.
glScalef(1.0f, 1.0f, 1.0f);
glScalef(1.0f, 1.0f, 4.0f);
PILA DE MATRICES
A veces nos interesa guardar el estado de las transformaciones por lo que utilizar la matriz de identidad no nos sirve, para este caso opengl tiene las pilas de matrices, funcionan igual que una pila, para ello tenemos las funciones glPushMatrix que pone en la pila y glPopMatrix que la quita de la pila, por lo tanto si nosotros aplicamos una transformación a toda la escena y luego a un objeto queremos aplicarle otra lo podemos poner en la pila luego quitarlo de la pila y asi mantenemos la transformación inicial.
En el ejemplo que os podéis descargar si pulsáis el botón ‘sin pila’ deja de usar las funciones glPushMatrix y glPopMatrix. Entonces veréis como el cubo de la izquierda se le acumulan las 4 transformaciones y se mueve de diferente forma que utilizando la pila. Si volvéis a pulsar el botón para que use la pila lo que hace es aplicar 3 transformaciones la que esta fuera de la pila y las 2 que tiene en concreto dentro de la pila del segundo cubo
Para poder almacenar transformaciones parciales OpenGL nos proporciona una pila sobre la que poder apilar y desapilar la matriz de transformación modelo-vista actual. Sobre esta pila se pueden hacer dos operaciones básicas:
glPushMatrix(); Hace una copia de la matriz actual sobre la cima de la pila. glPopMatrix(); Extrae la cima de la pila y la copia sobre la matriz actual. Mediante el uso de estas funciones podemos «aislar» las trasformaciones que se aplican a objetos distintos. Observa el siguiente fragamento de código: glLoadIdentity(); /* Carga la identidad sobre la matriz actual */ glPushMatrix(); /* Copia la identidad a la cima de la pila */ glTranslate3f(x, y, z); /* Efectua una tralación */ objeto(); /* Dibujamos un objeto cualquiera */ glPopMatrix(); /* Extraemos la cima de la pila y la copiamos sobre la matriz actual, de nuevo tenemos la identidad en la matriz actual */ glPushMatrix(); /* Volvemos a apilar la identidad */ glRotate3f(alfa, beta gamma); /* Efectuamos una rotación */ objeto(); glPopMatrix(); /* Volvemos a recuperar la identidad */ Como ves, podemos «aislar» las trasformaciones que actúan sobre los objetos si las colocamos entre un par glPushMatrix() / glPopMatrix(). |
No hay comentarios:
Publicar un comentario