Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Sobre las fisicas

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

« anterior - próximo »

DraKKaR

                                Bueno, pues eso. Tengo implementadas unas fisicas en mi motor. Todo funciona de maravilla hasta que lo pruebo en un ordenador más lento donde el juego va a 10fps. Como los calculos de las fuerzas dependen del tiempo (que haya tardado en renderizarse el ultimo frame) a velocidades tan pequeñas la cosa se vuelve loca. En realidad toda la parte de las fisicas van bien, menos cuandole aplico la antigravitacion a la nave, que como depende de la distancia de ésta al suelo para darle mayor fuerza o menor de ingravidez, al ir tan lentamente los calculos pierden la continuidad y sale lo ke no deberia. Me gustaria que los que os hayas metido en esto comenteis alguna experiencia, o problema y como lo solucionasteis.                                

karlesman

                                Hola.. Drakkar
Si el problema de que vaya a 10fps es del motor grafico la solucion es calcular mas veces por frame la fisica.
Es decir si un frame tarda hacerse 1 seg
podemos calcular la fisica 5 veces para los instantes 0.2 0.4 0.6 0.8 1.

Espero haberme explicado bien                                

CordayUK

                                exactamente!                                

Lord Trancos

                                Como haceis eso? Con threads ?                                
i>SaludoteZ de Lord Trancos!
http://www.dxlab.tk - http://dxlab.host.sk - programación de DirectX con Delphi.

karlesman

                                No... no se hace con threads
Supongo q Drakkar tendra una funcion parecida a ActualizarFisica(Tiempo_Transcurrido)

Antes
Render()
ActualizarFisica(Tiempo_ultimo_frame)

Ahora
Render()
for(i=0;i<5;i++){
  ActualizarFisica(Tiempo_ultimo_frame/5)
}                                

Lord Trancos

                                Vaya, no me imaginaba que fuese tan facil! :riendo:                                
i>SaludoteZ de Lord Trancos!
http://www.dxlab.tk - http://dxlab.host.sk - programación de DirectX con Delphi.

DraKKaR

                                Si.. tengo una funcion que te actualiza las fisicas del engine, pero como estas se hacen despues del render... probare lo que decis a ver ke tal...                                

Grugnorr

                                Nass, te posteo un artículo de Javier Arévalo, JARE, ya que no hay link directo en su web( y así lo veréis todos los vagos que no entraríais a un link :riendo:)

Hay que mantener la física separada del renderizado.


Main Loop with Fixed Time Steps, by Javier Arevalo:

--------------------------------------------------------------------------------

