sábado, 6 de octubre de 2012

La 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 distintas 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. En la figura 1 se observa la pila en la situación inicial con una sola matriz, al llamar a la función glPushMatrix() se duplica la matriz superior. 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().

Dibujando un rastro

Una característica de Logo es que la tortuga al avanzar va dibujando el camino por el que ha pasado. Hasta ahora la aplicación va transformando las coordenadas del objeto para situarlo en la nueva posición según las instrucciones introducidas pero no muestra la ruta seguida.
Para mostrar la ruta es necesario almacenar los puntos por los que pasa la tortuga. El rastro consistirá en una línea que una estos puntos.
Necesitaremos realizar tres operaciones: calcular la coordendas 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: GLdouble mModel[16]
Para operar con la matriz mModel, se cargará en la pila de matrices de GL_MODELVIEW despues de realizar un PushMatrix(), de modo que no altere la matriz actual. En la función main() se inicializa esta matriz con el código:
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glGetDoublev (GL_MODELVIEW_MATRIX, mModel);
glPopMatrix();

MOSTRAR 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);
}

No hay comentarios:

Publicar un comentario