OpenGL + Glut

Capítulo 1 : Inicio

Después de mucho navegar por internet y de ir aprendiendo a programar desde sitios en ingles, y viendo la gran cantidad de personas que quieren aprender a programar con gráficos, he decidido empezar a escribir este documento, pero espero que quede claro, yo, como los que leen esto, estoy siempre aprendiendo más y más de opengl, no piensen que después de haber leído esto van a salir a programar un quake 4 o algo parecido.

Para empezar, este tutorial será sobre opengl usando la librería GLUT, lo cual lo hace mucho más portable a otras plataformas.

Las primeras funciones son para inicializar GLUT, son void glutInit(int argc, char **argv) que es para inicializar GLUT.

Después de haber inicializado GLUT, empezamos seteando nuestra ventana de trabajo, con glutWindowsPosition(int x, int y) donde x e y son las coordenadas de nuestra ventana.

Luego definimos el tamaño de nuestra ventana con glutWindowsSize(int width, int height) donde width y height son largo y ancho de nuestra ventana.

Luego definimos el "modo", con la función glutDisplayMode(unsigned int mode) donde mode puede tomar los siguientes valores:

  • GLUT_RGBA o GLUT_RGB selecciona una ventana con rgb ( rojo, verde, azul) o rgba ( rojo, verde, azul y el canal alfa). El canal alfa se ocupa para transparencias.
  • GLUT_INDEX lo lamento, pero nunca he ocupado esto antes

También se puede seleccionar si se quiere una ventana con doble o un buffer (doble buffer es para animaciones, aunque se puede usar single para animaciones, pero no se vería perfecto).

  • GLUT_SINGLE un buffer.
  • GLUT_DOUBLE doble buffer, para animaciones principalmente.

También se pueden especificar que buffer se quiere :

  • GLUT_ACCUM buffer de acumulación (nunca lo he ocupado).
  • GLUT_STENCIL buffer stencil (no se cual seria la traducción), se ocupa para reflejos y sobras.
  • GLUT_DEPTH buffer de fondo.

Si se quiere una ventana tipo RGB, con buffer simple y depth buffer seria :

glutDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);

Después de todos esos pasos, se crea la ventana con el comando glutCreateWindows(char *title), donde title es el titulo de esta. GlutCreateWindows retorna el identificador de la ventana, que se ocupa cuando se definen múltiples ventanas. Así, nuestro código quedaría algo así:

#include <gl/glut.h> // glut.h incluye opengl.h y glu.h
 
int main( int argc, char ** argv) { 
   glutInit(&argc, argv); 
   glutWindowsPosition(100, 100); // Este comando puede ser opcional 
   glutWindowSize(320, 320); 
   glutCreateWindow("Primer programa GLUT"); 
}

Si compilan y ejecutan este código, se abrirá una ventana en negro, pues no hemos dibujado nada aún.

Ahora vamos a dibujar algo sencillo en la pantalla:

void dibujar() {
   glClear(GL_COLOR_BUFFER_BIT); // Se borra el buffer de la pantalla 
   glBegin(GL_TRIANGLES); // Se va a empezar una secuencia de triángulos. 
   glVertex3f(-0.5, -0.5, 0.0); // glVertex3f se usa para definir puntos 
                                // con 3 coordenadas que sean float, 
                                // glvertex3d para 3 coordenadas que sean double. 
   glVertex3f(0.0, 0.0, 0.0); 
   glVertex3f(0.0, 0.5, 0.0); 
   glEnd(); 
   // Se termina de definir los triángulos. 
}

Uno le puede poner el nombre que quiera a esta función, lo que si debe hacer es decirle a GLUT cual es es nombre de esta, esto se hace por medio de la fusión glutDisplayFunc(void *(func)(void)); donde func es el nombre de la función que hace las tareas de dibujar.

Ahora le avisamos a GLUT que estamos listos para entrar en loop de eventos de la aplicación, esto lo hacemos con la función glutMainLoop();. Ahora nuestro código luce así:

#include <gl/glut.h>
void dibujar() {
    glClear(GL_COLOR_BUFFER_BIT);	// Se borra el buffer de la pantalla
    glBegin(GL_TRIANGLES);	// Se va a empezar una secuencia de triángulos.
		glVertex3f(-0.5, -0.5, 0.0);	// glVertex3f se usa para definir puntos 
		glVertex3f(0.0, 0.0, 0.0);      // con 3 coordenadas que sean flota, 
		glVertex3f(0.0, 0.5, 0.0);      // glvertex3d para 3 coordenadas que sean double.
    glEnd();				// Se termina de definir los triángulos.
}
	
