Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Va de frames por segundo

Iniciado por plugin, 01 de Enero de 1970, 01:00:00 AM

« anterior - próximo »

plugin

                                Antes de nada hola a todos. Tengo una pequeña pregunta que ha de ser fácil pero no paro de darle vueltas y no se cómo hacerlo. Vamos a ver. Estoy haciendo un pequeño juegecillo; al hacer el Flip desde el backbuffer espero al retrazo vertical con lo que (dependiendo del monitor) consigo aproximadamente unos 75 FPS. Hasta aki todo ok, pero me surge una duda. Con este refresco quiere decir que si creo una animación a 25 FPS, ésta podrá tener un desfase de +/- 1/75 FPS (unos 13 ms) ya que mientras estoy refrescando no estoy calculando posibles cambios en la animación. Entonces según veo, este problema se verá incrementado en ordenadores con refresco de monitor más bajo, pudiendo ocasionar que las animaciones no se ejecutaran a la misma velocidad en diversas mákinas.
Mi bucle principal del juego, en resumen sería:

- Controla entrada raton/teclado y varios
- Modifica estado juego
- Refresca

Claro, al ser lineal la ejecución pues mientras está refrescando NO puedo hacer otra cosa. Asi que, ¿Como se hace en los juegos de verdad? ¿Son dos procesos paralelos, uno encargado de modificar el estado del juego y otro de refrescar la pantalla? De ser así también tendríamos problemas, ya que podría refrescarse la pantalla ANTES de que terminara de actualizar el estado/posicion de los sprites.

Bueno, después de esta peaso parrafada no se si ha quedado claro el tema. A ver si me aclarais algo,... Venga, un saludo:
--plugin                                

Drácula

                                No puedes resolver el problema utilizando el refresco, necesitas resolverlo por tiempos. Tienes que pensar no en pixels por frames, sino en cuantos pixels recorre en cuanto tiempo.

Si quieres que el personaje se desplace 2 pixels a la derecha, tu quizás uses esto:
X=X+2

Pero deberías hacer esto:

X=X+2*Timing

Porque ahora el tiempo tiene que formar parte de cualquier ecuación que implique movimiento!

Si quieres, échale un vistazo a mi motor en http://webs.ono.com/dracular

Ahí está implementada esta técnica con los ejemplos muy documentados.                                
ltimas mejoras en Merlín: Multitextura.Control y generación automática de LOD.Importa ASE y X. Frustum Clipping por BB.Render añadido de wireframe y del BB.Animaciones por interpolación.Animaciones de textura...
Actualmente:Octree y jerarquías

NeLo

                                Hi.

En mi opinión (y seguro que muchos estan de acuerdo conmigo) lo mejor es no depender del retrazo vertical.

Lo que se hace es escalar el movimiento en función del tiempo transcurrido entre el último frame y el actual.

Esto se hace almacenando el momento en el que se renderiza el frame actual, entonces cuando vayas a renderizar el próximo frame, restas el momento actual y el del frame anterior, y con ese tiempo (tiempo transcurrido entre el último y el actual frame), puedes resolver la ecuación
Espacio = Velocidad / Tiempo
(esto si no hay aceleración claro :sonriendo: )
Y asi escalas el movimiento.

Para el caso concreto de las animaciones por frames, no lo se cierto, pero supongo que habrá que esperar a que pase un determinado tiempo para pasar al frame siguiente. Asi que se debe almacenar el momento en el que se pasó de frame en la animación, y en cada frame (de renderizado) mirar si ha pasado el tiempo necesario para pasar al siguiente frame de animacion (Tiempo = 1000 / FPS_de_la_animación (esto en milisegundos)).

Espero haberme explicado con claridad, si no lo he hecho, dimelo e intentare repetir con mas claridad lo que no te haya quedado claro.

Saludos.                                
Drowning deep in my sea of loathing

plugin

                                Correcto. Con lo del desplazamiento estoy de acuerdo. Pero no tanto con el cambio de los sprites. Es decir (a ver si me explico), si baja la velocidad es posible que se pierdan frames y a lo mejor hay suficiente velocidad para mostrarlos todos. Supongamos una animacion a 25 FPS y que en ese ordenador el refresco de la pantalla es 60 Hz (FPS). Asi que la animacion podría actualizarse cada 1/25+1/60 segundos, con lo que se visualizaria a 17 FPS (en el peor de los casos). No se, a lo mejor me estoy haciendo un lio.
