OGRE3DBody Movement - setLinearVelocity at constant v / t ?

danoli3

07-10-2009 11:47:29

Hello,

At the moment I'm trying to move my actor (OGRE3DBody) by:
physicsBody->setLinearVelocity( NxOgre::Functions::XYZ<Ogre::Vector3, NxOgre::Vec3>( walkDirection ));

For the walkDirection vector I am using the current direction the player is facing
When I use the above code the Actor moves at the slowest speed in the direction.

I overcame this by multiplying the vector like this:
// Physics Code
Vector2 direction = this->getFacing(); // Get direction that the mesh is facing
float velocityY = physicsBody->getLinearVelocity().y; // Get linear velocity from the Y axis (so gravity still applies)
direction.x = direction.x * walkSpeed; // multiply direction by walkSpeed ( value of 86 )
direction.y = direction.y * walkSpeed;
// Get Y axis velocity (so our actor is effected by gravity when moving
walkDirection = Ogre::Vector3(direction.x , velocityY, direction.y);
physicsBody->setLinearVelocity( NxOgre::Functions::XYZ<Ogre::Vector3, NxOgre::Vec3>( walkDirection ));


I am not sure if this was the right thing to do, however it worked.
I had my character moving in the direction at a speed.

However more recently when debugging the movement system in a multi player environment I have noticed that this system is dependant on FPS and not on Time so every player had different movement speeds depenant on the FPS of that player.
This is not a desired outcome. Lol.

Please any help with this would be appreciated so much.
Am I using the right system? setLinearVelocity seems to work for player movement however is there a way to set a velocity that is constant and base it off time not Frame Rate?

I also have read this: viewtopic.php?f=6&t=8293&start=0 however OGRE3DBody uses an Actor not a Kinematic Actor so that solution doesn't help.

Thanks ;)

danoli3

09-10-2009 16:13:44

$5 donation via paypal to the person who leads me to a solution ;)

spacegaier

09-10-2009 16:24:43

Well as every game should always do: Just multiply the walking vector (the tranlastion vector in general) with the timeSinceTheLastFrame (you can either get itdirectly from Ogre or compute it yourself).

EDIT: The main() function in this class demonstrates how to calculate this time yourself in your main loop.

danoli3

13-10-2009 17:52:07

Thanks for your reply Spacegaier.

I tried doing this:

Vector2 direction = this->getFacing(); // Get direction of the actor
float velocityY = physicsBody->getLinearVelocity().y;
direction.x = direction.x * (walkSpeed * (walkSpeed * deltaTimeSecs));
direction.y = direction.y * (walkSpeed * (walkSpeed * deltaTimeSecs));
// Get Y axis velocity (so our actor is effected by gravity when moving
walkDirection = Ogre::Vector3(direction.x , velocityY, direction.y);
physicsBody->setLinearVelocity( NxOgre::Functions::XYZ<Ogre::Vector3, NxOgre::Vec3>( walkDirection ));
// Set the Velocity to the current actor facing point


On one computer I walked the same distance in 13 seconds as I walked in 7 seconds on another.
Any idea?

deltaTimeSecs is time since last frame.

betajaen

13-10-2009 18:02:08

Although it's probably not a huge factor, Friction will play a roll if your Body is on the touching the ground - causing the actual velocity to slow down.

Have you compared on reading what the velocity is in the next frame, compared to the one just set?

[Edit]

Are you using the Git version with the new Timer Code, or the standard release BloodyMess?

danoli3

14-10-2009 14:29:58

Using Git Version yes.

This is the source of the deltaTimeSecs:
unsigned long currentTime = timer.getMilliseconds();
Real deltaTime = 0;

if (lastTime - currentTime == 0)
deltaTime = 0;
else
deltaTime = (timer.getMilliseconds()-lastTime)/1000.0f;


I really don't think its the friction.

This is the current friction code:
NxOgre::SceneDescription sceneDesc;
sceneDesc.mGravity = NxOgre::Vec3( 0, -98.0f, 0 );
sceneDesc.mName = "Physics World";
// create the scene
pPhysScene = pPhysWorld->createScene( sceneDesc );

// create some default physical values that are applied globally to the physics scene.
pPhysScene->getMaterial( 0 )->setStaticFriction( 0.5 );
pPhysScene->getMaterial( 0 )->setDynamicFriction( 0.5 );
pPhysScene->getMaterial( 0 )->setRestitution( 0 );


