/
Inicio :: Foros

 F.A.Q.F.A.Q.                  Conéctese para revisar sus mensajesConéctese para revisar sus mensajes   

Matriz de transformación. OpenGL

 
      Índice del Foro elrincondelc.com -> Gráficos
Ver tema anterior :: Ver siguiente tema  
AutorMensaje
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 1344

MensajePublicado: 28/06/2011 7:15 am
Título: Matriz de transformación. OpenGL

Buenas.

Estoy dándole un poco a manuales de OpenGL. Y me ha surgido el primer problema que no sabría como solucionar con las funciones de esta biblioteca.

OpenGL trabaja con una matriz 4x4 la cual aplicada(multiplicada) a los puntos cargados en el modelo hace que veamos cierta proyección del modelo. Esta matriz 4x4 está oculta al programador. Sólo se puede modificar a través de ciertas funciones que modifican la matriz:

glLoadIdenty() -> carga la matriz identidad
glLoadMatrix( GLdouble* mat ) -> carga la matriz mat
glRotatef( ... ), glTranslatef( ... ), glScalef( ... ) -> rota/ traslada/ escala el modelo segun los parametros recibidos por las funciones.

El problema que le veo a estas últimas 3 funciones es que sólo se pueden aplicar después. Es decir, si la matriz al inicio indica que se hace una traslacion y luego se le aplica una rotación. Entonces la matriz será el resultado de hacer una traslación y luego una rotación,

En cambio si la matriz al inicio es una tralación y quiero que se convierta en una matriz que haga una rotacion primero y despues la traslacion no veo manera de hacerlo. Ni usando glPushMatrix() y glPopMatrix() se me ocurre la manera.

Solución que veo: implementar dicha solución vía software creando una matriz 4x4 propia de manera que pueda acceder a ella y manipularla e ir cargandola mediante la función glLoadMatrix. Aunque dicha manera desaprovecha los recursos que pueda tener el hardware gráfico en relación a la multiplicación de matrices.

¿Hay alguna otra solución?

Un saludo!
Volver arriba
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 1344

MensajePublicado: 29/06/2011 2:29 am
Título:

Seguramente una imagen vale más que mil palabras. Así que os dejo el código de un programa que funciona perfectamente pero que usa funciones propias para realizar las rotaciones deseadas.

Os explico:
1) Si se pulsa F1, F2, y F3 la figura rota sobre el eje rojo, verde y azul, respectivamente.
2) Si se pulsa F5, F6 y F7, la figura rota sobre los ejes de la pantalla horizontal, vertical y en profundidad, respectivamente.

La parte 1) la puedo implementar facilmente con funciones como glRotatef(). Sin embargo la parte 2) no encuentro manera de implementarla usando dichas funciones.

Me gustaría implementar la parte 2) mediante funciones de OpenGL para aprovechar, así, las ventajas del hardware gráfico en caso de que el ordenador los tenga.

Os dejo el código del programa para compilar y ejecutar y que ilustre la explicación dada:

Código:
#include<GL/glut.h>

#include<cmath>
   using std::sqrt;
   using std::cos;
   using std::sin;


GLfloat* mul_matrix( GLfloat* a, GLfloat* b, int n );
void display(void);
void init(void);
void SpecialKey( int key, int x, int y );

class Model_View
{
   private:
      static GLfloat mat[16];

