Bases de Animación en OpenGL

COORDIANACIÓN DE FRAMES

Debido a que el objetivo de los videojuegos es que puedan ser jugados en la mayor cantidad posible de PC, sin importar que configuración de hardware posean (lo cual no es totalmente cierto como ser verá mas adelante), es importante que las animaciones generadas por éste se vean bien en esta gama de equipos, es decir, que la animación no se vea “cortada” porque no se pueden generar a suficiente velocidad los frames (PC “anticuado”) o “acelerada”, porque los cálculos se realizan mas velozmente de planeado lo por los creadores del juego (PC con hardware 1a) . Es en este sentido que son necesarias técnicas que de alguna manera resuelvan estas dos ocurrencias, de manera que el jugador pueda disfrutar del videojuego sin importar que PC tenga.

Limitando los FPS

Cuando los frames se producen en tiempos menores a los deseados (menos de 1/30, 1/60, etc), basta demorar un poco la aparición de cada frame para que la animación luzca igual en equipos diferentes. Para hacer esto se puede medir cuanto tiempo ha pasado desde que se mostró el último frame y, estando ya hecho el frame a montar, esperar el tiempo que haga falta para que aparezca en el tiempo correcto, es decir, 1/30 de segundo después de haber mostrado el último.

limitandofps

Para mostrar el frame se hace referencia a hacer el cambio entre buffers.

El código utilizando los ticks de Windows para realizar el conteo de tiempo se vería así:

[CPP]
DWORD tiempo = 0;

render()
{
//El código de render de la escena.
while( GetTickCount() – tiempo < 30) { //Hacer acá cualquier cosa no muy costosa en tiempo computacional } SwapBuffers(hdc); //o cualquier otra función de cambio de buffers tiempo = GetTickCount(); } [/CPP] GetTickCount() devuelve el numero de milisegundos que han pasado desde que el sistema inicio con una precisión es 10 ms (en sistemas anteriores como 95,98 y ME el tick tendrá una resolución de 55ms) , por lo que el programa correrá a entre 30 y 34 fps. La razón de reiniciar el conteo después de que se termina de dibujar el frame y no al principio de la función render() es que el tiempo de generación del frame no solo va a corresponder a las operaciones de dibujo, sino también puede ser las de colisiones, IA, interpretación de scripts, etc, por lo que estos tiempos también deben ser tenidos en cuenta a la hora de realizar el cálculo del 1/30 de segundo. Las instrucciones que van en el ciclo de espera no necesariamente tienen que ser para perder tiempo, pueden hacerse cálculos, recibir la entrada del usuario, inspeccionar los eventos del sistema, o cualquier otra cosa que no ocupe una fracción significativa de 1/30 de segundo. Coordinación por movimiento.

Este tipo de coordinación es posible usarla tanto para más frames como para menos. Esta basada en “predecir” en que punto de su recorrido se encontraría un objeto que sigue su trayectoria en un tiempo particular bien sea regulando todos los movimientos con funciones de tiempo o interpolando los valores de puntos conocidos. El dibujo de los objetos se hace basado en el tiempo que se demoró el PC en realizar los cálculos, por lo que en general la medida del tiempo debería ser más exacta. Para esto se puede utilizar el contador de alta resolución de Windows, disponible a través del plataform SDK.

Coordinacion por Movimiento

En esta gráfica se muestra una bola que rebota, de la cual se espera que produzca un frame cada vez que t aumente en 1, aunque en realidad los frames se están produciendo en los tiempos t= { 0, 0.5 , 1, 1.2, 1.8, 2 }. Debido a que la bola se rige por una ecuación paramétrica de tiempo (ehhh, cálculo vectorial?), es posible predecir en que punto se encontrará en cada uno de dichos tiempos, por lo que los cuadros intermedios se pueden renderizar conservando el movimiento como se debería observar si solo se renderizara t = {0, 1 , 2}.

Un pseudocódigo que mostraría la coordinación por movimiento (con un contador de Ticks que no es el ideal) :

[CPP]
struct obj
{
Vector3d pos;
Vector3d vel;
}Obj;

Dword tiempoAct = GetTickCount(), tiempoPas, deltaT;

render()
{
//…
tiempoPas = tiempoAct;
tiempoAct = GetTickCount();
deltaT = tiempoAct – tiempoPas;

//Se actualiza la posición de todos los objetos
for( int i=0; i< NUMOBJ; i++) { losObj[i]->pos = vel*deltaT;
//dibujar el objeto i de la coleccion losObj[]
}
}
[/CPP]

Hay que notar entonces que los objetos harían en este ejemplo “saltos” proporcionales al tiempo transcurrido entre un frame y otro, por lo que siempre se dibujarían en pantalla en la posición adecuada, sin importar si el deltaT fue mayor o menor al recomendado (1/30s , 1/60s, etc).

Aunque este tipo de coordinación parece ideal para cualquier tipo de caso (hardware lento o rápido), hay que tener en cuenta que si el hardware es demasiado pobre en prestaciones se pueden obtener frames por debajo del nivel recomendado, lo que significaría una “ralentización” molesta que sería poco deseable a la hora de jugar. También es necesario considerar que si se producen demasiados frames (150?), probablemente la pantalla descartará algunos para adecuarse a la sincronización vertical, además por mucho que se insiste en el tema de la “fluidez”, se sabe que muy pocos humanos, aún en condiciones ideales, pueden percibir diferencias notables por encima de los 75fps.

Anotaciones Finales

Es importante definir el tipo de coordinación que se debe utilizar antes de codificar o crear animaciones, debido a que posteriormente un cambio podría ser engorroso de implementar. Hay que tener en cuenta que la coordinación por frames es fácil de implementar en el sentido en que solo hay que agregar unas cuantas líneas de código a la función de render, mientras que la coordinación por movimiento requiere cambios sobre cada función que se encarga de realizar cambios sobre la posición de los objetos y en los casos en que dichos datos no pueden ser funciones paramétricas de tiempo (datos de bones, scripts de movimientos, etc), será necesario realizar una interpolación numérica sobre los datos conocidos.

1 2

Compartir esta entrada

DiggReddit
  • http://www.amorespasados.jimdo.com Eduardo gt

    bueno este tutorial esta bastante bueno, para los que se inician en este programa es bueno saber el tipo de programacion que se utiliza para animaciones GL muy bueno!!! si quieren ayuda para usar este programa escribeme a lamentevirtual@hotmail.com ya que soy un total experto en el mismo……ok 8)

  • eduardogt

    no mames aqui no explicas nada acerca de la animacion estas hablando de pura teoria y pseudocodigos, postea algo bueno, ejemplos buenos con codigo fuente y todo imagenes, asi no aportas nada. que basura!!

  • Ernesto

    Todo este site es muy “pro Windows” para mi gusto.