I tried with:
pPhysScene->getMaterial( 0 )->setStaticFriction( 0 );
pPhysScene->getMaterial( 0 )->setDynamicFriction( 0 );


No noticed difference.

I've done a lot of testing and the player does move at a different speed depending on the fps.
Can you see a problem with the velocity code?

betajaen

14-10-2009 14:52:54

I've been working on this now for a later part of a day.

Although I don't have a definite answer yet, multiplying the velocity by time step isn't the answer, also your gravity is 10 times higher than it should be.

betajaen

14-10-2009 21:07:07

Alright, I've found something out that I didn't know before.

I'll try and sum up what I know; It's somewhat related to what you want, but I think the research needs to be written down for future users.

With the default settings and the current timing code in NxOgre, things do move slower if the current frame rate is below the inverse of the timestep. So if your timestep is 1/60, then when your FPS goes below 60, then the Physics slows down.

I can show you this with the new timing code and timestep classes in Detritus. I've done two tests; a box has a constant velocity of 1m/s in the +X direction. Around every second interval I take a measurement of where the box is, and what the time is. I also perform a simple velocity equation to calculate where the box should ideally be, then I compare the two.

This is an ideal situation where the delay is lowest as possible. Unfortantly, I can't get results bang on the second because computers are unpredictable.

* PhysX Time: 1.01666, Actual Time:1.01677, Diff: 1.00011%
Actual: 1.01666, Calculated:1.01666, Diff: 1%
* PhysX Time: 2.03333, Actual Time:2.03314, Diff: 0.999907%
Actual: 2.03333, Calculated:2.03333, Diff: 1%
* PhysX Time: 3.04999, Actual Time:3.0494, Diff: 0.999806%
Actual: 3.04999, Calculated:3.04999, Diff: 1%
* PhysX Time: 4.06666, Actual Time:4.06573, Diff: 0.999771%
Actual: 4.06666, Calculated:4.06666, Diff: 1%
* PhysX Time: 5.08331, Actual Time:5.08294, Diff: 0.999926%
Actual: 5.08331, Calculated:5.08331, Diff: 1%
* PhysX Time: 6.09996, Actual Time:6.10034, Diff: 1.00006%
Actual: 6.09996, Calculated:6.09996, Diff: 1%
* PhysX Time: 7.11661, Actual Time:7.11753, Diff: 1.00013%
Actual: 7.11661, Calculated:7.11661, Diff: 1%
* PhysX Time: 8.13326, Actual Time:8.13562, Diff: 1.00029%
Actual: 8.13326, Calculated:8.13326, Diff: 1%
* PhysX Time: 9.14991, Actual Time:9.1594, Diff: 1.00104%
Actual: 9.14991, Calculated:9.14991, Diff: 1%


As you can see the differences are about ~1%, which is more than acceptable.

The next test, I introduce a delay of 100 milliseconds in the loop, and run the test again.

* PhysX Time: 1.1, Actual Time:1.20003, Diff: 1.09094%
Actual: 1.2, Calculated:1.1, Diff: 1.09091%
* PhysX Time: 2.19999, Actual Time:2.30004, Diff: 1.04548%
Actual: 2.29999, Calculated:2.19999, Diff: 1.04546%
* PhysX Time: 3.29999, Actual Time:3.40004, Diff: 1.03032%
Actual: 3.39999, Calculated:3.29999, Diff: 1.03031%
* PhysX Time: 4.39998, Actual Time:4.50005, Diff: 1.02274%
Actual: 4.49999, Calculated:4.39998, Diff: 1.02273%
* PhysX Time: 5.49998, Actual Time:5.60013, Diff: 1.01821%
Actual: 5.59997, Calculated:5.49998, Diff: 1.01818%
* PhysX Time: 6.59997, Actual Time:6.70014, Diff: 1.01518%
Actual: 6.69995, Calculated:6.59997, Diff: 1.01515%
* PhysX Time: 7.69996, Actual Time:7.80015, Diff: 1.01301%
Actual: 7.79993, Calculated:7.69996, Diff: 1.01298%
* PhysX Time: 8.79996, Actual Time:8.90015, Diff: 1.01139%
Actual: 8.89992, Calculated:8.79996, Diff: 1.01136%
* PhysX Time: 9.89995, Actual Time:10.0002, Diff: 1.01012%
Actual: 9.9999, Calculated:9.89995, Diff: 1.0101%