      static GLfloat aux_mat[16];
      static void generate_matrix_rotate( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
   public:
      static void loadIdentity();
      static void rotate_before( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
      static void rotate_after( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
};


int main(int argc, char **argv)
{
   glutInit( &argc, argv );

   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
   glutInitWindowPosition(20,20);
   glutInitWindowSize(500,500);
   glutCreateWindow(argv[0]);

   init();

   glutDisplayFunc(display);
   glutSpecialFunc(SpecialKey);


   glutMainLoop();

   return 0;
}

void init(void)
{
   glClearColor(0.0,0.0,0.0,0.0);
   // Color de fondo: negro
   glClear(GL_COLOR_BUFFER_BIT);
   // Borramos la pantalla
   glMatrixMode(GL_PROJECTION);
   // Modo proyección
   glLoadIdentity();
   // Cargamos la matriz identidad
   glOrtho(-4.0,4.0,-4.0,4.0,-4.0,4.0);

   Model_View::loadIdentity();
}


// atributos y metodos de Model_View

GLfloat Model_View::mat[16];
GLfloat Model_View::aux_mat[16];

void Model_View::loadIdentity()
{
   int i;
   for( i = 0; i < 16; ++i )
   {
      if( i % 5 == 0 ) mat[i] = 1.0;
      else             mat[i] = 0.0;
   }
   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity();
}

void Model_View::rotate_before( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
   generate_matrix_rotate( angle, x, y, z );

   GLfloat* r = mul_matrix( aux_mat, mat, 4 );

   glMatrixMode( GL_MODELVIEW );
   for( int i = 0; i < 16; ++i )
      mat[i] = r[i];
   glLoadMatrixf( mat );

   delete [] r;
}

void Model_View::rotate_after( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
   generate_matrix_rotate( angle, x, y, z );

   GLfloat* r = mul_matrix( mat, aux_mat, 4 );

   glMatrixMode( GL_MODELVIEW );
   for( int i = 0; i < 16; ++i )
      mat[i] = r[i];
   glLoadMatrixf( mat );

   delete [] r;
}

void Model_View::generate_matrix_rotate( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
   int i;

   const GLfloat RR = x*x + y*y + z*z; // 3*, 2+
   const GLfloat R = sqrt( RR );

   GLfloat xdR[] = { x/R, y/R, z/R }; // 3/

   angle *= (M_PI/180.);

   const GLfloat S = sin( angle );
   const GLfloat C = cos( angle );
   const GLfloat X = xdR[2] * (1 - C); // 1*

   for( int j = 0, i = 0; i < 11; ++j, i += 5 )
      aux_mat[i] = ( xdR[(j+1)%3] + xdR[(j+2)%3] ) * cos( angle ) + xdR[j%3];

   GLfloat a = xdR[0] * xdR[1] * C; // 2*
   GLfloat b = xdR[2] * S;          // 1*
   aux_mat[1] = -a + b;
   aux_mat[4] = -a - b;

   a = xdR[0] * X;
   b = xdR[1] * S;
   aux_mat[2] = a - b;
   aux_mat[8] = a + b;

   a = xdR[1] * X;
   b = xdR[0] * S;
   aux_mat[6] = a + b;
   aux_mat[9] = a - b;

   for( i = 3; i < 15; i += 4 )
      aux_mat[i] = 0.0;
   for( i = 12; i < 15; ++i )
      aux_mat[i] = 0.0;
   aux_mat[15] = 1.0;

}

void SpecialKey( int key, int x, int y )
{
   glMatrixMode( GL_MODELVIEW );
   switch(key)
   {
      case GLUT_KEY_F1:
         Model_View::rotate_after( 1.5, 1.0, 0.0, 0.0 );
         break;
      case GLUT_KEY_F2:
         Model_View::rotate_after( 1.5, 0.0, 1.0, 0.0 );
         break;
      case GLUT_KEY_F3:
         Model_View::rotate_after( 1.5, 0.0, 0.0, 1.0 );
         break;
      case GLUT_KEY_F5:
         Model_View::rotate_before( 1.5, 1.0, 0.0, 0.0 );
         break;
      case GLUT_KEY_F6:
         Model_View::rotate_before( 1.5, 0.0, 1.0, 0.0 );
         break;
      case GLUT_KEY_F7:
         Model_View::rotate_before( 1.5, 0.0, 0.0, 1.0 );
         break;
   }

   glutPostRedisplay();
}

void display(void)
{
   // Color de fondo: negro
   glClearColor(0.0,0.0,0.0,0.0);

   // Borramos la pantalla
   glClear(GL_COLOR_BUFFER_BIT);

   // Modo de modelado
   glMatrixMode(GL_MODELVIEW);

   // Dibujamos las lineas
   glBegin(GL_LINES);
      glColor3f(1.0,0.0,0.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(3.0,0.0,0.0);

      glColor3f(0.0,1.0,0.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(0.0,3.0,0.0);

      glColor3f(0.0,0.0,1.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(0.0,0.0,3.0);

      glColor3f(1.0,1.0,0.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(3.0,3.0,3.0);
   glEnd();

   // Forzamos el dibujado
   glFlush();

}

GLfloat* mul_matrix( GLfloat* a, GLfloat* b, int n )
{
   // a is a matrix nxn
   // b is a matrix nxn
   // return r == a * b (nxn)

   const int nn = n*n;
   GLfloat* r = new GLfloat[nn];

   int i,j,k;
   for( i = 0; i < n; ++i )
      for( j = 0; j < nn; j += n )
      {
         r[j + i] = 0.0;
         for( k = 0; k < n; ++k )
            r[j + i] += a[k*n+i] * b[j + k];
      }

   return r;
}


El código está en C++. Lo compilo con g++ así:
Código:
g++ prov.cpp -o prov -lglut -lGL


Nota: para relacionarlo con el anterior post, decir, que las dos formas de rotar 1) según los ejes de la figura o 2) según los ejes imaginarios de la pantalla dependen de si aplicas la tranformación/multiplicas la matriz antes o después( rotate_before, rotate_after).

Un saludo!
Volver arriba
daltomi



Registrado: 28 Abr 2007
Mensajes: 335
Ubicación: Argentina

MensajePublicado: 30/06/2011 12:10 am
Título:

Buenas.
Para le punto (2) : Debes seleccionar la matriz de proyección, rotarla, y por último dibujar en la matriz del modelador.
Muestro todo el código modificado por si me olvidé de algo:
Código:

#include<GL/glut.h>

#include<cmath>
   using std::sqrt;
   using std::cos;
   using std::sin;


void display(void);
void init(void);
void SpecialKey( int key, int x, int y );

class Model_View
{
   private:

   public:
      static void rotate_before( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
      static void rotate_after( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
};


int main(int argc, char **argv)
{
   glutInit( &argc, argv );

   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
   glutInitWindowPosition(20,20);
   glutInitWindowSize(500,500);
   glutCreateWindow(argv[0]);

   init();

   glutDisplayFunc(display);
   glutSpecialFunc(SpecialKey);


   glutMainLoop();

   return 0;
}

void init(void)
{
   glClearColor(0.0,0.0,0.0,0.0);
   // Color de fondo: negro
   glClear(GL_COLOR_BUFFER_BIT);
   // Borramos la pantalla
   glMatrixMode(GL_PROJECTION);
   // Modo proyección
   glLoadIdentity();
   // Cargamos la matriz identidad
   glOrtho(-4.0,4.0,-4.0,4.0,-4.0,4.0);

}

void Model_View::rotate_before( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
    glMatrixMode(GL_PROJECTION);
    glRotatef(angle,x,y,z);
}

void Model_View::rotate_after( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
   glMatrixMode(GL_MODELVIEW);
   glRotatef(angle,x,y,z);
}


void SpecialKey( int key, int x, int y )
{
   switch(key)
   {
      case GLUT_KEY_F1:
         Model_View::rotate_after( 1.5, 1.0, 0.0, 0.0 );
         break;
      case GLUT_KEY_F2:
         Model_View::rotate_after( 1.5, 0.0, 1.0, 0.0 );
         break;
      case GLUT_KEY_F3:
         Model_View::rotate_after( 1.5, 0.0, 0.0, 1.0 );
         break;
      case GLUT_KEY_F5:
         Model_View::rotate_before( 1.5, 1.0, 0.0, 0.0 );
         break;
      case GLUT_KEY_F6:
         Model_View::rotate_before( 1.5, 0.0, 1.0, 0.0 );
         break;
      case GLUT_KEY_F7:
         Model_View::rotate_before( 1.5, 0.0, 0.0, 1.0 );
         break;
   }
   glutPostRedisplay();
}

void display(void)
{
   // Color de fondo: negro
   glClearColor(0.0,0.0,0.0,0.0);

   // Borramos la pantalla
   glClear(GL_COLOR_BUFFER_BIT);

   // Modo de modelado
   glMatrixMode(GL_MODELVIEW);

   // Dibujamos las lineas
   glBegin(GL_LINES);
      glColor3f(1.0,0.0,0.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(3.0,0.0,0.0);

      glColor3f(0.0,1.0,0.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(0.0,3.0,0.0);

      glColor3f(0.0,0.0,1.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(0.0,0.0,3.0);

      glColor3f(1.0,1.0,0.0);
      glVertex3f(0.0,0.0,0.0);
      glVertex3f(3.0,3.0,3.0);
   glEnd();

    glPushMatrix();

    glTranslatef(1.0,1.0,1.0);
   
    glBegin(GL_TRIANGLE_FAN);
      glColor3f(0.5,0.5,0.5);
      glVertex3f(0.0,1.0,0.0);
      glVertex3f(1.0,1.0,0.0);
      glColor3f(0.8,0.8,0.8);
      glVertex3f(1.0,0.0,0.0);
      glVertex3f(0.0,0.0,0.0);

    glEnd();
   
   glPopMatrix();

   // Forzamos el dibujado
   glFlush();

}

Para la multiplicación de matrices puedes usar glMultiMatrixf().

Saludos.
Edito: use glPush/PopMatrix como ejemplo.
Volver arriba
Dirección AIM
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 1344

MensajePublicado: 30/06/2011 4:04 am
Título:

Muchas gracias daltomi.

Me queda mucho por aprender. Miraré con más detenimiento como funcionan las transformaciones en la matriz de proyección y en la de modelado para acabar de entenderlo.

Marcharé unos días fuera. Cuando vuelva ya escribiré si hay dudas.

Un saludo! Smile
Volver arriba
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 1344

MensajePublicado: 05/07/2011 3:20 am
Título:

Hola daltomi.

He compilado y ejecutado tu código y no hace lo mismo que el mío.

Mi programa independientemente de las rotaciones que haga con F1, F2 Y F3. Luego cuando roto con F5, F6 Y F7, rota en relación a los ejes de la cámara( horzontal, vertical y en profundidad respecto a la pantalla). En cambio tu código no.

Todo esto parece que tiene que ver con que las multiplicaciones que se aplican son siempre post-multiplicaciones(sean aplicadas al la proyección o al modelo). Implementando por software la pre-multiplicación de matrices puedo hacer lo que deseaba. Ahora bien, es una implementación software que no aprovecha los recursos hardware que puedan haber.

He pensado intentar implementar algo con glLookAt() que me permita rotar la camara alrededor de un origen. Pero tendria que traducir antes los angulos de rotación y eje en los 9 argumentos de glLookAt(). Pero me parece igual de ineficiente. Sigo buscando.

Un saludo!
Volver arriba
daltomi



Registrado: 28 Abr 2007
Mensajes: 335
Ubicación: Argentina

MensajePublicado: 05/07/2011 1:24 pm
Título:

Hola Pantalàimon_

Si, tienes razón.
Además que no funciona, existe otro problema, me he equivocado con el uso de GL_PROJECTION como vista de cámara(aunque había leído lo contrario).
Si te interesa puedes leer projection abuse

Si estas por utilizar gluLookAt() puedes leer: OpenGL-viewing

Por la dudas te dejo el link de la wiki de codepixel.com sobre OpenGL

Saludos.
Volver arriba
Dirección AIM
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 1344

MensajePublicado: 06/07/2011 7:25 am
Título:

Gracias daltomi.

A ver que te parece esta solución Smile

Código:
void Model_View::rotate_before( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
   GLfloat aux_mat[16];
   glMatrixMode( GL_MODELVIEW );
   glGetFloatv( GL_MODELVIEW_MATRIX, aux_mat );
   glLoadIdentity( );
   glRotatef( angle, x, y, z );
   glMultMatrixf( aux_mat );
}


Un saludo!
Volver arriba
daltomi



Registrado: 28 Abr 2007
Mensajes: 335
Ubicación: Argentina

MensajePublicado: 07/07/2011 11:24 pm
Título:

Hola Pantalàimon_

Excelente, yo traté de hacer algo parecido pero no funcionó. Para futuras referencias esto se conoce como "mecánica de estados de OpenGL".

Offtopic:
Como noté que estas buscando un poco de performance y estas utilizando glBegin/glEnd te comento que esta "deprecated" hace varias revisiones, es decir hay que evitarlas. En su lugar puedes usar "vertex arrays"(algo viejo también) o VBO(vertex buffer object).
Un ejemplo con vertex arrays sobre tú código:
Código:

void display(void)
{
    //std=c++0x
    const vector<GLubyte> index{0,1,2,3,4,5};

    const vector<GLubyte> color{255,0,0, 
                                255,0,0, 
                                0,255,0,
                                0,255,0, 
                                0,0,255,
                                0,0,255};
   //color y coord homogéneos
    const vector<GLfloat> coord{0.0,0.0,0.0,
                                3.0,0.0,0.0,
                                0.0,0.0,0.0,
                                0.0,3.0,0.0,
                                0.0,0.0,0.0,
                                0.0,0.0,3.0};

   glClearColor(0.0,0.0,0.0,0.0);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
 
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);

   glVertexPointer(3,GL_FLOAT,0,coord.data() );
   glColorPointer(3,GL_UNSIGNED_BYTE,0,color.data() );

   glDrawElements(GL_LINES,index.size(), GL_UNSIGNED_BYTE,index.data() );
   
   glDisableClientState(GL_VERTEX_ARRAY);
   glDisableClientState(GL_COLOR_ARRAY);

   glutSwapBuffers();//yo utilizo GL_DOUBLE

}


O también:
Código:

void display_2(void)
{
    //R,G,B,X,Y,Z
    const vector<GLfloat> cv_array{1.0,0.0,0.0,0.0,0.0,0.0,
                             1.0,0.0,0.0,3.0,0.0,0.0,   
                             0.0,1.0,0.0,0.0,0.0,0.0,
                             0.0,1.0,0.0,0.0,3.0,0.0, 
                             0.0,0.0,1.0,0.0,0.0,0.0,
                             0.0,0.0,1.0,0.0,0.0,3.0};
   
   const vector<GLubyte> index{0,1,2,3,4,5};
   
 
   glClearColor(0.0,0.0,0.0,0.0);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);
 
   glInterleavedArrays(GL_C3F_V3F,0,cv_array.data() );

   glDrawElements(GL_LINES,index.size(), GL_UNSIGNED_BYTE,index.data() );

   glutSwapBuffers();
}


Existen referencias de VA y VBO en el link de codepixel.

Saludos.
Volver arriba
Dirección AIM
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 1344

MensajePublicado: 11/07/2011 2:20 am
Título:

Gracias daltomi por las recomendaciones.

He encontrado un manual decente en castellano sobre OpenGL lo que debe ser viejo y usa funciones deprecated. Sin embargo creo que antes me empaparé un poco de ese manual aunque sea a modo introducción ya que tengo un poco de dificultad con el inglés. Luego cuando tengo una pequeña base ya intentaré mejorar las dudas más técnicas a base de esas otras fuentes.

Sobre el tema de performance, pues sí, estoy intentando hacer algo. Ahora mi intencion es crear una especie de clase "estática" Display que tenga un metodo para insertar en un contenedor( aún no se si usar list, vector o map) figuras que se muestren por pantalla. Luego otro método display() que muestre las figuras que hay en el contenedor de la clase( la cual deberá pasarse como parámetro a glutDisplayFunc()) y supongo que también algun método extractor de figuras. A todo esto tambien deberé crear una clase abstracta Figure de donde se deriben todas las clases dibujables por pantalla.

Estoy en ello. Pero a medida que vaya leyendo supongo que estas ideas iniciales que tengo también se irán modificando.

Un saludo y gracias!
Volver arriba
Requiem



Registrado: 11 Abr 2006
Mensajes: 706

MensajePublicado: 11/07/2011 8:40 am
Título:

Pantalaímon...

Lo que estoy haciendo en mi blog, ahora mismo no te servirá mucho por que me estoy centrando en el tema de 2D ( el 3D viene despues Very Happy)... pero ya tengo implementado la carga y pintado de modelos MD2 y algunas cosillas más que tal vez te sirven...

Si te interesa mirarlo para "inspirarte", eres libre de mirar lo que quieras: http://lordpakus.blogspot.com/

Enga vaya bien
Volver arriba
      Índice del Foro elrincondelc.com -> Gráficos
Página 1 de 1Todas las horas están en GMT - 8 Horas

 
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas

(c) ElRincondelC.com

Un proyecto de UrlanHeat.com