Saturday, October 20, 2007

Mi carro en OpenGL


Mi carro en OpenGL
Dibujado de un carro en OpenGL y su proyección Ortogonal
Jose Angel Espinoza Portillo
Tarea 4 • Graficacion • 24 Octubre 2007


El FrameWork
Se utilizo un conjunto de códigos pre-configurados y listos para cargar una entidad de OpenGL en un widget de Qt, estos códigos fueron entregados por el Dr. Luis Gerardo de la Fraga y pude ser encontrado en el siguiente sitio: http://delta.cs.cinvestav.mx/~fraga/Cursos/Graficacion/2007/.
Algunas de las funciones ya implementadas son la rotación al dar click en el QGLWidget y arrastrar hacia alguna dirección.

Archivos
Utilizando el framework original de trabajo llamado “quad”. El cual contiene los archivos de código siguientes:
  • painter.cpp y painter.h: Implementación del QWidget es la ventana principal del sistema, aquí se implementan los botones, geometría, eventos y elementos que se observan en la ventana de la aplicación.
  • quad.cpp y quad.h: Implementa del QGLWidget que representa a el área en la cual se va a dibujar. Incluye funciones de trazado de inicialización de estados y de modos de renderización de el área de trazado.
  • main.cpp: Es el código que iniciativa la aplicación y le da la ejecución a el Qt para que interprete las instrucciones especificadas en canvas.cpp.


Diseño de el Carro
Especificación de las características de el carro y sus vértices.



Antes de empezar a programar hay que desarrollar una estructura de hilos para identificar la forma de el vehículo vista desde varios ángulos, y para especificar la dimensión de sus puntos (vértices).

De las estructuras anteriores se tomara la distancia de sus puntos desde un origen imaginario para definir un arreglo de vectores v1.



Definiendo el arreglo “v1”
Este arreglo se define en el archivo quad.h, para que pueda usarse en la clase, es inicializada en el constructor junto a su especificación con los puntos que en ella se representan de la siguiente manera.

Quad::Quad( QWidget *parent, const char *name )
...;
v1[0][0] = 0.0; v1[0][1] = 0.0; v1[0][2] = 4.0;
v1[1][0] = 5.0; v1[1][1] = 0.0; v1[1][2] = 4.0;
v1[2][0] = 5.0; v1[2][1] = 8.0; v1[2][2] = 4.0;
v1[3][0] = 0.0; v1[3][1] = 8.0; v1[3][2] = 4.0;

v1[4][0] = 1.0; v1[4][1] = 2.0; v1[4][2] = 4.0;
v1[5][0] = 4.0; v1[5][1] = 2.0; v1[5][2] = 4.0;
v1[6][0] = 4.0; v1[6][1] = 7.0; v1[6][2] = 4.0;
v1[7][0] = 1.0; v1[7][1] = 7.0; v1[7][2] = 4.0;

v1[8][0] = 1.25; v1[8][1] = 2.75; v1[8][2] = 5.25;
v1[9][0] = 3.75; v1[9][1] = 2.75; v1[9][2] = 5.25;
v1[10][0] = 3.75; v1[10][1] = 6.1; v1[10][2] = 5.25;
v1[11][0] = 1.25; v1[11][1] = 6.1; v1[11][2] = 5.25;

v1[12][0] = 0.0; v1[12][1] = 0.0; v1[12][2] = 1.0;
v1[13][0] = 5.0; v1[13][1] = 0.0; v1[13][2] = 1.0;
v1[14][0] = 5.0; v1[14][1] = 8.0; v1[14][2] = 1.0;
v1[15][0] = 0.0; v1[15][1] = 8.0; v1[15][2] = 1.0;
...;
}


Definiendo los valores en v1[n][o], v1[n][1] y v1[n][2] en los planos ‘x’, ‘y’ y ‘z’ respectivamente.

Dibujando el Carro
El arreglo anterior no es suficiente para que una figura sea dibujada en el espacio tridimensional, hay que indicarle a el OpenGL como debe unir los puntos anteriores y esto se hace como a continuación:

