x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Fixed timestep update for physics / damping code?

Hello.

I have a Component in which I need to run some physics related code. Specifically, linear damping but only on the X and Y axis and not Z.

I currently run the following code in the TickComponent():

     UPrimitiveComponent* component = PawnOwner->GetRootPrimitiveComponent();
     FVector initVel = component->GetPhysicsLinearVelocity();
     FVector hInitVel = FVector(initVel.X, initVel.Y, 0);
     component->SetPhysicsLinearVelocity(initVel - hInitVel * damping * DeltaTime);

But it is not framerate independent.

Is there a way I can run the above code at a fixed timestep?

Thanks.

Product Version: Not Selected
Tags:
more ▼

asked Jul 05 '14 at 02:59 AM in C++ Programming

avatar image

Acren
460 46 50 70

avatar image Acren Jul 06 '14 at 03:25 AM

I think the issue is that, while you can scale the velocity reduction by DeltaTime, the distance moved won't actually be the same due to physics being stepped at different intervals to rendered frames. (Or at more iterations)

alt text

So, for a classic Velocity / Time graph where the area under the graph (roughly) represents the distance moved, you can see that while the velocities of two different framerates will always be similar, the distance moved won't be.

I need a way for the distance moved to be the same.

I think I need either a way to tick at a small fixed timestep, or somewhere I can run code after each physics step iteration.

veltime.png (7.0 kB)
(comments are locked)
10|2000 characters needed characters left
Viewable by all users

4 answers: sort voted first

I think to get a fixed timestep, you would just wrap your damping code in a loop and use a static variable to track the elapsed time. It would look something like this (desiredTimeStep would be whatever fixed duration you want):

 static float elapsedTime = 0.0f;
 
 elapsedTime += DeltaTime;
 while (elapsedTime >= desiredTimeStep)
 {
   elapsedTime -= desiredTimeStep;
   FVector initVel = component->GetPhysicsLinearVelocity();
   FVector hInitVel = FVector(initVel.X, initVel.Y, 0);
   component->SetPhysicsLinearVelocity(initVel - hInitVel * damping * desiredTimeStep);
 }
more ▼

answered Jul 05 '14 at 04:54 PM

avatar image

affliction50
81 3 6 7

avatar image affliction50 Jul 05 '14 at 05:26 PM

Looking at your code again, I guess I probably wouldn't use a static variable like in the example code I have. Maybe make that a member variable.

If you know for sure that you're only going to have one object in the game running that code, the static variable will work fine. If you're going to have multiple objects, the static variable is persistent across all of them and you'd get some undesired behavior as a result.

avatar image Acren Jul 06 '14 at 03:20 AM

Yeah, I would use a member for that.

Wouldn't this solution only have an effect if the desiredTimeStep is a significantly greater than the average DeltaTime, through reducing the amount of iterations (and accuracy)?

avatar image affliction50 Jul 06 '14 at 07:33 AM

It shouldn't unless I wrote something out incorrectly. It just forces the damping part of your update to use the exact same step value each time. If desiredTimeStep is significantly smaller than the average DeltaTime, you'd be running that while loop a bunch of times each frame with smaller delta values.

Quick examples with completely arbitrary numbers:

Let's say your average DeltaTime is 10 and your desiredTimeStep is 5. Each frame you'd dampen your velocity 2 times using your desired "5" for each iteration. If you have some really fast frames back to back and the DeltaTimes are 1 each, you don't dampen at all until it accumulates to 5, and then you use 5 again the next frame. It also maintains its consistency by carrying over the leftover time so you aren't dropping anything. If you get a frame with a DeltaTime of 12, you'd carry 2 of those over and they'd get rolled into the next frame's time.

Each dampening will be completely consistent whether your actual framerate is faster or slower than "desired".

EDIT: I changed the code I posted above. I used the wrong variable for the actual damping. It was supposed to be desiredTimeStep and not elapsedTime. That would have been completely wrong. Fixed now though.

avatar image Acren Jul 06 '14 at 08:52 AM

Thanks, but unfortunately this doesn't really do anything if the desiredTimeStep < deltaTime apart from forcing the velocity to only update in multiples of desiredTimeStep. It still only updates at variable deltaTime intervals, with engine physics still using the velocity in between those updates, thus giving different results for different deltaTime values.

I posted an image as a comment to my OP which illustrates what I think the problem is, I hope.

avatar image affliction50 Jul 06 '14 at 10:21 AM

