ensuring framerate independent motion

foxbat

12-07-2006 08:37:27

What's the correct approach to applying a force once per frame, and having it integrate to a framerate independent value in the physics engine? I looked through the NxOgre scene setup, and it appears that it runs in constant timesteps of 60 hertz. Am I correct in that observation?

I assumed that due to constant time stepping, I could apply a constant force every frame and achieve fps independent movement, however this doesn't work. At higher framerates the simulation speed is faster. I've also tried multiplying each force applied per frame by the time between each frame. I think this would work if PhysX were running in variable timestep mode, but with constant timesteps, the same thing happens. Higher fps generates a faster simulation rate.

So far, the only thing I've been able to make fps independent is the character controller, by multiplying distance moved by the time between frames. This makes sense, since the character is moved directly each frame update rather than from the inner-workings of PhysX. Everything else, however, has me baffled.

What's the correct way produce fps independent motion?

betajaen

12-07-2006 08:41:47

NxOgre is never constant :wink: it just passes on the time since last frame to PhysX.

I believe to apply the force, is as so:


// For as long as you want to apply the force:
myBody->addForce(Vector3(100,0,0) * _timeSinceLastFrame);

foxbat

12-07-2006 08:50:51

I've tried multiplying by_timeSinceLastFrame, but the results still majorly vary with frame rate.

Regarding the time stepping, I ment to ask whether PhysX is running in constant timestep mode. I can't see anywhere in NxOgre where you use NxScene setTiming(), so I assumed that the physX scene is running in the default mode, which I believe is constant timestep at 60 hertz.

ColeZero

12-07-2006 19:33:09

Is this FPS independent motion even possible without PhysX-Hardware?
I've also noticed that the simulation is fps-dependent and not only with nxOgre, i've noticed this also with the PhysX-Demos directly.
So i thought that this can be solved with the hardware, because there is no software-solver for this, since the hardware calculates everything , except the graphics.

update:
And a completly fps independent movement is not possible because, everything that moves on the screen, no matter if thats a cube or a character is fps-dependent, if got a low framerate the game or app runs slow.
Maybe you could write a" fps-brake", so that you got not more than 60fps.

betajaen

12-07-2006 19:40:54

Don't quote me on this, but I believe you'd call for an update every time too, else if it didn't; It'd be constantly running the PhysX simulation every hertz it has.

foxbat

13-07-2006 01:36:07

I think that regardless of how often an update is called, physX will still only advance the simulation once every 60th of a second. If you call an update at a greater rate, eg 120 times a second, then half of those updates don't actually do anything. If you call an update at a slower rate then 60 times a second, physX does multiple substeps for that update. Eg, if you only call an update at 30fps, physX will do two physics calculations per frame rather than one, in order to achieve 60 updates per second.

It is very possible to get frame rate independent movement on a system. To start with, phyX updates at a constant known rate, which allows forces to be applied at a known rate. The problem is, I just can't work out what to multiply the forces by to convert the timing from the fps to 60 hertz. Simply multiplying by timeSinceLastFrame does not work.

It is possible to setup physX to update when you specify, eg update at a variable rate. But to do this, NX_TIMESTEP_VARIABLE must be specifically set in setTiming() of the PhysX scene. What this does, is only updates the simulation when you call an update. If this were used, then multiplying forces by timeSinceLastFrame would produce the correct result.

The problem with using a variable simulation rate is that the motion produced becomes slightly randomized, and the physics solution generated is not as accurate.

The physX demos are not coded to take frame rate into account. With correctly applied forces, frame rate independent movement is possible without physX hardware. If it weren’t possible, the API would be practically useless for games. Setting a fps cap is not the answer, since there is still a major variation between 30fps and 60fps. A cap would need to be set at the lowest playable framerate, say 25fps, which is out of the question.

Wretched_Wyx

13-07-2006 07:00:11

I am by no means highly familiar with this topic, but quite a few games (successful ones at that) have used PhysX. Out of the high volume of games made with PhysX, I'm sure there are a few that have been made and worked just fine without following the method you outlined. I'm not saying you're wrong, or that your method isn't necessarily better, just saying that it's not necessarily the only way to implement PhysX and have the game run optimally.

Have you checked out the PhysX forums for information on this? Or combed through the documentation that comes with the PhysX SDK? I did a little bit myself, and here a couple of things I found relating to the topic (do a search in PhysXDocumentation.chm):

Continuous Collision Detection
Simulation Timing
enum NxTimeStepMethod

I'm going to guess though, and say you already saw these things. If not, hope those helped. Interesting read for me though.

betajaen

13-07-2006 09:03:31

But to do this, NX_TIMESTEP_VARIABLE must be specifically set in setTiming() of the PhysX scene.

Well what we arguing about? I'll put it in the source if you like.

foxbat

13-07-2006 12:05:36

Don't change the source just yet. NX_TIMESTEP_VARIABLE would make things easier, but could also decrease the solver precision. I'll ask around on the ageia forums and get back to you on this.

betajaen

13-07-2006 12:27:30

I have no need to change the source source.

I've just changed ever so slightly how a scene can be created now, for anything complicated now you can use a blueprint.


mWorld = new world(mRoot)
blueprint<scene> bp();
bp.timingMethod = scene::TIMING::FIXED;
bp.iterators = 12;
mScene = bp.create("MyScene", mSceneMgr);


But of course mWorld->createScene() still exists.