ManuelRomero/grafica/ej1

De WikiEducator
Revisión a fecha de 11:39 10 jun 2013; ManuelRomero (Discusión | contribuciones)

(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Saltar a: navegación, buscar
Road Works.svg Trabajo en proceso, espera cambios frecuentes. Tu ayuda y retroalimentación son bienvenidos.
Ver página de charlas.
Road Works.svg




Practica 2

Enunciado
Se trata de realizar de forma diferente el mismo dibujo
Vamos a dibujar un disco o agujero de tres formas diferentes
Obtenemos la misma imagen, pero de la forma real nos permite modificar facilmente su aspecto
  • Observamos el escenario

OpenGEPractica2.png

Crear un nuevo proyecto

  • Creamos un nuevo proyecto según hemos visto en el capítulo anterior
Archivo ==> Nuevo ==> Proyecto 
Seleccionamos  Proyecto vacío
  • Ponemos nombre al proyecto
  • Seleccionamos la opción crear directorio para la solución

Creamos el proyecto

  • Ahora creamos un nuevo archivo fuente para nuestro proyecto
  • Para ello abrimos la venta Explorador de soluciones
  • Esta ventana muestra la estructura de directorios creada para nuestra solución o proyecto

VCPPNuevoArchivo3.png

  • En él seleccionamos la carpeta de Archivo de código fuente y con el botón derecho creamos un nuevo fichero

VCPPNuevoArchivo4.png

  • Pegamos el fuente que se nos ha facilitado en la práctica.
///////////////////////////////////////////////////////////////////////////////////////////        
// circularAnnuluses.cpp
//
// This program draws three identical-looking circular annuluses in three different ways - 
// see comments below.
//
// Interaction:
// Press the space bar to toggle between wirefrime and filled for the lower annulus.
// 
// Sumanta Guha.
/////////////////////////////////////////////////////////////////////////////////////////// 
 
#include <cstdlib>
#include <cmath>
#include <iostream>
 
#ifdef __APPLE__
#  include <GLUT/glut.h>
#else
#  include <GL/glut.h>
#endif
 
#define PI 3.14159265
#define N 40.0 // Number of vertices on the boundary of the disc.
 
using namespace std;
 
// Globals.
static int isWire = 0; // Is wireframe?
static long font = (long)GLUT_BITMAP_8_BY_13; // Font selection.
 
// Routine to draw a bitmap character string.
void writeBitmapString(void *font, char *string)
{  
   char *c;
 
   for (c = string; *c != '\0'; c++) glutBitmapCharacter(font, *c);
} 
 
// Function to draw a disc with center at (X, Y, Z), radius R, parallel to the
// xy-plane.
void drawDisc(float R, float X, float Y, float Z)
{
   float t;
   int i;
 
   glBegin(GL_TRIANGLE_FAN);
      glVertex3f( X, Y, Z);
      for(i = 0; i <= N; ++i)
	  {
         t = 2 * PI * i / N; 
         glVertex3f(X + cos(t) * R, Y + sin(t) * R, Z);
	  }
   glEnd();
}
 
// Drawing routine.
void drawScene(void)
{  
   float angle;
   int i;
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers including 
                                                       // the depth buffer.
 
   glPolygonMode(GL_FRONT, GL_FILL);
 
   // Upper left circular annulus: the white disc overwrites the red disc.
   glColor3f(1.0, 0.0, 0.0);
   drawDisc(20.0, 25.0, 75.0, 0.0);
   glColor3f(1.0, 1.0, 1.0);
   drawDisc(10.0, 25.0, 75.0, 0.0);
 
   // Upper right circular annulus: the white disc is in front of the red disc blocking it.
   glEnable(GL_DEPTH_TEST); // Enable depth testing. 
   glColor3f(1.0, 0.0, 0.0);
   drawDisc(20.0, 75.0, 75.0, 0.0);
   glColor3f(1.0, 1.0, 1.0);
   drawDisc(10.0, 75.0, 75.0, 0.5); // Compare this z-value with that of the red disc.
   glDisable(GL_DEPTH_TEST); // Disable depth testing.
 
   // Lower circular annulus: with a true hole.
   if (isWire) glPolygonMode(GL_FRONT, GL_LINE);else glPolygonMode(GL_FRONT, GL_FILL);
   glColor3f(1.0, 0.0, 0.0);
   glBegin(GL_TRIANGLE_STRIP);
      for(i = 0; i <= N; ++i)
	  {
         angle = 2 * PI * i / N; 
         glVertex3f(50 + cos(angle) * 10.0, 30 + sin(angle) * 10.0, 0.0);
         glVertex3f(50 + cos(angle) * 20.0, 30 + sin(angle) * 20.0, 0.0);
	  }
   glEnd();
 
   // Write labels.
   glColor3f(0.0, 0.0, 0.0);
   glRasterPos3f(15.0, 51.0, 0.0);
   writeBitmapString((void*)font, "Overwritten");
   glRasterPos3f(69.0, 51.0, 0.0);
   writeBitmapString((void*)font, "Floating");
   glRasterPos3f(38.0, 6.0, 0.0);
   writeBitmapString((void*)font, "The real deal!");
 
   glFlush();
}
 
// Initialization routine.
void setup(void) 
{
   glClearColor(1.0, 1.0, 1.0, 0.0);  
}
 
// OpenGL window reshape routine.
void resize(int w, int h)
{
   glViewport(0, 0, (GLsizei)w, (GLsizei)h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0.0, 100.0, 0.0, 100.0, -1.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}
 
// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
   switch(key) 
   {
      case ' ':
         if (isWire == 0) isWire = 1;
         else isWire = 0;
         glutPostRedisplay();
         break;	  
      case 27:
         exit(0);
         break;
      default:
         break;
   }
}
 
// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
   cout << "Interaction:" << endl;
   cout << "Press the space bar to toggle between wirefrime and filled for the lower annulus." << endl;  
}
 
