Looking into fix my time step

Started by
9 comments, last by ryan20fun 8 years, 8 months ago

Hello all.

I was looking at changing my game loop. But I have some questions,

(Q1)Like why do they have the accumulator in a while loop

(Q2)does that loop do the update or do you wait until the loop ends.

(Q3) What is t with long waits this just counts up and up each time you do a pass.

(Q4)lloks like it only works when frame time is small

(Q5)My test code maybe wrong.

(Q6)How do you proccess 8000 objects in a small amount of time. That will not make the time delay blow up.

(Q7)Its just me I have it all wrong Hoping.

This does not look wright if I add a 1 second delay at the end of the loop the while accumulator will spin for like depending on the wait can spin

upto 615 steps in the loop and more, this seams wrong why waste that loop.

I noticed in the article they put a if(frameTime > 0.25) frameTime = 0.25; whats the point of calling thy timer. In my current setup I just hard coded a 0.20 as my frame delta and vsync thats why I want to change to this, But I'm missing something.

this is the article

May be I have it wrong here is my test app.

.


#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include<Windows.h>
#include <string>
#include <iostream>
#include <sstream>
#include<GameTimer.h>



int main(int argc, char* argv[])
{
														
       // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
	
	
	
	std::cout << "Press Q to quit" << std::endl;

	__int64 ctr1 = 0, freq = 0;
	__int64 currentTime = 0;//hires_time_in_seconds();
	int acc = 0, i = 0;

	//get the time
	if(QueryPerformanceCounter((LARGE_INTEGER *)&currentTime)== FALSE)
	{
		std::cout << "Timer error" << std::endl;
	}
	
	QueryPerformanceFrequency((LARGE_INTEGER *)&freq);


	double t = 0.0;
	const double dt = 0.01;


	double accumulator = 0.0;


	size_t listsize = 0;
	std::string line; //stores the most recent line of input 
	while(std::getline(std::cin, line)) //read entire lines at a time 
	{ 
		//deal with the contents of `line`
		if(line.compare("q") == 0 || line.compare("Q") == 0)
			break;

	

		if(QueryPerformanceCounter((LARGE_INTEGER *)&ctr1)== FALSE)
		{
			std::cout << "Timer error" << std::endl;
		}
		__int64 newTime =  ctr1;//hires_time_in_seconds();
		double frameTime = ((newTime - currentTime) *1.0 / freq);//convert to seconds
		

		//if(frameTime > 0.25 )
		//	frameTime = 0.25;

		std::cout <<  "CurrentTime: = " << currentTime << std::endl;
		std::cout <<  "NewTime: = " << newTime << std::endl;
		std::cout <<  "Current Frame Time: = " << frameTime << std::endl;
		currentTime = newTime;

		accumulator += frameTime;

		int count = 0;
		while( accumulator >= dt )
		{
			count++;
			//Sleep(200);

			std::cout << "accumulator::" << accumulator << " Steps :" << count << std::endl;
			std::cout <<  "Current Frame Time: = " << frameTime << std::endl;
			//integrate( state, t, dt );
			accumulator -= dt;
			t += dt;
			std::cout <<  "Time t = " << t << std::endl;
		}

		Sleep(1000);


	}//end while running

	return 0;
}

.

Just found this post Now if I set a DT of 1/120 and a sleep(1000) there is over 23000 steps lol say good by to your game loop hehehe. 1/30 seams to work a lot better

but what happens if your render takes a second say good bye again.

Can't you just set a timer to fire every 0.03 seconds and update.

I think I may have to move this into my real app and see what happens.

Advertisement

As a start: next time, put the link to article on top. It is necessary context.

(Q1)Like why do they have the accumulator in a while loop?

Most likely for easiness of explanation (?). I don't see much of a point either.

(Q2)does that loop do the update or do you wait until the loop ends.

It does a thing called integrate and a thing called render... I assume you don't crunch English well.

In the given context, to integrate means "run the computations and produce new values [from the RK integrator]".

To render is to draw.

(Q3) What is t with long waits this just counts up and up each time you do a pass.

"Yes"

Seriously, I cannot make any sense of what you're really asking there. Anyway, t is the sum of tick time which in theory is the time passed since t0.

(Q4)lloks like it only works when frame time is small

You are correct, sort of. If physics tick time is too big then you're screwed forever. This problem has no solution and even Bullet (physics library) warns about that case. Decoupling rendering and physics makes the whole problem way less concerning.

(Q6)How do you proccess 8000 objects in a small amount of time. That will not make the time delay blow up.

8k (moving!) objects are pro stuff. Let me put that easily for you: use a physics library.

Even for them, 8k (moving) objects are quite a stretch. In general, when you start having thousands objects you can try move those to GPU.

You might be suprised to know 8k (mostly static) objects are a breeze. The key is fast reject of objects surely not interacting (broadphase) and then further refinement (narrowphase). Physics libraries get much smarter.

