ManuelRomero/grafica/ej1

De WikiEducator
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
  • 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

<sourece lang=cpp>

// 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();

</source>

  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
  9. También existen primitivas de objetos predeterminados
  10. glutWireSphere(radius, slices, stacks) glutSolidSphere(radius, slices, stacks)
  11. glutWireCube(size) glutSolidCube(size)
  12. glutWireCone(base,height, slices, stacks) glutSolidCone(base,height, slices, stacks)
  13. glutWireDodecahedron(void) glutSolidDodecahedron(void)
  14. glutWireOctahedron(void) glutSolidOctahedron(void)
  15. glutWireTetrahedron(void) glutWireTetrahedron(void)
  16. GL_POLYGON
Dibujando el circulo sobreescrito
  • En este caso primero dibujamos un
Test de profundidad

El algoritmo del Z-buffer es del tipo espacio-imagen. Cada vez que se va a renderizar un pixel, comprueba que no se haya dibujado antes en esa posición un pixel que esté más cerca respecto a la cámara. Este algoritmo funciona bien para cualquier tipo de objetos: cóncavos, convexos, abiertos y cerrados. Para activarlo, hay que hacer una llamada a glEnable(GL_DEPTH_TEST) Esta llamada le dice a OpenGL que active el test de profundidad. Además