int main(int argc, char **argv) {
   glutInit(&argc,argv);
   glutInitWindowPosition(100,100);
   glutInitWindowSize( 320, 320);
   glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
   glutCreateWindow("Un Triángulo!!!");

   glutDisplayFunc(dibujar);
   glutMainLoop();
}

Otras funciones necesarias para empezar, son glColor3f( float r, float g, float b); con lo cual definimos el color que vamos a usar.

void dibujar() {
   glClear(GL_COLOR_BUFFER_BIT);	// Se borra el buffer de la pantalla
   glBegin(GL_TRIANGLES);	// Se va a empezar una secuencia de triángulos.
   GlColor3f(1.0, 0.0, 0.0);
   glVertex3f(-0.5, -0.5, 0.0);	// glVertex3f se usa para definir puntos con 3 
   glColor3f(0.0, 1.0, 0.0);    // coordenadas que sean float, glvertex3d para 3 
   glVertex3f(0.0, 0.0, 0.0);   // coordenadas que sean double.
   glColor3f(0.0, 0.0, 1.0);
   glVertex3f(0.0, 0.5, 0.0);
   glEnd();				// Se termina de definir los triángulos.
}

Con ese nuevo código se obtendrá un triángulo con cada vértice de diferente color.

Otra cosa, si se quieren definir figuras que no sean triángulos, en glBegin, se puede ocupar en vez de GL_TRIANGLES, GL_QUADS para definir polígonos de 4 lados, GL_POLYGON para definir polígonos cualquiera, aunque creo que las tarjetas de video transforman todo a triángulos al momento de mostrarlo. También esta la opcion GL_LINE, para dibujar lineas.

Si se dibuja en 2D, se puede ocupar glVertex2f( float x, float y); o glVertex2d(double x, double y);

Cambiando el tamaño de la ventana

Al cambiar el tamaño de la ventana a veces, no se despliega lo esperado, puesto que los cálculos de perspectiva quedan mal hechos por tener un nuevo tamaño, para solucionar esto, GLUT proporciona una función que llama a una función que recalcule estos valores para casos en que se cambie el tamaño de la ventana. La función es glutReshapeFunc(void *(func)(int width, int height); donde func es la función a la que llamaremos y width y height son los datos que le ingresaremos a esta. Entonces en main() agregamos antes de glutMainLoop(); glutReshapeFunc(cambiarTamano);.

Antes de definir la función voy a explicar otras funciones necesarias, primero, gluPerspective(double fov, double aspect, double near, double far), esta función pone la perspectiva, así se ven mas reales los gráficos que hagamos. fov es el campo de visión que queremos, se define en grados y va en relación con aspect, near y far es cuan cerca y lejos podemos ver, con un menor far, veremos hasta más cerca.

gluLookAt(double eyex, double eyey, double eyez,           // Desde donde miramos 
          double centerx, double centery, double cenbterz, // Hacia donde miramos 
  	      double upx, double upy, double upz)              // el eje hacia arriba

gluLookAt define dónde esta el observador, hacia donde esta mirando y cual es el eje que nos indica la dirección hacia arriba.

Y ahora vamos a definir esta función :

void cambiarTamano(int largo, int ancho) {
   if(ancho=00) ancho=1;		// Previene que dividamos por 0
   glMatrixMode(GL_PROJECTION);	// Escogemos la matriz de proyección
   glLoadIdentity();		// Se resetea la matriz
   glViewPort(0,0,largo, ancho);	// Se va a usar toda la ventana para mostrar gráficos
   gluPerspective( 45 ,		// ángulo de visión
      (float)lago/(float)ancho, // Razón entre el largo y el ancho, para calcular la perspectiva
      1,					    // Cuan cerca se puede ver
      1000);					// Cuan lejos se puede ver
   glMatrixMode(GL_MODELVIEW);	// Escogemos la matriz de vista
   glLoadIdentity();
   gluLookAt( 0.0, 0.0, 0.0,	// Hacia donde miramos
	 		  0.0, 0.0, -1.0,	// Desde donde miramos
			  0.0, 1.0, 0.0);	// Que eje es el que esta hacia arriba
}	

Así es como queda el código.



suministrado por FreeFind
Valid HTML 4.0! Valid CSS!