This does not look wright if I add a 1 second delay at the end of the loop the while accumulator will spin for like depending on the wait can spin

upto 615 steps in the loop and more, this seams wrong why waste that loop.

It is not 'wasted'. It is the correct behavior. To properly integrate arbitrary functions, your dt must be "approaching zero" (talking mathematical here) so if your frame time is too big you go over and over and over until you iterated the state enough.

In other words, the state can only evolve in small steps.

I noticed in the article they put a if(frameTime > 0.25) frameTime = 0.25; whats the point of calling thy timer. In my current setup I just hard coded a 0.20 as my frame delta and vsync thats why I want to change to this, But I'm missing something.

What you miss is that vsync is unreliable (as a start) as drivers can force it off or on and you would be screwed. Plus, there's no current guarantee your software will be faster than vsync so you actually do your computation in vsync multiples. Last and perhaps more important, the whole point of the article is that you have a flexible tick which is predictable, not an hardwired one.

Or, condensing to core: fail.

Just found this post Now if I set a DT of 1/120 and a sleep(1000) there is over 23000 steps lol say good by to your game loop hehehe. 1/30 seams to work a lot better

Once again, you failed to grasp the whole point of dt 1/120, the user specifically mentions it works in higher-precision simulation.

Can't you just set a timer to fire every 0.03 seconds and update.

And then, when your update takes 0.035 seconds your timed updates will just happily enqueue forever and after a while you will have a problem anyway. That's of course assuming they don't stump on each other with no remorse.

Previously "Krohm"

Thanks.

And whats with this bit.

if(frameTime > 0.25 ) frameTime = 0.25; Does it just stop spiral of death.

Ok t is the accumulated running time since started.

and with my up date, to compare is done by looping all objects with DT of 0.20f each frame and I was wondering how to intergrate the fix my time step.

UpDate(0.20f);

render();

present();

And I know what the render is I put the Sleep there to act as a long render.

obviously I used large sleep values so I coud see what all the post are saying about jitter. and also why they where using max loop flag to quit.

but the jittercould be many steps in the loop or is that spiral of death.

Lspiro has it 1/30 for DT is all you need. I just tryed 1/120 to see what the other guy was talking about, Which gave me the spiral of 33000 steps of death.

I'm going to try the above in me real game and see what happens the update is decoupled from my render. As it stands the current setup I have on a Mplay. one pc's object arrives like 15 frames before the slower pc.'s object does. This is only for object motion. AT the moment my update function runs as fast as the render

as its like this

UpDate(0.20f);

render();

present();

Like Krohm said.

What you miss is that vsync is unreliable (as a start) as drivers can force it off or on and you would be screwed. Plus, there's no current guarantee your

software will be faster than vsync so you actually do your computation in vsync multiples. The reason I'm asking.

(Q6)How do you proccess 8000 objects in a small amount of time. That will not make the time delay blow up.

8k (moving!) objects are pro stuff. Let me put that easily for you: use a physics library.
Even for them, 8k (moving) objects are quite a stretch. In general, when you start having thousands objects you can try move those to GPU.
I don't know how to answer Q6 other than "write good code". The most recent game I worked on uses CPU skinned animation - worst case is 30 humanoids on screen with 10k vertices each. That's 300000 'objects' (vertices) that need animating. Even that was only ~10MB RAM read bandwidth and ~5MB VRAM write bandwidth.
You write the code in whatever way it takes, such that it finishes in a few milliseconds... i.e. efficiently :P
Basically: find out why your code/algorithms are slow, then optimize them.

while(std::getline(std::cin, line)) //read entire lines at a time 	{
Wait... Your game loop executes once every time that you press the enter key?
This kind of game loop is designed for real-time games -- games where the main loop takes less than ~50ms per frame.
It's not going to work well for a non-realtime loop like in your code!

And whats with this bit.
if(frameTime > 0.25 ) frameTime = 0.25; Does it just stop spiral of death.

Yes. That bit forces the game to explicitly desync with real world clocks and go into slow motion, only IF the user's PC is so old that the game has dropped below 4 frames per second.
If the game is running faster than 4 frames per second, that code does nothing.

You can tweak that number (1/4=0.25) to choose what your minimum FPS is / at what point you enable slow-mo to avoid the spiral.