// Main routine.
int main(int argc, char **argv) 
{
   printInteraction();
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); // Initialize the buffers 
                                                             // including the depth buffer.
   glutInitWindowSize(500, 500);
   glutInitWindowPosition(100, 100); 
   glutCreateWindow("circularAnnuluses.cpp");
   setup(); 
   glutDisplayFunc(drawScene); 
   glutReshapeFunc(resize);  
   glutKeyboardFunc(keyInput);
   glutMainLoop(); 
 
   return 0;  
}

Explicación del fuente

  • A continuación se va a explicar el código que genera el escenario anterior
  • Por ser esta práctica la primera se explicará de forma detallada
  • de esta forma servirá para empezar a entender cómo usar OpenGL en programación

Cabecera

  • definimos bibliotecas stardar de C++
#include <cstdlib>
#include <cmath>
#include <iostream>
  • Se incluye la biblioteca para usar glut
  • Todas las funciones que empiecen por glut serán de esta biblioteca
#ifdef __APPLE__
#  include <GLUT/glut.h>
#else
#  include <GL/glut.h>
#endif
  • Constantes
  1. PI para operaciones matemáticas
  2. N el número de vértices para el límite de un disco
#define PI 3.14159265
#define N 40.0 // Number of vertices on the boundary of the disc.
  • Se define un namespace para el proyecto
using namespace std;
  • Variables globales que son estáticas y por lo tanto inicializadas
// Globals.
static int isWire = 0; // Is wireframe?
static long font = (long)GLUT_BITMAP_8_BY_13; // Font selection.

Programa principal

  • El programa principal de nuestra aplicación es el siguientes
int main(int argc, char **argv) 
{
   //Mesaje para el usuario de cómo usar el programa
   printInteraction();
 
   //Rutinas de inicialización
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); // Initialize the buffers 
                                                             // including the depth buffer.
   glutInitWindowSize(500, 500);
   glutInitWindowPosition(100, 100); 
   glutCreateWindow("circularAnnuluses.cpp Practica 1");
 
   //Dibuja nuestro escenario
   setup(); 
   glutDisplayFunc(drawScene); 
   glutReshapeFunc(resize);  
   glutKeyboardFunc(keyInput);
   glutMainLoop(); 
 
   return 0;  
}

Rutinas de inicialización de OpenGL y GLUT

Ver referencia web en página oficial

  • Los primeros métodos de la librería glut se invocan al principio
  • Sirven para inicalizar la librería.
