practica4_animacion

Transcripción

practica4_animacion
PRACTICA # 4 DOBLE BÚFER Y ANIMACIÓN
ÁLVAREZ FAJARDO GERARDO ADOLFO
GRUPO 4
Cuestionario previo
1. Investigue y
tienen. Esto es,
a. frame
b. depth
c. stenci
reporte cuáles búferes se implementan en OpenGL y que función
investigue el
buffer o búfer de color, tanto frontal como posterior.
buffer o búfer de profundidad.
buffer.
Para poder trabajar con OpenGL, primero se debe crear un contexto de trabajo, este contexto
contiene el estado actual de maquina finita, asi como las referencias a los diferentes buffers
de trabajo, estos buffers se pueden ver como zonas de memoria correspondiendo a la pantalla
en las cuales OpenGL va a dibujar, en general a parte del buffer de color
(GL_COLOR_BUFFER) que es el buffer en el cual se van a dibujar las
primitivas, existen otro tipo de buffers mas especializados.
La configuracion en memoria de estos buffers (cuantos bits representan un pixel, etc) depende
de la manera como fue creado el contexto OpenGL y de las limitaciones del hardware, por esto
no se puede acceder directamente sino solo a traves de las primitivas OpenGL.
OpenGL puede funcionar adicionalmente de dos maneras, de modo directo o indirecto:
Modo directo: las primitivas se van dibujando a medida que se van definiendo.
Instruccion -> Buffer de Color = Pantalla
Modo indirecto: las primitivas se guardan en una lista y solo se dibujan cuando el usuario decida
o la lista este llena, esto permite optimizar la fase de dibujo.
Instruccion-> Pila de instrucciones-> flush -> Buffer de Color = Pantalla
En este modo cuando se desea que OpenGL pinte lo que esta en la lista se utiliza la instrucción
glFlush(): esta instruccion obliga a pintar y no espera a que el hardawre termine para continuar
con el programa, analogamente la glFinish() obliga a pintar pero espera a que el hw termine
antes de continuar con el programa.
En el modo indirecto, OpenGL permite definir dos buffers de colores (doublebuffer), asi un
buffer corresponde a lo que se ve en pantalla y otro a el buffer donde se esta pintando, de
esta manera una vez que se ha pintado todo lo deseado y se quiere que esto aparezca en
pantalla se intercambian los buffers, esta instruccion depende del sistema operativo para esto
se utilizara la instruccion de la libreria portable glut: glutSwapBuffers() (esta ejecuta
implicitamente glFlush o glFinish), en este modo glFlush y glFinish obligan a pintar en el buffer
de dibujo pero esto NO sera visible hasta intercambiar buffers.
Para utilizar los diferentes tipos de buffers de OpenGL estos se deben crear al crear el
contexto opengl, en el caso de la utilizacion de la libreria glut, al llamar la funcion:
glutInitDisplayMode (buffers), buffers es una combinacion de valores indicando que buffers
se deben crear i.e. para crear un contexto con doble buffer rgba y z-buffer buffers seria =
GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH, los valores para crear otro tipos de buffers
son:
GLUT_STENCIL = buffer de stencil.
GLUT_ACCUM = buffer de acumulacion.
Todos los buffers deben ser activados o desactivados dependiendo de la utilizacion con el
comando glEnable(param) o glDisable(param), donde param corresponde al tipo de test que se
activa, i.e param = GL_STENCIL_TEST para el buffer de stencil, o param=GL_DEPTH_TEST
para el buffer de profundidad (activado por defecto).
Los buffers de stencil, acumulacion y profundidad funcionan aplicando una serie de operaciones
y funciones sobre los valores que se van a escribir en el buffer, asi para manejar la funcion del
buffer de profundidad se utiliza la funcion glDepthFunc(funcion), donde funcion indica cuando
pasa el test de profundidad (GL_EQUAL, GL_LESS, GL_LEQUAL (por defecto),
GL_NOTEQUAL, GL_GREATER, GL_GEQUAL). En el caso de la funcion de test, se define
glStencilFunc(funcion, mascara), donde función son las mismas que para la profundidad, y
mascara indica que bits del stencil se utilizan. Adicionalmente a la funcion de stencil, se utiliza
la operacion de stencil glStencilOp(fallo,zfallo,zpaso) que especifica como se modifica el
buffer de stencil dependiendo de si la funcion del buffer stencil y z fallaron o pasaron, pueden
ser GL_KEEP,GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR, GL_INVERT.
2. Investigue y reporte cómo se hace una secuencia animada de caricaturas.
Cualquier forma de animación, bien sea esta al estilo antiguo de Disney (frames hechos a
mano), cine, animaciones gif, videos de computadora y videojuegos utiliza una técnica que
consiste en mostrar rápidamente, a entre 30 y 60 cuadros por segundo (fps) un conjunto de
imágenes que varían de forma ligera, para crear la sensación de movimiento aprovechando una
característica de la visión humana llamada persistencia de la visión.
En el caso particular de los videojuegos, los frames se hacen mezclando un conjunto de figuras
bidimensionales (sprites) o haciendo complejos cálculos sobre la manera en que se vería una
proyección bidimensional de una escena “abstracta” tridimensional (3d), o una mezcla de
ambas, y realizando en cada caso un cálculo del pequeño movimiento que debe hacer cada
objeto para dar una sensación fluida de animación.
El búfer doble
Se ha mencionado ya que para poder dar la sensación de movimiento es necesario mostrar
cerca de 30 cuadros por segundo. El problema es que el computador no genera
“instantáneamente” la imagen a partir de los sprites o la escena 3d, por lo que si se posee una
sola área de dibujo en la memoria se verán molestos intervalos entre un frame y otro (mientras
se hacen los cálculos y se realizan movimientos de memoria). Es en este sentido que la
estrategia de múltiples buffers, dos en este caso funciona.
La estrategia es bastante simple, se tienen 2 áreas de memoria, una es la que actualmente se
muestra en pantalla (Front Buffer) y la otra es sobre la cual se realizan los cálculos (back
buffer). Cuando la escena se termina de dibujar se intercambian los papeles entre los buffers,
es decir, el Back se convierte en Front y viceversa. De esta manera el usuario no ve cuando se
está renderizando sobre el buffer, solo ve el resultado final, con la ventaja adicional de que el
proceso es bastante eficiente, ya que no se realizan copias entre áreas de memoria, al menos
para mostrar los frames.
La parte teórica funciona de manera similar en diferentes entornos, bien sea DirectX, OpenGL
o SDL. En el caso práctico de OpenGL, la especificación del API no incluye una garantía de que
los dos buffers estén presentes (obviamente al menos el Front debe existir), por lo que las
funciones para solicitar y manejar mas de un buffer dependen del entorno en el que se esté
ejecutando la aplicación (Windows, Mac, Linux, etc.). Microsoft provee una implementación
propia del Doble Buffer para Windows y esta misma funcionalidad es ofrecida por Glut y
similares para diferentes sistemas operativos de manera genérica.
Implementación Glut
Es bastante sencilla (ver tutorial Hola Mundo 3d en OpenGL), basta solicitar el modo Doble
Buffer al inicializar la ventana y cada vez que se terminan de pasar los parámetros de dibujo a
OpenGL y estos han sido ejecutados, pedir un cambio de Buffer así:
1.
2.
3.
4.
5.
6.
inicializarVentana()
{
…
glutInitDisplayMode(GLUT_DOUBLE| …)
…
}
7.
8. render()
9. {
10.
//comandos de dibujo
11.
glutSwapBuffers();
12. }
La función glutInitDisplayMode() se encarga de solicitar al sistema el modo requerido por el
programador, en este caso Doble Buffer (GLUT_DOUBLE) y otros que se le suministren
seguidos de “|” (GLUT_DOUBLE | GLUT_RGB por ejemplo). glutSwapBuffers() intercambia el
Buffer actual sobre el que se está dibujando (Back) con el que se muestra en pantalla (Front).
Implementación Windows
La implementación del doble buffer es algo mas compleja (ver tutorial Hola Complicado Mundo
OpenGL – Win32), pero básicamente está ligada al PIXELFORMATDESCRIPTOR – HDC con los
cuales se solicita y al HDC, con el cual se intercambian los Buffers. El código luce así:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
HDC hdc=NULL;
…
crearVentana()
{
//todo el código para crear la ventana
static PIXELFORMATDESCRIPTOR pfd=
{
...
,... |PFD_DOUBLEBUFFER | //tercer parámetro
,...
};
PixelFormat=ChoosePixelFormat(hdc,&pfd);
}
render()
{
//El código de render
SwapBuffers(hdc);
}
Donde el pdf es la variable para inicializar el modo de pantalla y hdc es el hardware device
context asociado a la ventana.
3. Investigue y reporte que hace la función glutDisplayFunc()
void glutDisplayFunc (void (*func)(void)): el glutDisplayFunc fija el servicio repetido de la
exhibición para la ventana actual.
4. Investigue y reporte que hace la función glutIdleFunc().
void glutIdleFunc (void (*func)(void)) el glutIdleFunc fija el servicio repetido ocioso global.
GLUT llama a ésta función todo el tiempo, haciendo que se logre una animación
Sintaxis: void glutIdleFunc(void (*func)(void));
5. Investigue y reporte que hace la función glutMainLoop();
La función glutMainLoop() es el bucle infinito de gestión de eventos. Se entra en ella pero
jamás se sale. Cuando se dispara el evento que provoca la salida del bucle, el programa acaba.
Cualquier cosa que pongamos detrás de la llamada a glutMainLoop() no se ejecutará jamás.
Con la función glutMainLoop(), avisamos a GLUT que estamos listos para entrar en loop de
eventos de la aplicación.
La función glutMainLoop() hace que el computador espere la ocurrencia de un evento para
entonces invocar a la función respectiva (callback).
Ejercicio 1
Uno de los cubos solo se mantiene rotando sobre su eje y el otro además de rotar, se traslada.
Ejercicio 2. Animando la cámara.
Esta vez la cámara se mantiene rotando 360° mientras que la animación en ambos cubos
continúa.
Ejercicio 3. Animación libre.
1) Un par de esferas. Una se mueva de derecha a izquierda y la otra de izquierda
a derecha, ambas sobre el eje x.
2) Un par de esferas. Una se mueve de arriba hacia abajo y la otra de abajo hacia
arriba, en el eje y.
Conclusiones
Con esta práctica aprendí a animar objetos; Ahora ya creando y teniendo cualquier objeto en la
pantalla, puedo darle movimiento y rotación en distintos sentidos.
Comprendí la utilización de los búfers.

Documentos relacionados