shrug That's what a fixed time step is. The question said you wanted a fixed time step for linear damping. If you want it to do that for the velocity as well, then turn off physics and handle velocity in the same loop.

Here's an article for more information: http://gafferongames.com/game-physics/fix-your-timestep/

avatar image Acren Jul 06 '14 at 11:15 AM

Well, damping is just altering velocity...

Sadly I can't just disable physics and handle it myself as I need the actor to respond physically to collisions with other actors and also to AddForce and AddImpulse and such. (If I could, life would be MUCH easier for me...)

I have indeed seen Fix Your Timestep and know about the built in substepping, and yes they are very relevant :)

Looking at the substepping article again, I suppose what I'm looking for is a way to handle custom damping (and/or any other physics related code) in the physics thread, as if possible, would be a way to handle it independently of framerate, and without having to disable the engine physics and write my own.

Although at the end of the day here, all I'm really trying to do is apply linear damping on 2 axis rather than 3. It doesn't seem like it would be impossible to do with the engine physics, but it may well be.

Something like a PostPhysicsStep(float deltaTime) would be amazing...

avatar image affliction50 Jul 06 '14 at 08:08 PM

Does the physics system already do linear damping? I haven't done anything with physics in UE4, but it seems like it would. If it does, why not just store the z-value for the velocity each frame. The next frame, just set the z-velocity to the previous frame's value. You'd be storing a single float and doing an assignment each frame instead of the more involved calculations.

avatar image Acren Jul 06 '14 at 11:11 PM

Indeed it does, and it's a good idea however locking the z-velocity through the physics calculations I think would also disable gravity, impulse from collisions, etc on that axis...

avatar image affliction50 Jul 06 '14 at 10:40 AM

And just to clarify, the step size makes a difference. If you're desired time lapse is based on 60 frames per second and your game is running at 30 frames per second, it makes a pretty big difference. The velocity after only 2 seconds in that case can be off by 1.5 - 2%. Obviously with longer periods of time, that difference grows.

avatar image affliction50 Jul 06 '14 at 10:55 AM

And the Unreal Engine 4 page talking about how they do fixed time steps: https://www.unrealengine.com/blog/physics-sub-stepping

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Let’s assume the following code gives the desired result with a fixed 1/60s timestep:

 component->SetPhysicsLinearVelocity(initVel - hInitVel * damping * DeltaTime);

This effectively multiplies the X and Y components each frame by:

 (1 - damping / 60)

After N 60fps steps, the X and Y components have been multiplied by:

 (1 - damping / 60) ^ N

So what if DeltaTime is not constant? No problem, you can treat DeltaTime as a non-integer number of 60fps steps:

 (1 - damping / 60) ^ (DeltaTime * 60)

This gives you the following, framerate-independent code:

 float const TimedDamping = 1.f - FMath::Pow(1.f - damping / 60, DeltaTime * 60);
 component->SetPhysicsLinearVelocity(initVel - hInitVel * TimedDamping);
more ▼

answered May 02 '15 at 11:02 AM

avatar image

SamHocevar
41 2 4 5

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

I think somethings wrong with your calculations, you scaling whole result where what you should just scale the delta values, so try this

 initVel - ((hInitVel * damping) * DeltaTime)
more ▼

answered Jul 05 '14 at 01:11 PM

avatar image

Shadowriver
35.8k 927 169 1105

avatar image affliction50 Jul 05 '14 at 02:31 PM

It doesn't look like those parentheses are changing the order of operations at all. Multiplication is commutative, so order doesn't matter. And the multiplication happens before subtraction whether you have parentheses or not. Unless I'm missing something, wouldn't both of those give the same results?

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Unreal Engine does not use fixed time steps, and cannot get deterministic behavior using the default physics integration. The best you can do is enable sub-stepping, setting some small sub-step size, and hope for the best. I have a simulation that definitely "hitches" when something takes away the machine for a few milliseconds :-(

To provide consistent (but still not 100% deterministic) behavior with variable time step, you'd have to use a Runge-Kutta-4 integrator, which is way too expensive (calculating all those derivatives) and also use swept collision detection across the board.

more ▼

answered Jul 07 '14 at 12:02 AM

avatar image

jwatte
1.3k 48 41 88

avatar image Acren Jul 09 '14 at 09:07 AM

Yeah, I'd not expect it to be completely deterministic, but I'm getting an almost consistent 5% offset in my above situation, which seems pretty huge.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question