(Note: this article first appeared as a Tip Of The Day in Flipcode. The C++ to HTML formating comes from Kurt's internal tools)

The following description came up during a thread in the SWEng mailing list, and I thought it would make and interesting Tip Of The Day. Thanks to Neil Stewart for his input, and Dave Smith for bringing it up in the first place.

Most games want to keep a consistent gameplay speed regardless of the framerate achieved by the visuals. Given the wildly varying performance of PC hardware, this is not immediately obvious. The key idea here is the assumption that rendering takes MUCH more time than game logic.

In our current project, we're using a fixed timestep scheme. In the past I have worked with variable timesteps, and somehow always keep coming back to fixed. :sonriendo: What we do in our main game loop is, essentially:


time0 = getTickCount();
do
{
 time1 = getTickCount();
 frameTime = 0;
 int numLoops = 0;

 while ((time1 - time0) > TICK_TIME && numLoops < MAX_LOOPS)
 {
   GameTickRun();
   time0 += TICK_TIME;
   frameTime += TICK_TIME;
   numLoops++;
// Could this be a good idea? We're not doing it, anyway.
//    time1 = getTickCount();
 }
 IndependentTickRun(frameTime);

 // If playing solo and game logic takes way too long, discard pending
time.
 if (!bNetworkGame && (time1 - time0) > TICK_TIME)
   time0 = time1 - TICK_TIME;

 if (canRender)
 {
   // Account for numLoops overflow causing percent > 1.
   float percentWithinTick = Min(1.f, float(time1 - time0)/TICK_TIME);
   GameDrawWithInterpolation(percentWithinTick);
 }
}
while (!bGameDone);


Let's examine the main parts:


 while ((time1 - time0) > TICK_TIME && numLoops < MAX_LOOPS)
 {
   GameTickRun();
   time0 += TICK_TIME;
   frameTime += TICK_TIME;
   numLoops++;
   time1 = getTickCount();
 }


The concept behind this is forcing every game logic tick to represent a fixed amount of real-time (real-time is the time shown on your wristwatch). Of course, ticks better take less CPU time to execute, than the real-time it represents. For the record, a variable timestep model would look more like this:


   GameTickRun(m1-m0); // Each tick represents a varying amount of time.
   time0 = time1;


I won't go in the details & issues of a variable timestep model, although it would make another great TOTD (hint, hint).

Imagine the following situation: You want to have a ball rolling at a speed of 10 pixels per second (real-time seconds). You have a TICK_TIME of 50 milliseconds (20 ticks per second), which means that every tick, or call to GameTickRun(), the ball should move 0.5 pixels per tick. That's the internal speed the game should use for each time it updates the ball's position inside the GameTickRun() function.

No, let's say that rendering each frame takes 100 milliseconds, and that updating the ball position takes no time. This means that every time you enter the loop, time1 will be 100 more than time0, therefore the loop will execute twice for each frame rendered (at 10 fps). If each render takes 50 milliseconds (say you got a better videocard), the loop will be done just once and you'll be achieving 20 fps. In both cases, you'll get your ball moving at 10 pixels per second, the second one with smoother framerate than the first. Remember, we're not fixing a framerate, we're rendering as fast as our hardware permits, and running the game logic whenever we have to.

Things get more interesting if we say that we're achieving the framerate of 30, therefore each render takes 33.333333333 milliseconds to complete. What do we get? The first time we run the loop after rendering, we find that only 33.33333 milliseconds have elapsed, not enough to fulfill a single game logic tick (TICK_TIME == 50), so we just skip the game logic and render a frame. Next time the time elapsed is 66.666666666, so we run one logic tick and account for the 50 milliseconds a tick represents, thus getting 16.666666666 milliseconds left, and render. Next tick we have 16.66666+33.3333333333 = 50 milliseconds, so we run a tick, get a remainder of 0 milliseconds, render, and go on and on...

The real-world situation is that your framerate varies anywhere from 30 to 60 fps for a fast PC game (console games often try to achieve a constant framerate).

As for the concern that a series of game logic ticks would take more time to execute, than time they represent, that's what MAX_LOOPS is for, to limit the amount of ticks executed before rendering. Yes I have seen this happen many times, that's why I have added it. If you're playing a network game you usually can't just slow down the "game time" unless all machines do the same, so you can't use the MAX_LOOPS guard. (I'm assuming a lockstep network model)

I love the separation between frames (visual updates) and ticks (game logic updates), makes everything so simple.


 IndependentTickRun(frameTime);


This is where we gather user input and update the whole user interface and perform general housekeeping. :sonriendo: Things that don't need to be run at a precise real-time speed. Since we want our game logic to be perfectly deterministic, the things executed here (or during rendering) must not affect the fixed-step game logic, in any way. In fact we have a run mode where we record the user commands to a file, and we can play back these commands entirely within the timestep loop above. This is an invaluable aid for debugging, and is the basis for the lockstep network model we employ.


 float percentWithinTick = Min(1.f, float(time1 - time0)/TICK_TIME);
 GameDrawWithInterpolation(percentWithinTick);


This litte thing allows us to interpolate the positions, orientations, etc of the visuals, in between game ticks. It smooths the visual aliasing caused by a non-constant framerate. Which is the case, because we run a game logic tick 15 times per second (TICK_TIME = 1000/15), while displaying at framerates in the range 20-60 frames per second (fingers crossed).