Yo ahora mismo el problema que tu solucionas con x=x+Y*timming yo lo hago así:
- Calculo posicion personaje
- ¿Ha pasado el tiempo necesario para actualizar posicion?
- SI -> Actualizo posicion

Claro está que si el ordenador es muy lento pues con este método la nimacion NO saltaría frames e iria muy lenta. Por otro lado es para animar un personaje (Que tampoco necesito mucha velocidad). Por eso comente lo de si se solía hacer en varios procesos. Puedo implementar uno que se dedique a actualizar posiciones y otro que refresque cada cierto tiempo. Mi idea es aprovechar de alguna manera el tiempo que se tarda en dibujar la pantalla.

Pos bueno, muchas gracias por la respuesta. Saludos!!
--plugin                                

Drácula

                                El problema del personaje es exactamente igual. Imagínate que tienes una animación de 30 fotogramas que tiene que durar 1 segundo a tu gusto.

Entonces, calculas el fotograma actual dependiendo del tiempo en el que estés respecto a 1 segundo. Si el ordenador es más lento, verás menos fotogramas, pero cuando haya pasado un segundo, verás el último fotograma, que es lo que quieres. Si es más rápido, verás el mismo fotograma unas cuantas veces, pero eso no afecta negativamente visualmente!                                
ltimas mejoras en Merlín: Multitextura.Control y generación automática de LOD.Importa ASE y X. Frustum Clipping por BB.Render añadido de wireframe y del BB.Animaciones por interpolación.Animaciones de textura...
Actualmente:Octree y jerarquías

plugin

                                [Contestando a NeLo]
Joder, que rápidez con las respuestas, jeje. Si, te explicas bien pero en el cambio de sprites yo sigo viendo el problema. Si hago lo que dices (y es lo que hago) puede ser que no se anime EXACTAMENTE los aprites. Verás, a ver si me explico:
- Supongamos que pinte el ultimo sprite en un tiempo X. Entonces el siguiente frame ha de pintarse en (por ejemplo) X+15ms
- Cuando voy a pintar de nuevo el frame pregunto ¿ha pasado ya el tiempo necesario? Entonces, si por ejemplo vamos por el tiempo X+14 pues la respuesta es NO, con lo que no se actualiza el frame.
- A continuacion se refresca la pantalla, que tarda (otra suposicion) 5 ms.
- A la siguiente vez pregunto ¿ha pasado ya el tiempo para cambiar de frame? La respuesta es SI. Pero claro, ya vamos por el tiempo X+14+5=X+19. Con lo que la animacion no es EXACTA (bueno, es que soy mu quisquilloso, jeje)

Pudiera ser que pasando de esperar al refresco ganara velocidad y el desfase fuera mínimo, no se... Gracias de nuevo
--plugin                                