Again not so bad, 100ms is an entirety for a processor and the graphics drawing will be done by then. So this is a good real-world example.

Let's repeat the test, with a significant delay; 500 milliseconds - or half a second. Some serious lag.

* PhysX Time: 1.49999, Actual Time:2.00001, Diff: 1.33334%
Actual: 0.533331, Calculated:1.49999, Diff: 0.355556%
* PhysX Time: 2.99999, Actual Time:3.50001, Diff: 1.16667%
Actual: 0.933329, Calculated:2.99999, Diff: 0.311111%
* PhysX Time: 4.49998, Actual Time:5.00001, Diff: 1.11112%
Actual: 1.33333, Calculated:4.49998, Diff: 0.296297%
* PhysX Time: 5.99998, Actual Time:6.50001, Diff: 1.08334%
Actual: 1.73333, Calculated:5.99998, Diff: 0.288889%
* PhysX Time: 7.49997, Actual Time:8.00002, Diff: 1.06667%
Actual: 2.13333, Calculated:7.49997, Diff: 0.284445%
* PhysX Time: 8.99996, Actual Time:9.50002, Diff: 1.05556%
Actual: 2.53333, Calculated:8.99996, Diff: 0.281482%
* PhysX Time: 10.5, Actual Time:11, Diff: 1.04762%
Actual: 2.93333, Calculated:10.5, Diff: 0.279366%


Wow. PhysX has really slowed down. At the end of the test, the box should be at ~10m, but it has only travelled 3m

The reason why it's like this, is I'm not completely sure. It's related to the internal accumulator code, that stacks up any remaining time for the next timestep, What it should be doing is simulating extra time whenever possible to make up the delay. Which it doesn't look like it's doing.

So my advice for now is to;

- The deltaTime you give to PhysX probably isn't the one it's going to use, it'll calculate it's own based off that. I have a pretty good algorithm written now, that can guess what the PhysX deltaTime will be. When Detritus is released, I advice you use the new TimeStep classes.
- Don't use deltaTime to change velocity - Velocity doesn't work like that. Naughty, Spacegaier .
- Make your application simulate as fast as possible, turn off VSync, or if you want a fixed 60Hz graphics, have a second timer for NxOgre to go at full blast or more than 60Hz.


My source code for the test can be found here (Although it may change in the future):

http://github.com/betajaen/cake/blob/de ... akeCLI.cpp

danoli3

16-10-2009 16:23:53

Thanks betajaen.

Wow I didn't realise it was a major problem like that! I just thought it was our issue!
LOl!

Alright bak to no deltaTime changing the setVelocity.

For now I might try fixing the timestep using this kind of idea:
http://gafferongames.com/game-physics/f ... -timestep/
http://www.gamedev.net/community/forums ... 1&#2946301

Not sure if that will be a work around that will work... I'll try it ;)

betajaen

16-10-2009 16:29:32

We used to do that in NxOgre (for quite a while actually), when I decided to just trust PhysX and pass the raw time value directly, rather than several times in semi-fixed smaller increments like the article is suggesting.

In Detritus, it does a bit of both. Since PhysX doesn't return what deltaTime it used, I use that gaffer tutorial to get a pretty good approximation of what it is. That way, the user can use the PhysX timestep in their force calculations for the next frame.

TBH; I wish Ageia wrote some better documentation on this subject, and provided a insight on how their accumulator works.

al2950

17-10-2009 15:12:01

@danoli3

Just been speaking to betajaen in this thread;
viewtopic.php?f=6&t=11312

It seems like the current Master GIT branch is much more susceptible to this problem than betajaen Detritus branch. ie if you have a frame rate of 30fps your physics will run at half the speed of realtime

danoli3

19-10-2009 06:35:12

@danoli3

Just been speaking to betajaen in this thread;
viewtopic.php?f=6&t=11312

It seems like the current Master GIT branch is much more susceptible to this problem than betajaen Detritus branch. ie if you have a frame rate of 30fps your physics will run at half the speed of realtime


Thanks great problem solving ;D!

Donated $5 to betajaen for support

betajaen

19-10-2009 10:16:11

That was really unnecessary but thanks, it'll go towards next months slicehost payment.