Problem with velocity and framerate

Hansel

02-07-2006 14:15:32

Hi :mrgreen:

How can I update Newton with evt.timeSinceLastFrame? In Ogre, to move a simple object through XYZ axes I used to do

objet_node->setPosition(objet_node->getPosition()+Vector3(x,y,z)*evt.timeSinceLastFrame)


But now, with Newton, I want to do the same thing:


// the objet is stopped

objet_body->setVelocity(Vector3(x,y,z)*evt.timeSinceLastFrame))


Bue it doesn't work as I want, because if the framerate is, for example, 20 fps, the objet speed is 50, but if the framerate is 50 then the speed increases to 110+ (the speed and the gravity).

The velocity the object takes depends on framerate. I've seen something about mWorld->update() but I don't know if that is what I need. How can I do to mantain the velocity of my character constant regardless of framerate?


Thanks ;)

walaber

03-07-2006 02:17:47

remove the "*evt.timeSinceLastFrame" from the equation.

Hansel

03-07-2006 15:10:10

I've already done that but the problem is still here :(

For example, the code I use for jumping:

if ((mInputDevice->isKeyDown(KC_RSHIFT)) && (mTimeUntilNextToggle <= 0))
{
ash->get_body()->setVelocity(ash->get_body()->getVelocity()*Vector3(1,0,1)+Vector3(0,300,0));
mTimeUntilNextToggle = 0.8;
}



For example, Ash jumps in camera solid mode very slowly compared to camera wireframe mode. What's wrong? :(

walaber

03-07-2006 20:37:13

how are you updating the Newton world? please show the code you use...

Hansel

03-07-2006 20:49:31

bool frameStarted(const FrameEvent& evt)
{


Real speed= evt.timeSinceLastFrame;
world->update( evt.timeSinceLastFrame);






// CONTROLS







bool result = Ash_FrameListener::frameStarted(evt);

return result;
}

walaber

04-07-2006 08:25:34

OK that's why. if your framerate drops below 60fps, Newton will update as if you are still going along at 60fps.

in other words, if you pass a number larger than 1/60, Newton will update with a value of 1/60.

this means that if for example in debug mode the FPS drop to like 20, everything will appear to be in slow motion.

you can implement a "time slicing" method to prevent this, have a look at OgreNewt::BasicFrameListener() for an example of how it works.

Hansel

04-07-2006 16:06:25

I have tried this:

bool frameStarted(const FrameEvent& evt)
{


Real speed = evt.timeSinceLastFrame;


desired_framerate = 1/evt.timeSinceLastFrame;;

m_update = (Ogre::Real)(1.0f / (Ogre::Real)desired_framerate);
m_elapsed = 0.0f;


m_elapsed += evt.timeSinceLastFrame;


int count = 0;

if ((m_elapsed > m_update) && (m_elapsed < (1.0f)) )
{
while (m_elapsed > m_update)
{
world->update( m_update );
m_elapsed -= m_update;
count++;
}
}
else
{
if (m_elapsed < (m_update))
{
// not enough time has passed this loop, so ignore for now.
}
else
{
world->update( m_elapsed );
count++;
}
}

bool result = Ash_FrameListener::frameStarted(evt);

return result;
}




But nothing changes. What's the matter? :(


I think world->update() doesn't have any effect when I apply it.

abecam

04-07-2006 16:26:12

Have you tried tou add m_elapsed = 0.0f; // reset the elapsed time so we don't become "eternally behind".


This line is a magic "don't stay behind" statement :)

Also, I do not set m_elapsed = 0 at each frame, instead I only do:

m_elapsed += evt.timeSinceLastFrame;

And then:


if ((m_elapsed > m_update) && (m_elapsed < (1.0f)) )
{
while (m_elapsed > m_update)
{
m_World->update( m_update );
m_elapsed -= m_update;
countUpdt++;
}
}
else
{
if (m_elapsed < (m_update))
{
// not enough time has passed this loop, so ignore for now.
}
else
{
m_World->update( m_elapsed );
countUpdt++;
m_elapsed = 0.0f; // reset the elapsed time so we don't become "eternally behind".
}
}


Not sure I help you (but it how I do it and it works (simple copy and past from BasicListener really :) ) )

Hansel

04-07-2006 16:51:05

I changed the code to this one:


bool frameStarted(const FrameEvent& evt)
{


Real speed= evt.timeSinceLastFrame;


desired_framerate = 1/evt.timeSinceLastFrame;;

m_update = (Ogre::Real)(1.0f / (Ogre::Real)desired_framerate);
m_elapsed += evt.timeSinceLastFrame;


int count = 0;

if ((m_elapsed > m_update) && (m_elapsed < (1.0f)) )
{
while (m_elapsed > m_update)
{
world->update( m_update );
m_elapsed -= m_update;
count++;
}
}
else
{
if (m_elapsed < (m_update))
{
// not enough time has passed this loop, so ignore for now.
}
else
{
world->update( m_elapsed );
count++;
m_elapsed = 0.0f; // reset the elapsed time so we don't become "eternally behind".
}
}
bool result = Ash_FrameListener::frameStarted(evt);

return result;
}




But everything remains the same.

I didn't realize before but there is one thing that seems to be very strange. Framerate variations affect to Ash when he jumps but they don't affect to him when he is just moving in any direction. It looks like the gravity is the only affected here, at least in a scale that I can appreciate. How can it be possible?

abecam

04-07-2006 19:27:33

I am not sure also of these lines:
Real speed= evt.timeSinceLastFrame;


desired_framerate = 1/evt.timeSinceLastFrame;;

m_update = (Ogre::Real)(1.0f / (Ogre::Real)desired_framerate);
m_elapsed += evt.timeSinceLastFrame;


I suppose you use speed later, but you adapt the desired_framerate to the time elapsed since the last frame?
I have the two last lines in my listener constructor only. The desired framerate is the time you want, not the time you have: then the if-else try to follow that, wait if too fast, break ( =0 ) if really too slow (as it is a simulation, if you start to be late, you might accumulate that-> if you use 0.01 sec step for each update in Newton, but your framerate is 0.02, you need to ask Newton for 0.02 sec of update next time. The thing is that there is a chance that the Newton update takes more than 0.01 sec, but also that it needs more time to calculate for 0.02 sec than for 0.01 sec, so the next calculation will take 0.03 sec, and etc. So it is quite crucial that you use a "keep the rythm- break if needed" part. )
Then, this was the long-unclear-useless post :) :)

Hansel

05-07-2006 10:55:24

I think I solved. I had 2 framelisteners added to the root, one to actualice the scene (in graphic terms) and the other to actualice newton world. But I was updating the world in the scene framelistener at the same time I was updating the world every frame with the other framelistener. I have just realized that the mistake can be there.

I go to probe it :D

Hansel

05-07-2006 10:59:27

Yes, it works fine now, thanks for all :D