Frodrig

                                Bueno, lo que te han dicho es mas o menos lo que yo mismo te explicaria. Para mi motor (CrisolEngine / http://usuarios.lycos.es/crisolengine) estoy utilizando un esquema que NO hace uso del retrazado vertical. Lo que vengo a hacer es dibujar siempre que pueda y solo cuando han pasado x milisegundos actualizar la IA (ejecuto las solicitudes de eventos scripts que hayan sucedido) y la entrada.

Con el tema del movimiento y la animacion, que es lo que te interesa a ti, ya es otro cantar pues no podemos esperar nada de tiempo, ha de ejecutarse lo mas rapido posible para que tengamos unas secuencias suave. Para lograr eso, utilizo interpolacion lineal que viene a ser lo que te han explicado antes.

Me resulto de mucha ayuda el post que puso Javier Arevalo en Flipcode:

http://www.flipcode.com/cgi-bin/msg.cgi?sh...orum=totd&id=-1

Echale un vistazo pues no tiene desperdicio y puede que te resuelva todas tus dudas.

Un saludo.
Fer.                                

Emotion

                                Hola Frodrig,

He estado viendo el post de Arevalo, pero tiene un problema, y es que la resolucion que tiene la funcion del getTickCount es muy pequeña, para eso vendria mejor usar el QueryPerformance, que puede tener un margen de error de 1 microsegundo, mientras que el getTickCount tiene una precision de 1 milisegundo...

Eso se traduce en que aunque consiguieras mantener una medida de tiempo aceptable en tu maquina, tal vez la medida de tiempo no sea igual en otra maquina mas veloz o mas lenta...

Hay, ademas, una formula mas efectiva que las expuestas, aunque la pondre esta noche, que ahora mismo estoy en el curro y no quiero que me trinquen dandole gustillo al teclado...

Saludos
                               
G3: Get the Power!

MChiz

                                Hola plugin:
Pues yo me encontre con el mismo problema que tu hace unos dias.
La solucion ( a mi parecer ) es muy parecida a la que por aqui han dicho.
Supongo que te referiras a cada frame de la animacion con un indice, no? Supongo tambien que utilizaras un dato de tipo int.
Lo que yo hago es tener ese indice como un float. Si por ejemplo quieres que la animacion se mueva a un frame por segundo haces esto:

graph += 1.0f * deltaTime;

Y a la hora de pintarlo, lo tratas como un int:

draw( ( int )graph );

A mi con eso se me ha solucionado. Tenemos que con esto, para hacer 4 frames por segundo seria:

graph += 0.25f * deltaTime;

Y asi sucesivamente :sonriendo:
Espero haberte sido de ayuda.
Un saludo!!

< MChiz >                                

MChiz

                                jeje, hola de nuevo
Acabo de ver el post de Emotion y tiene toda la razon. Las funciones QueryPerformanceCounter y QueryPerformanceFrequency son muchisimo mas precisas que GetTickCount. Pero debes comprobar que el hardware en el que correra tu juego soporta estos contadores ( son por hardware ). Si no los soportas, deberas buscar alternativas. Yo te recomiendo la funcion timeGetTime(), que CREO que es mejor que la GetTickCount() ( no estoy seguro ). Esta en la libreria de Windows "winmm.lib" y en el header "mmsystem.h".
Saludos y suerte!! :sonriendo:

< MChiz >                                

NeLo

                               
Citar
- Supongamos que pinte el ultimo sprite en un tiempo X. Entonces el siguiente frame ha de pintarse en (por ejemplo) X+15ms
- Cuando voy a pintar de nuevo el frame pregunto ¿ha pasado ya el tiempo necesario? Entonces, si por ejemplo vamos por el tiempo X+14 pues la respuesta es NO, con lo que no se actualiza el frame.
- A continuacion se refresca la pantalla, que tarda (otra suposicion) 5 ms.
- A la siguiente vez pregunto ¿ha pasado ya el tiempo para cambiar de frame? La respuesta es SI. Pero claro, ya vamos por el tiempo X+14+5=X+19. Con lo que la animacion no es EXACTA (bueno, es que soy mu quisquilloso, jeje)

Creo que ahi no puedes hacer nada, si el PC solo puede mostrar un frame cada 5 milesimas, no pretendas apurar en una animacion de 1 frame cada 6 milesimas (por ejemplo). Ese problema pasará siempre (siempre que no uses V-Sync, que es lo mejor, no usarlo), lo único que se podría hacer en el caso de los sprites, es hacer una animación lo mas suave posible, es decir, con el mayor número de frames por segundo posible.

Byez.                                
Drowning deep in my sea of loathing

Frodrig

                                Cierto, cierto, yo tambien uso QueryPerformanceCounter. Supongo que Arevalo lo pondria mas que nada por motivos didacticos pero si es completamente verdad lo que comentais, hay que usar este temporizador.

Saludos.
Fer.                                

Ithaqua

                                Lo del QueryPerformanceCounter no soportado por hardware olvidaros. Que yo sepa esa función utiliza internamente la instrucción ensamblador RDTSC, que mide el número de ciclos de procesador transcurridos desde el último reset.
Esta instrucción (muy utilizada hace tiempo para medir el número de ciclos por segundo de rutinas críticas) esta presente desde el Pentium, así que a no ser de que queráis dar soporte a los 486... :sonriendo:


                               
thaqua^Stravaganza
http://ithaqua.stravaganza.org

plugin

                                Pues nada. Algo me he aclarado. Voy a darle vueltas a la cabeza a ver que saco en conclusión. Con respecto al contados, SI. Si ya nos ponemos a hacerlo exacto habra que utilizar el contador de alta precision en vez de timeGetTime() o algo así.

Bueno, a ver que hago al final.... Ya veremos a ver que nos cuenta Emotion, y la conclusion que saco de todo esto.

Gracias por toas las respuesta (joe y es mi primer post!!) . Thankx
--plugin                                

AK47

                                Saludos
Una cosa, has comentado que esperas al retrazado vertical y luego haces Flip. Usas el WaitForVerticalBlank? Si es asi quitalo, ya que el Flip ya lo hace por defecto :ojo:                                






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.