ManuelRomero/grafica/ej1
De WikiEducator
Revisión a fecha de 03:11 9 jun 2013; ManuelRomero (Discusión | contribuciones)
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 invoccar 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");
Mensaje para usuario
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; }
===Rutinas de incialización : glClearColor(...). glutInit( ...)
- 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
- Dibujando el círculo o disco
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)
- Estableciendo un color
glColor3f(float red, float green, float blue);
- 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