Javier Arevalo

--------------------------------------------------------------------------------


© Copyright 2000-2001
Javier Arévalo Baeza
                               
hat the hells!

Lord Trancos

                                Gracias por el articulo y por tenernos en consideración a los vagos :jaja:                                
i>SaludoteZ de Lord Trancos!
http://www.dxlab.tk - http://dxlab.host.sk - programación de DirectX con Delphi.

DraKKaR

                                Vale... ya me funciona bien la cosa!!! Gracias a todos por responder y en especial a grugnorr por su mega post, gracias a el he visto la luz XD.
Bueno, voy a explicar un poco mejor cual era el problema que tenia, creo ke es un tiop de problem que hasta que no te has dado de narices contra él no sabes ke existe y no escribes el codigo del engine preparandolo para ello.
Mi engine tiene un subsistema de fisicas. Éste esta programado con fórmulas que como cualquiera puede imaginar, dependen del TIEMPO utilizado en renderizar el ultimo frame. De esta manera se controla que el sistema de fisicas vaya bien en cualquier ordenador, independientemente de si va a 50 fps ke a 300 fps, la velocidad de la accion y las respuestas fisicas será la misma.
Ahora bien, una vez escrito ese codigo lo pruebas y te das cuenta de ke a velocidades muy pekeñas (en mi caso < 10 fps) las fisicas empiezan a volverse locas y todo se desmadra. Fallo posiblemente dado a errores de redondeo de las variables ke se acentuan a velocidad extremadamente lentas (corregidme si me ekivoco).
La SOLUCION: como bien han comentado los colegas de stratos: en vez de calcular una vez las fisicas antes de renderizar el frame actual, lo ke hay ke hacer es calcular las fisicas varias veces con untervalos de tiempo pekeños (ya que es con intervalos de tiempo pekeños cuando el engine va bien) de tal forma que se calculen las fisicas de ese intervalo mayor en pekeños subintervalos.
De esta forma se corrige el problema del desmadre de las fisicas. Como desventaja, el calculo repetidas veces de las fisicas que puede ralentizar el juego. Aunque puede que no sea una desventaja (CREO, aun no lo he testeado) ya que al ejecutarse un juego extremadamente lento, se supone que el cuello de botella lo produce el render, no el calculo de las fisicas.

Como nota final, aconsejar encarecidamente que se tenga en cuenta esto a la hora de desarrollar un sistema de fisicas mas o menos avanzado, porque creo que al final os encontrareis con ese problema (al menos yo si que me he encontrado con el, y como habeis leido antes, otras personas tb).

Nada mas, hasta luego y gracias a todos, que no solo hay ke postear aki para poner dudas, sino tb para dar agradecimientos y dar consejos.                                

Findeton

                                [a DraKKaR]

Hola, estoy intentando crearme un motor de física, y me gustaría que me dieses algunos consejos. Hasta ahora lo que he podido hacer es saber si un polígono choca con otro, calculando si él plano que forma un polígono intersecta con el plano que forma el otro polígono, y luego proyectando bidimensionalmente los polígonos y calculando si sus líneas se intersectan. Luego, para no realizar el cálculo polígono a polígono lo que hago es que cada objeto tenga una 'malla' con menos polígonos que el objeto en sí, y que sea a partir de esas mallas de donde se calcule las intersecciones. También he optimizado el proceso mediante el cálculo de la intersección de las esferas circunscritas de los objetos/polígonos en cuestion, es decir, sabemos el radio de los dos objetos los cuales queremos saber si intersectan, pues si la suma de los radios es menor que la distancia entre los dos objetos no puede haber intersección y por lo tanto no hay que calcularla. Me gustaría saber qué métodos utilizas tú, si no te importa.                                

Findeton

                                Ehm, podrías contestar?  :-? plz                                