void Quad::paintGL(void){
...;
glBegin(GL_QUADS);
glColor3f( 1.0, 0.0, 0.0 );
glVertex3fv( &v1[0][0] );
glVertex3fv( &v1[1][0] );
glVertex3fv( &v1[2][0] );
glVertex3fv( &v1[3][0] );

glVertex3fv( &v1[8][0] );
glVertex3fv( &v1[9][0] );
glVertex3fv( &v1[10][0] );
glVertex3fv( &v1[11][0] );

glColor3f( 0.0, 1.0, 0.0 );
glVertex3fv( &v1[12][0] );
glVertex3fv( &v1[13][0] );
glVertex3fv( &v1[14][0] );
glVertex3fv( &v1[15][0] );

glColor3f( 1.0, 1.0, 1.0 );
glVertex3fv( &v1[0][0] );
glVertex3fv( &v1[3][0] );
glVertex3fv( &v1[15][0] );
glVertex3fv( &v1[12][0] );

glVertex3fv( &v1[8][0] );
glVertex3fv( &v1[4][0] );
glVertex3fv( &v1[7][0] );
glVertex3fv( &v1[11][0] );

glColor3f( 0.0, 0.0, 1.0 );
glVertex3fv( &v1[0][0] );
glVertex3fv( &v1[1][0] );
glVertex3fv( &v1[13][0] );
glVertex3fv( &v1[12][0] );

glVertex3fv( &v1[4][0] );
glVertex3fv( &v1[5][0] );
glVertex3fv( &v1[9][0] );
glVertex3fv( &v1[8][0] );

glColor3f( 1.0, 1.0, 0.0 );
glVertex3fv( &v1[1][0] );
glVertex3fv( &v1[2][0] );
glVertex3fv( &v1[14][0] );
glVertex3fv( &v1[13][0] );

glVertex3fv( &v1[5][0] );
glVertex3fv( &v1[6][0] );
glVertex3fv( &v1[10][0] );
glVertex3fv( &v1[9][0] );

glColor3f( 1.0, 0.0, 1.0 );
glVertex3fv( &v1[2][0] );
glVertex3fv( &v1[3][0] );
glVertex3fv( &v1[15][0] );
glVertex3fv( &v1[14][0] );

glVertex3fv( &v1[10][0] );
glVertex3fv( &v1[11][0] );
glVertex3fv( &v1[7][0] );
glVertex3fv( &v1[6][0] );
glEnd();
...;
}


Problemas


Al implementar el código anterior se detecto un problema con el eje de rotación y la orientación de los puntos, el dibujo se dibujaba como en esta figura:
Para solucionar estos problemas se le resto a todos los puntos la mitad del punto con mayor unidad de cada vértice y se intercambiaron los puntos de ‘z’ y ‘y’ con el siguiente código:

for (n=0;n<16;n++){ n="0;n<16;n++){" u =" v1[n][1];">

Calculando la proyección

Utilizando una matriz de transformación.

Principios matemáticos
Como fue visto en clase para hacer una proyección ortogonal es necesario un valor l para indicar la “Profundidad” visible del objeto y un ángulo a para designar la inclinación de la proyección y asignarlo a una matriz para especificar que transformación, la cual esta expresada en la Tabla (matriz) 01.
Tabla (matriz) 01

La cual multiplicada por la matriz de el objeto se dará el efecto deseado.

Implementación
Para la implementación de matrices en OpenGL se debe utilizar matrices tipo cuaternion que se implementa como un vector de 16 elementos de algún tipo en este caso GLfloat (que es una implementación de OpenGL que garantiza la potabilidad del tipo float en diferentes arquitecturas ) y se declara:

GLfloat matriz2[16];

Como básicamente es una matriz con ceros, se asignaron estos (los ceros) a todos los elementos y luego basandonos las posiciones de los indices señalados en la Tabla 02.
Tabla 02

Se escribió la matriz de la siguiente manera:

matriz2[0]=1;
matriz2[2]=-l*cos((angle*PI)/180);
matriz2[5]=1;
matriz2[6]=-l*sin((angle*PI)/180);
matriz2[15]=1;

Y luego antes de escribir el código de la representación de la figura escribir:

glMultMatrixf(matriz2);

Problema
Pero al implementar este código tal cual con las bases antes mencionadas encontrábamos otro problema, que era básicamente que no parecía dibujar nada en la pantalla, después de algunas comprobaciones matemáticas y con otros objetos nos percatamos de un patrón del error, el cual era básicamente la inversión de los indices de la matriz y fue en ese momento donde se descubrió que OpenGL no interpretaba los indices del cuaternion de la manera que inducimos sino como en la Tabla 03, y al final queda como a continuación:



matriz2[0]=1;
matriz2[8]=-l*cos((angle*PI)/180);
matriz2[5]=1;
matriz2[9]=-l*sin((angle*PI)/180);
matriz2[10] = 0.00001; /* Arregla un depth bug */
matriz2[15]=1;

Donde se usan l y angle que explicare a continuación.

Tabla 03



El painter
Dibujado de los componentes a utilizar
Se implementan por primera vez los objetos QSlider, para dar mas inter actividad a el sistema y conectandolo a unos SLOTS’s en el quad que modifican el valor de a (angulo) o l que se usan en el proceso de dibujado de el objeto en la ventana OpenGL.

Forma final de el Ejecutable

El cual tiene un switch entre la manipulación (Rotación) de el objeto que el Dr. de la Fraga tenia implementado originalmente con el nuevo objeto y la vista de la proyección del cuerpo. Los slides que modifican los valores de l y a (angulo).

Conclución
  • Es relativamente sencillo crear objetos 3D en OpenGL, pero lo que es complicado es la estructura que devén de tener los datos para su apropiado manejo.
  • Nunca seré un diseñador de autos.

Labels: ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home