You should always test your code on your minimum-spec PC, and if the framerate is too slow, fix your code to be more efficient (or raise your game's minimum hardware requirements).

Hi!

(Q1)Like why do they have the accumulator in a while loop

Looking at your code:


integrate( state, t, dt );

It looks like you are moving your simulation forward in fixed delta times. The accumulator acts as a way of collecting time up until the point where you start the simulation. At that point you want to either catch up or don't do your integration. So for example if you wanted to do your integration 30 times a second and your rendering 60 times a second the first time you got to that while loop the accumulator would have the value 1/60. The second time it would have the value 1/30, so do your integration step once. On the other hand, if you were on a slower machine the first time you got to that while loop you could have a value of 1/15 in the accumulator(rendering at 15fps), in this case you would need to to do two steps of simulation to "catch up" to your rendering. It just looks like a way to keep your simulations consistent.

Hey all.

I put the loop in the game. And gained 9 milliseconds per frame as a byproduct cool this updates the updates less then I was when running free.

But the units move so slow its like half a pixel per hour.

I set the if(frameTime > 0.35) and the time delta is 0.0299999, so it never makes it to the if statement thats all working.

thats just wrong there frame time is at 0.35;

I update my objects like this(see code)and I played with the values but the only way I could in crease the units travel speed was by reducing the mass of the unit before I had it set to

Unit mass = 100.0;//kgs had to move it down to 1.0; but even thats not that fast at all.

If I remove the timedelta from update velocity it moves faster. have I got it wrong for this fix your time step loop.

.


///over ride the motion data
	RTSComponentMotion.m_dMaxSpeed		= 2600.5f;
	RTSComponentMotion.m_dMass			= 100.0f;//kg
	RTSComponentMotion.m_dMaxTurnRate		= 1;
	RTSComponentMotion.m_dMaxForce		= 1000.0f;

		//if we have a destination
		if(HasDestination && GetDestination(&destination))
		{
			//we are walking set the walking animation
			CurrentUnitAnimationOrder.SetCurrentOrder(CurrentUnitAnimationOrder.RUN);

			//does object to object
			m_vSteeringForce = m_SteeringBehaviors->Calculate();
		
			//Acceleration = Force/Mass
			D3DXVECTOR3 acceleration = m_vSteeringForce/ ComponentMotion->m_dMass;

			//update velocity
			ComponentMotion->m_vVelocity += acceleration  * timedelta; 

			//make sure vehicle does not exceed maximum velocity
			ComponentMotion->m_vVelocity = Truncate(ComponentMotion->m_vVelocity, ComponentMotion->m_dMaxSpeed);
			
			//update the position
			ComponentMotion->m_vPos += ComponentMotion->m_vVelocity * timedelta;

And one more thing where and how to add some extra speed so the unit could run or walk.

Time delta is usually a small number, anywhere from 1/30 to 1/60, for example. So if we look at it with random numbers and assume the simple case of just position and velocity:

position = <5, 5>

velocity = <3, 0>

deltaTime = 1/30

And your options are to use delta time or not:

w/delta time:

position = position + velocity * deltaTime

position = <5, 5> + <3, 0> * 1/30

position = <5.1, 5>

without delta time:

position = position + velocity

position = <5, 5> + <3, 0>

position = <8, 5>

So assuming this delta time 1/30(30 fps) the object being integrated/simulated without delta time would appear to move faster.

So if you weren't using a delta time before you have to rethink your scalar values and what they mean for objects in motion before. As in, you need to raise your velocity, lower your mass or increase the acceleration.

Sorry all I just can't get my units to travel at speed.

if I use timedelta to update the velocity and also on the position, no matter what extra speed value the units travel is slow.

this setup.

//update velocity

ComponentMotion->m_vVelocity +=( acceleration) * timedelta; I tryed adding extra speed here (acceleration * 200) * timedelta

I also tryed here adding extra to the position

ComponentMotion->m_vPos += (ComponentMotion->m_vVelocity * 550) * timedelta;

But the only way I managed to increase the speed is if I drop the timedelta from the position like so.

//update velocity

ComponentMotion->m_vVelocity +=( acceleration * 200) * timedelta; //fast unit and smooth motion

removed the time delta

ComponentMotion->m_vPos += (ComponentMotion->m_vVelocity);// * timedelta; no timedelta

the other setup that worked was using both timedeltas .

What part is wrong, Does both time deltas need to be there and whats happening to it when its not there.

You've kinda awnsered yourself there :)

Just use the delta time on all velocity/acceleration/Etc calculations, And then add that to the position and then clear the velocity for the next frame.

Movement: Think of the values as that many units per second, So a velocity of <5,5> means 5 units/pixels/meters per second.

HTH

Never say Never, Because Never comes too soon. - ryan20fun

Disclaimer: Each post of mine is intended as an attempt of helping and/or bringing some meaningfull insight to the topic at hand. Due to my nature, my good intentions will not always be plainly visible. I apologise in advance and assure you I mean no harm and do not intend to insult anyone.

Hey Thanks All.smile.png wub.png hehe.

Ryan20fun how did you know that the velocity was not being reset. Good heads up thanks.

I sort of was on that line of thinking but I reset the velocity in the onDestination call not per steps.

I have some fine tuning to do on the values, But all is working fine.

And it does perfect synchronization, Even with 1 PC renders at 13 millisecond and the other runs at 34 milliseconds per frame.

Again wow. I put this off for like a couple of years. My next gtame I'll do this from now on.

This topic is closed to new replies.

Advertisement