void glutInit(int *argcp, char **argv);
Inicializa la librería GLUT para que pueda usar una sesión con el sistema de ventanas. En caso de que no se pueda retorna un error
argcp Es un puntero a la variable argc del main (ver int main(char* argv, int argc); Sirve para poder pasar de la línea de comandos valores para GLUT
argcv Igual que en el caso anterior, pero ahora a la variable argv del main().
  • Toma los valores que le pasamos al main y se los envía a la bibliteca de GLUT
void glutInitDisplayMode(unsigned int mode);
Establece el modo de visualización incial.
  • Este valor por defecto es RGBA (colores básicos y el canal Alpha)
  • Se pueden concatenar bits para especificar el modo de visualización. ver la siguiente lista de valores posibles
  • En nuestro caso el método es invocado glutInitDisplayLaod(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
  1. GLUT_SINGLE establece un single buffered window.
  2. GLUT_RGB es como GLUT_RGBA establece este mode de visualización
  3. GLUT_DEPTH establece buffer de profundidad (para que objetos de adelante oculten a los de atrás, sin que éstos desaparezcan de la escena)
http://www.opengl.org/documentation/specs/glut/spec3/node12.html#SECTION00033000000000000000
void glutInitWindowSize(int width, int height);
void glutInitWindowPosition(int x, int y);
  • Establecen el tamaño y la posición inicial de la ventana cuando es creada con el método glutCreateWindow(...)
int glutCreateWindow(char *name);
  • Crea la ventana de nivel superior de nuestra aplicación.
  • el parámetro name será el título de la ventana
*El int que retorna servirá para identificar la ventana
  • Este valor se puede usar al invocar al método glutSetWindow.
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); // Initialize the buffers 
                                                             // including the depth buffer.
   glutInitWindowSize(500, 500);
   glutInitWindowPosition(100, 100); 
   glutCreateWindow("circularAnnuluses.cpp Practica 1");

Nuestro código

  • Una vez inicializado el entorno vienen nuestra acciones
  • El el programa principal son las siguientes invocaciones
 printInteraction();
 ...
 setup(); 
 glutDisplayFunc(drawScene); 
 glutReshapeFunc(resize);  
 glutKeyboardFunc(keyInput);
 glutMainLoop(); 
 return 0;
void printInteraction(void)
  • Se imprime un mensaje por la pantalla para interactuar con el usuario.
  • Este contenido va a la consola no a la ventana windows
  • es código c++ (objetos de la clase iostream)
  • Por ello hay que hacer el include de la clase iostream
  • El código de esta parte quedaría
...
#include <iostream>
...
void printInteraction(void)
{
   cout << "Interaction:" << endl;
   //cout << "Press the space bar to toggle between wirefrime and filled for the lower annulus." << endl;  
   cout << "Presiona la barra espaciadora para alternar entre el anillo relleno de color y relleno de alambre ." << endl;  
}
void glutDisplayFunc(void (*func)(void));
  • glutDisplayFunc Carga la funcion pasada como parámetro en la ventana de window actual
void glutReshapeFunc(void (*func)(int width, int height));
  • glutReshapeFunc vuelve a dibujar la ventana de window con la función que recibe como parámetro
void glutKeyboardFunc(void (*func)(unsigned char key,int x, int y));
  • glutKeyboardFunc Asigna el callback del teclado a la ventana actual de windows,
  • cuando presionemos una tecla la función pueda recoger el valor y reaccionar ante el evento
void glutMainLoop(void);

glutMainLoop hace que glut entre en su blucle de procesamiento

  • Esta función no retorna una vez invocada
  • Sí que se invocarán a las fucniones que previamente han sido registradas .

El contenido de nuestro código

glClearColor
  • Es una función propia de OpenGl como todas las que empiezan por gl
  • La función glClearColor(float red, float green, flota green, float alpha)
  • Especifica el color que pasamos como argumentos con el que se borrara el buffer al hacer un glClear().
  • Los parámetros son valores reales entre 0 y 1
  • Los tres primeros espefician el color
  • El cuarto es el nivel de transparencia canal alpha.
// Rutinas de inicialización
void setup(void) 
{
   glClearColor(1.0, 1.0, 1.0, 0.0);  
}
Ahora es cuando vamos a hacer funcionar nuestro código
glColor3f(float red, float green, float blue);
  • Estableciendo un color, previamente borramos el que hubiera
void glPolygonMode( GLenum face,GLenum mode);
glPolygonMode(GL_FRONT, GL_FILL);
  • especifica el modo de rasterización de los polígonos,
  • el parámetro face En este caso GL_FILL hace que todo el área del polígono se rellene.
  • Otras opciones GL_POINT o GL_LINE
Dibujando el círculo o disco

Discos sobredibujados

drawDisc(float radio ,float x, float y, float z)
  • Dibuja un disco con un radio con un espesor y orientación , y una posición (x,y,z)
  • Esta sección dibujaría dos circulos uno negro y pequeño (10 de radio)y otro rojo y grando (20 de radio)
  • Ambos con el mismo centro (25,75,0)
  • Observar la coordenada z a 0 hace que estén a la misma profundidad, por lo que el orden en el que se dibuja es importante (primero el grande y luego el pequeño)
  • La consecuencia es que el pequeño se superpone al grande
   glColor3f(1.0, 0.0, 0.0);
   drawDisc(20.0, 25.0, 75.0, 0.0);
   glColor3f(1.0, 1.0, 1.0);
   drawDisc(10.0, 25.0, 75.0, 0.0);

Usando el Z-buffer o test de profundidad

  • En este caso con la componente z hacemos que uno esté por delante del otro
  • Peviamente habilitamos el test de profundidad para que un objeto que esté por delante de otro lo oculte
 glEnable(GL_DEPTH_TEST)
 ...
 glDisable(GL_DEPTH_TEST)
  • En este caso da lo mismo el orden en el que dibujemos los discos
// Upper right circular annulus: the white disc is in front of the red disc blocking it.
   glEnable(GL_DEPTH_TEST); //Habilitamos el test de profundidad. 
   glColor3f(1.0, 0.0, 0.0);
   drawDisc(20.0, 75.0, 75.0, 0.0);
   glColor3f(1.0, 1.0, 1.0);
   drawDisc(10.0, 75.0, 75.0, 0.5); //Observar la componente z.
   glDisable(GL_DEPTH_TEST); // Deshabilitamos el test de profundidad.

Dibujando realmente un disco

  • En esta caso vamos a dibujar una serie de vértices que vamos a contectar entre ellos
  • Así generaremos la forma deseada
  • isWire es un booleano que actualizamos al tocar la tecla de espacio
  1. true se visualiza en el polígono formado sólo líneas GL_LINES
  2. fasle se visualiza el polígono formado relleno GL_FILL
 // Lower circular annulus: with a true hole.
   if (isWire) glPolygonMode(GL_FRONT, GL_LINE);else glPolygonMode(GL_FRONT, GL_FILL);
   glColor3f(1.0, 0.0, 0.0);
   glBegin(GL_TRIANGLE_STRIP);
      for(i = 0; i <= N; ++i)
	  {
         angle = 2 * PI * i / N; 
         glVertex3f(50 + cos(angle) * 10.0, 30 + sin(angle) * 10.0, 0.0);
         glVertex3f(50 + cos(angle) * 20.0, 30 + sin(angle) * 20.0, 0.0);
	  }
   glEnd();
  1. glBegin(tipoPrimitiva).. glEnd()
  • Esta estructura permite definir una primitiva


Icon define.gif

Definición

Primitiva Una primitiva es simplemente la interpretación de un conjunto de vértices dibujados de una manera específica en pantalla



  • Primitivas geométricas básicas
  1. GL_POINTS
  2. GL_LINES
  3. GL_LINES_STRIP
  4. GL_LINE_LOOP
  5. GL_TRIANGLES
  6. GL_TRIANGLES_STRIP
  7. GL_QUADS
  8. GL_QUADS_STRIPS
  • También existen primitivas de objetos predeterminados
  1. glutWireSphere(radius, slices, stacks) glutSolidSphere(radius, slices, stacks)
  2. glutWireCube(size) glutSolidCube(size)
  3. glutWireCone(base,height, slices, stacks) glutSolidCone(base,height, slices, stacks)
  4. glutWireDodecahedron(void) glutSolidDodecahedron(void)
  5. glutWireOctahedron(void) glutSolidOctahedron(void)
  6. glutWireTetrahedron(void) glutWireTetrahedron(void)
  7. GL_POLYGON

Funcion de remodelado

  • Esta funcion se ejecuta cada vez que tengamos que volver a cargar la pantalla
  • Aquí es donde aplicamos las matrices para ajustar nuestro modelo
  • Es importante entender estas funciones
void resize(int w, int h)
{
   glViewport(0, 0, (GLsizei)w, (GLsizei)h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0.0, 100.0, 0.0, 100.0, -1.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}
void glViewport(GLint x, GLint y, GLsizei w, GLsizei h);
  • permite definur un viewport.


Icon define.gif

Definición

Viewport es un área rectangular de la ventana de visualización


  • x, y es la esquina inferior izquierda del rectángulo, con respecto a la esquina inferior izquirda de la ventana.
  • w,h son la anchura y la altura de nuestra ventana
glMatixMode(GL_MODELVIEW)
glLoadIdentity();
  • Inicializamos la matriz de transformación.
  • Todas las transformaciones que hagamos son acumulativas y se van quedando en esta matriz
  • Al cargar la matriz identidad glLoadIdentity() gargamos la matriz identidad que es el elemento neutro de la multiplicación