Diferencia entre revisiones de «ManuelRomero/grafica/ej1»
De WikiEducator
(→Mensaje para usuario) |
(→Funcion de remodelado) |
||
(30 revisiones intermedias por el mismo usuario no mostrado) | |||
Línea 5: | Línea 5: | ||
===Practica 2=== | ===Practica 2=== | ||
;Enunciado | ;Enunciado | ||
− | :Se trata de | + | :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 |
[[Imagen:OpenGEPractica2.png]] | [[Imagen: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 | ||
+ | [[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 | ||
− | * | + | *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] === | |
− | === | + | [http://www.opengl.org/documentation/specs/glut/spec3/node9.html#SECTION00030000000000000000 Ver referencia web en página oficial] |
− | '''''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 | ||
+ | ;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'' | ||
+ | *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''. | ||
<source lang=cpp> | <source lang=cpp> | ||
// Rutinas de inicialización | // Rutinas de inicialización | ||
Línea 76: | Línea 357: | ||
</source> | </source> | ||
− | ; | + | ;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); | ||
+ | <source lang=cpp> | ||
+ | glPolygonMode(GL_FRONT, GL_FILL); | ||
+ | </source> | ||
+ | *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 | ||
+ | <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> | ||
+ | *En este caso da lo mismo el orden en el que dibujemos los discos | ||
<source lang=cpp> | <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}} | ||
+ | *Primitivas geométricas básicas | ||
+ | #GL_POINTS | ||
+ | #GL_LINES | ||
+ | #GL_LINES_STRIP | ||
+ | #GL_LINE_LOOP | ||
+ | #GL_TRIANGLES | ||
+ | #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> | </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
Trabajo en proceso, espera cambios frecuentes. Tu ayuda y retroalimentación son bienvenidos. Ver página de charlas. |
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
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
- En él seleccionamos la carpeta de Archivo de código fuente y con el botón derecho creamos un nuevo fichero
- 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
- PI para operaciones matemáticas
- 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);
- 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.
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
- true se visualiza en el polígono formado sólo líneas GL_LINES
- 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();
- glBegin(tipoPrimitiva).. glEnd()
- Esta estructura permite definir una primitiva
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
- GL_POINTS
- GL_LINES
- GL_LINES_STRIP
- GL_LINE_LOOP
- GL_TRIANGLES
- 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
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.
- 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