Diferencia entre revisiones de «ManuelRomero/grafica/ej1»

De WikiEducator
Saltar a: navegación, buscar
(Funcion de remodelado)
 
(26 revisiones intermedias por el mismo usuario no mostrado)
Línea 6: Línea 6:
 
;Enunciado
 
;Enunciado
 
:Se trata de realizar de forma diferente el mismo dibujo
 
:Se trata de realizar de forma diferente el mismo dibujo
:Vamos a dibujar un disco o ''agujero' ' de tres formas diferentes
+
: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
 
:Obtenemos la misma imagen, pero de ''la forma real'' nos permite modificar facilmente su aspecto
 
*Observamos el escenario
 
*Observamos el escenario
 
[[Imagen:OpenGEPractica2.png]]
 
[[Imagen:OpenGEPractica2.png]]
  
===Código por partes===
+
===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
 +
[[Imagen:VCPPNuevoArchivo3.png]]
 +
*En él seleccionamos la carpeta de Archivo de código fuente y con el botón derecho creamos un nuevo fichero
 +
[[Imagen:VCPPNuevoArchivo4.png]]
 +
*Pegamos el fuente que se nos ha facilitado en la práctica.
 +
<source lang=cpp>
 +
///////////////////////////////////////////////////////////////////////////////////////////       
 +
// 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; 
 +
}
 +
 
 +
</source>
 +
*
 +
 
 +
===Explicación del fuente===
 
*A continuación se va a explicar el código que genera el escenario anterior
 
*A continuación se va a explicar el código que genera el escenario anterior
*Esta explicación también servirá para empezar a entender cómo usar OpenGL en programación
+
*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++
 +
<source lang=cpp>
 +
#include <cstdlib>
 +
#include <cmath>
 +
#include <iostream>
 +
</source>
 +
*Se incluye la biblioteca para usar glut
 +
*Todas las funciones que empiecen por '''''glut''''' serán de esta biblioteca
 +
<source lang=cpp>
 +
#ifdef __APPLE__
 +
#  include <GLUT/glut.h>
 +
#else
 +
#  include <GL/glut.h>
 +
#endif
 +
</source>
 +
*Constantes
 +
#PI para operaciones matemáticas
 +
#N el número de vértices para el límite de un disco
 +
<source lang=cpp>
 +
#define PI 3.14159265
 +
#define N 40.0 // Number of vertices on the boundary of the disc.
 +
</source>
 +
*Se define un namespace para el proyecto
 +
<source lang=cpp>
 +
using namespace std;
 +
</source>
  
 +
*Variables globales que son estáticas y por lo tanto inicializadas
 +
<source lang=cpp>
 +
// Globals.
 +
static int isWire = 0; // Is wireframe?
 +
static long font = (long)GLUT_BITMAP_8_BY_13; // Font selection.
 +
</source>
  
 
===Programa principal===
 
===Programa principal===
Línea 43: Línea 262:
 
}
 
}
 
</source>
 
</source>
 
+
===[http://www.opengl.org/documentation/specs/glut/spec3/node9.html#SECTION00030000000000000000 Rutinas de inicialización de OpenGL y GLUT] ===
===Mensaje para usuario===
+
[http://www.opengl.org/documentation/specs/glut/spec3/node9.html#SECTION00030000000000000000 Ver referencia web en página oficial]
'''''void printInteraction(void)'''''
+
*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);'''''
 +
#GLUT_SINGLE establece un single buffered window.
 +
#GLUT_RGB es como GLUT_RGBA establece este mode de visualización
 +
#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'''''.
 +
<source lang=cpp>
 +
  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");
 +
</source>
 +
===Nuestro código===
 +
*Una vez inicializado el entorno vienen nuestra acciones
 +
*El el programa principal son las siguientes invocaciones
 +
<source lang=cpp>
 +
printInteraction();
 +
...
 +
setup();
 +
glutDisplayFunc(drawScene);
 +
glutReshapeFunc(resize); 
 +
glutKeyboardFunc(keyInput);
 +
glutMainLoop();
 +
return 0; 
 +
</source>
 +
;void printInteraction(void)
 
*Se  imprime un mensaje por la pantalla para interactuar con el usuario.
 
*Se  imprime un mensaje por la pantalla para interactuar con el usuario.
 
*Este contenido va a la consola no a la ventana windows
 
*Este contenido va a la consola no a la ventana windows
Línea 62: Línea 325:
 
   //cout << "Press the space bar to toggle between wirefrime and filled for the lower annulus." << 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;   
 
   cout << "Presiona la barra espaciadora para alternar entre el anillo relleno de color y relleno de alambre ." << endl;   
 
 
}
 
}
 
</source>
 
</source>
 +
;void glutDisplayFunc(void (*func)(void));
 +