DraKKaR

                                Perdona findeton, pero es ke ultimamente no me paso nunca por estos foros, estoy muy ocupado con mi engine (y leyendo el señor de los anollis XDD).

Bueno, respecto a tu pregunta, te comentare un poco como hago las colisiones, ya que más que de físicas, tu post habla de las colisiones entre objetos.

Lo primero tengo ke decir que no estoy muy orgulloso de mis colisiones y tengo pensado mejorarlas bastante. La forma en ke yo hago colisiones ahora.

Distingo entre 2 tipos de colisiones:

Colisiones Objetos-Mapa
Para saber si un objeto colisiona contra el mapa, lo ke hago es (me vais a matar XD) tratar el objeto como un punto, exactamente con el punto central del objeto. Los problemas de esto son opios: un objeto no detectara la colision con el escenario hasta ke no toke conel centro del obj, por lo ke medio objeto atravesara el escenario. Lo ke hago es trazar un segmento a partir del punto central del objeto en la posicion inicial hasta el punto donde kiero ir. De esta manera calculo la interseccion con este segmento y "todos" los triangulos del escenario. Lo pongo entre comillas porke no lo calculo sobre todos los del escenario, ya ke utilizo octrees para descartar muchisima geometria, en mapas grandes esto es esencial. La idea ke tengo para mejorarlo es tratar el objeto como un volumen, no como un punto, usando alguna primitiva ke envuelva al cuerpo contra la ke sea sencillo calcular las colisiones. Kiero usar OBBs pero tb se podrian usar cilindos, esferas, AABBs...

Colisiones Objeto-Objeto
Para detectar colsiones por ejemplo entre 2 naves, o entre disparos y naves trato a los objetos como formas simples, actualmente esferas, aunke kiero tratarlos al igual ke arriba como OBBs, porke pueden akoplarse mucho mejor ke las esferas a una forma.

EL problema, weno no es un problema, sino lo ke no me gusta demasiado de tu planteamiento es el usar mallas para detectar colisiones, detectando colisiones triangulo-trianguloMe parece costoso e innecesario, incluso con mallas reducidas. Yo creo ke los unicos poligonos contra los ke hay ke detectar colisiones son los del mapa. Para los objetos basta con un cuerpo que los envuelva y ke te permita saber cuando han colisionado de forma rapida y simple, no hace falta saber si exactamente ha colisionado con un triangulo del objeto. Por ejemplo, el MDK2 usaba un cilindro ke envuelve al personaje y ke le permitia detectar colisiones con todo. Si algo se mete dentro de ese volumen (el cilindro) pues entonces diremos que ha colisionado con el personaje.


Espero ahber respondido a tu pregunta, y perdona la tardanza ;P[/u]                                

Findeton

                                Ante todo muchas gracias por responder y dar la info. Sobre lo de utilizar pequeñas mallas para el cálculo de colisión entre objetos... quizás tengas razón en aquello de que es calcular demasiado. Así que sólo calcularé la detección de colisión entre polígonos de por ejemplo una persona y un mapa, siendo un polígono el correspondiente al 'pie' de la persona y buscando con cuáles polígonos puede colisionar a traves de una matriz en la que cada celda es un cuadrado del escenario. Una vez sepa en qué cuadrado o celda del mapa (2D, desde arriba) se encuentra el polígono, sólo tendré que detectar la colisión entre unos pocos polígonos del suelo y uno del pie. Todo ello suponiendo que la ifo del mapa ha sido preprocesada, y que en caso de que el mapa cambie, tb cambie la matriz en forma de árbol.                                

DraKKaR

                                creo que aun podrias simplificar mucho más las colisiones eliminando eso de detectar colisiones entre poligonos del mapa y poligonos del objeto. Yo limitaria las colisiones a poligonos del mapa contra un volumen ke envuelve al objeto, como un cilindro, un OBB (ya habras notado ke me ponen caxondo los OBBs...).
Aunque es solo mi punto de vista, y conocer otros puntos de vista tb estaria bien.                                






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.