*[http://www.opengl.org/documentation/specs/glut/spec3/node46.html#SECTION00081000000000000000 glutDisplayFunc] Carga la funcion pasada como parámetro en la ventana de window actual
 +
;void glutReshapeFunc(void (*func)(int width, int height));
 +
*[http://www.opengl.org/documentation/specs/glut/spec3/node48.html#SECTION00083000000000000000 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));
 +
*[http://www.opengl.org/documentation/specs/glut/spec3/node49.html#SECTION00084000000000000000 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
  
===Rutinas de incialización : glClearColor(...) ===
+
;void glutMainLoop(void);
 +
[http://www.opengl.org/documentation/specs/glut/spec3/node14.html#SECTION00041000000000000000 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''
 
*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)
 
*La función glClearColor(float red, float green, flota green, float alpha)
Línea 81: Línea 357:
 
</source>
 
</source>
  
;Los siguintes son métodos de la librería glut que se invocan al principio
+
;Ahora es cuando vamos a hacer funcionar nuestro código
(MRM Explicar que impliación tienes y como se usan
+
;glColor3f(float red, float green, float blue);
 
+
*Estableciendo un color, previamente borramos el que hubiera
 
+
;void glPolygonMode( GLenum face,GLenum mode);
 
<source lang=cpp>
 
<source lang=cpp>
  glutInit(&argc, argv);
+
glPolygonMode(GL_FRONT, GL_FILL);
  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");
+
 
+
 
</source>
 
</source>
;Ahora es cuando vamos a hacer funcionar nuestro código
+
*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
 
;Dibujando el círculo o disco
drawDisc(float radio ,float x, float y, float z)
+
====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)'''''
 
*Dibuja un disco con un '''''radio''''' con un espesor  y orientación , y una posición '''''(x,y,z)'''''
;Estableciendo un color
+
*Esta sección dibujaría dos circulos uno negro y pequeño (10 de radio)y otro rojo y grando (20 de radio)
glColor3f(float red, float green, float blue);
+
*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
 +
<source lang=cpp>
 +
  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);
 +
</source>
 +
====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
 +
<source lang=cpp>
 +
glEnable(GL_DEPTH_TEST)
 +
...
 +
glDisable(GL_DEPTH_TEST)
 +
</source>
  
;Dibujando el circulo sobreescrito
+
*En este caso da lo mismo el orden en el que dibujemos los discos
*En este caso primero dibujamos un  
+
<source lang=cpp>
 +
// 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.
 +
</source>
 +
====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
 +
#''true'' se visualiza en el polígono formado sólo líneas '''''GL_LINES'''''
 +
#''fasle'' se visualiza el polígono formado relleno '''''GL_FILL'''''
 +
<source 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>
 +
#glBegin(tipoPrimitiva).. glEnd()
 +
*Esta estructura permite definir una '''''primitiva'''''
 +
{{Definicion|'''''Primitiva''''' Una primitiva es simplemente la interpretación de un conjunto de vértices dibujados de una manera específica en pantalla}}
  
;Test de profundidad
+
*Primitivas geométricas básicas
El algoritmo del Z-buffer es del tipo espacio-imagen. Cada vez que se va a renderizar un pixel, comprueba
+
#GL_POINTS
que no se haya dibujado antes en esa posición un pixel que esté más cerca respecto a la cámara. Este
+
#GL_LINES
algoritmo funciona bien para cualquier tipo de objetos: cóncavos, convexos, abiertos y cerrados.
+
#GL_LINES_STRIP
Para activarlo, hay que hacer una llamada a
+
#GL_LINE_LOOP
glEnable(GL_DEPTH_TEST)
+
#GL_TRIANGLES
Esta llamada le dice a OpenGL que active el test de profundidad. Además
+
#GL_TRIANGLES_STRIP
 +
#GL_QUADS
 +
#GL_QUADS_STRIPS
 +
*También existen primitivas de objetos predeterminados
 +
#glutWireSphere(radius, slices, stacks) glutSolidSphere(radius, slices, stacks)
 +
#glutWireCube(size) glutSolidCube(size)
 +
#glutWireCone(base,height, slices, stacks) glutSolidCone(base,height, slices, stacks)
 +
#glutWireDodecahedron(void) glutSolidDodecahedron(void)
 +
#glutWireOctahedron(void) glutSolidOctahedron(void)
 +
#glutWireTetrahedron(void) glutWireTetrahedron(void)
 +
#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
 +
<source lang=cpp>
 +
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();
 +
}
 +
</source>
 +
;void glViewport(GLint x, GLint y, GLsizei w, GLsizei h);
 +
*permite definur un viewport.
 +
{{Definicion|'''''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

Última revisión de 11:39 10 jun 2013

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