Networked Physics with PhysX

There is one additional thing if you get different sim depending on the framerate. I made this change too: https://github.com/0lento/UnrealEngine/blob/141c09501a0628b8ed7a88145e22c9072498ce19/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysSubstepTasks.cpp#L415 (I’m just bypassing the last substep check)
It wouldn’t change the amount of substeps or anything huge like that, it just guarantees that last substep will have same deltatime as all previous. The different is really just some floating point inaccuracy due to the math they do there, it wouldn’t change the deltatime that much but enough that simulation will look slightly different depending on the framerate.

It’s different alright, you don’t have to add anything to the target map for those 4.15 delegates to work. I’ve used the custom physics delegate in past but it’s been a long time since I used those with fixed timesteps.

Yeah so I ended up just pulling that code from 4.15, so thanks for the heads up. Right now I have some serious jitter on my faster vehicle so I’m guessing that’s related to frame aliasing and I need to implement the mesh interp you showed off in your gif.

Most of my lerp code is here .

You can freely use this fork: https://github.com/0lento/UnrealEngine/tree/4.15-FixedTimestep for whatever you want but I give no support for it :). Basically it does:

a) fixed timestepping (optional/does not remove option to use regular substepping, also every setting exposed in project setting)
b) allow lerping for interpolated bodies by the specified project setting which has options for Always/Disabled/By Component (there’s a component specific setting in PrimitiveComponent so you can set it by component in editor/code if you want only lerp “hero” objects)
c) allow moving interpolated rigidbody into lerped position for Tick only (so your linetraces etc queries during Tick match the visuals in case you need to do that for regular gameplay reasons), this will then move the RB back into last simulated position after Tick so you are not making compromises for the sim.
d) allow enabling enhanced determinism mode for physx 3.4
e) have flexible settings for starvation prevention (soft and hard limit and option to select if you fall back to regular substeps after that or just clamp the substep amount)
f) expose collision event dispatching so you can call it yourself from your project and get collision events on substeps (engine only does this for next tick by design so you have to wait after all substeps are done to get any hit / overlap events)

I’ve not promoted the fork mainly because it’s largely untested and there are things that would need some additional thought. Also worth mentioning I only store old and last physics transform after all physics are done, so basically I can only capture the physics state after previous full sim and current sim, so latest physics transform is always truly latest but old is actually from previous Tick cycle and not the substeps physics state before the latest one.

Thank you for the fork. I investigated it a bit but went ahead and tried my own solution. I’m using extrapolation instead of interpolation. This is a first pass. It’s late and haven’t tested it a whole lot. Just at 10hz, 20hz, 30hz, 60hz physics and all sorts of framerates it seems good but haven’t tested it in a live environment or a more dynamic environment. Its really late and so this might look a bit trashy, but here it is:




void UVehicleMoveComponent::OnRegister()
{
	Super::OnRegister();

	OwningVehicle = Cast<AVehiclePawn>(GetOwner());
	UpdatedMesh = Cast<USkeletalMeshComponent>(UpdatedPrimitive);

	if (FPhysScene* PScene = GetWorld()->GetPhysicsScene())
	{
		PScene->OnPhysScenePreTick.AddUObject(this, &UVehicleMoveComponent::PhysScenePreTick);
		PScene->OnPhysSceneStep.AddUObject(this, &UVehicleMoveComponent::PhysSceneStep);
	}

	UActorComponent::CreatePhysicsDelegate.AddLambda([this](UActorComponent* Component)
	{
		if (Component == UpdatedMesh)
		{
			if (FBodyInstance* BI = UpdatedMesh->GetBodyInstance())
			{
				BI->OnCalculateCustomProjection.BindUObject(this, &UVehicleMoveComponent::CalculatePhysProjection);
			}
		}
	});

	UActorComponent::DestroyPhysicsDelegate.AddLambda([this](UActorComponent* Component)
	{
		if (Component == UpdatedMesh)
		{
			if (FBodyInstance* BI = UpdatedMesh->GetBodyInstance())
			{
				BI->OnCalculateCustomProjection.Unbind();
			}
		}
	});
}

void UVehicleMoveComponent::CalculatePhysProjection(const FBodyInstance* BodyInstance, FTransform& WorldTransform)
{
	if (FPhysScene* PScene = GetWorld()->GetPhysicsScene())
	{
		float DT = PScene->GetTimeSinceLastPhysStep(PST_Sync);
		UE_LOG(Midair, Warning, TEXT("CalculatePhysProjection with DT: %f"), DT);
		// can't assume locked?
		FVector AngularChangeThisFrame = FMath::DegreesToRadians(BodyInstance->GetUnrealWorldAngularVelocity()) * DT;
		FVector RotAxis = AngularChangeThisFrame.GetSafeNormal();
		float RotAngle = AngularChangeThisFrame.Size();
		FQuat ProjectedRotation = FQuat(RotAxis, RotAngle) * WorldTransform.GetRotation(); // https://answers.unrealengine.com/questions/132849/how-do-i-apply-an-angular-velocity-to-a-quaternion.html
		FVector ProjectedLocation = WorldTransform.GetTranslation() + BodyInstance->GetUnrealWorldVelocity() * DT;
		WorldTransform = FTransform(ProjectedRotation, ProjectedLocation);

		// @todo: was the tank turning slower at a lower framerate + lower physics tick rate?
	}
	
}


Yeah, it’s all about making a compromise somewhere. I mainly did the Fix Your Timestep! | Gaffer On Games implementation. Basically you could add one physics step and calculate physics bit into future with old input. It’s not directly extrapolation IMO but it would still mean that input will lag a bit. With my forks and that articles approach, you interpolate physics so it appears always one rendered frame late, so that’s not ideal either. Doing extrapolation by projecting the estimated position can then again have noticeable artifacts when things clip into geometry before next physics step have actually resolved the collision. Doing the interpolation/extrapolation outside of the engine core is a lot easier and I’d suggest that if you only need to lerp select rigidbodies, it makes everything so much simpler.

btw. there’s a small error on the fork which I’ve already corrected but haven’t pushed the changes yet. I’ll add interpolation for the other direction (when physics are faster than rendering) before I push it there. I feel that GafferOnGames article is bit incorrect on how they do the interpolation in such case. It would work right if you substepped additional step into future, because then you’d have alpha between last two physics steps and you could truly lerp between them to get it in sync. Now if you do it like he does in the article, your last two substeps would be both between current and previous tick and obviously lerping between them can’t be in sync for either Tick. This is why I didn’t save the physics body transforms on substeps on my implementation (besides that it’s a royal pita to do that at engine level due to the way the system is built).

Edit-> fix is in the repo now.

I’m trying to add networking to a physical box.

What I’m trying is to find a way of executes the physics simulation for only the cube actor with custom DeltaTime.

In this way in the server I’m able to move the cube by the same distance I’ve moved on client side, and correct the position it on client side when need.

Do you have chosen the fixed timestamp solution becouse you are sure that isn’t possible to simulate physics for only one actor?

If one wants to simulate just one physics rigidbody (or few), one could just use the new immediate mode in physx 3.4. UE 4.16 will have this also wrapped into engine plugin but they do not expose the immediate mode functions to us (but you could still duplicate the plugin and expose the needed parts yourself).

What immediate mode in physx does is that it allows you to simulate individial objects outside of physics scene which could be handy for networked physics too as you could resimulate things individually without moving them in the physics scene while resimulation happens.

This is a fantastic answer. I’m in 4.15 where there’s physx 3.4. There’s a way to expose that API?

Edit:
I’m also searching the function you said (Immediate mode) into the documentation of physx but with no success. If you had the link, can you give it to me please?

It’s possible to expose that API, in best case scenario you could use parts of the mentioned engine plugin in your own project using 4.15 (or it could fail miserably, I haven’t checked the dependencies). Immediate mode is already implemented on PhysX 3.4 that’s been used by UE 4.14+ but there could have been some bugfixes to physx since (PhysX 3.4.0 release was at GDC I think, we’ve been using beta/alpha in 4.14).

Anyway, the said plugin is here: https://github.com/EpicGames/UnrealEngine/tree/master/Engine/Plugins/Runtime/ImmediatePhysics. Do note that Epic treats immediate mode as feature to add additional physics to animated meshes but it’s use isn’t limited to it. Because they use it like that, they don’t expose the things that would be useful for people like us who’d like to get low level access but that should be easy enough to override if you modify the plugin to fit your own purposes (or someone makes PR that exposes the needed function, looks like the needed change could be one liner).

To your question about documentation, there’s no public API docs for PhysX 3.4 yet as far as I know. If you are a registered nvidia developer (doesn’t cost you anything), you can link your github account into Nvidia Gameworks repo and that gives you access to PhysX 3.4 SDK, including docs and sample code (which include sample of immediate mode too if you want to implement it yourself / check what Epic did differently on their plugin).

Btw, their API docs are mostly parsed from headers so you can examine the function descriptions here as well:
https://github.com/EpicGames/UnrealEngine/blob/4.15/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Include/PxImmediateMode.h

I think I am going crazy, this is going to be my third time writing the same thing again for client side prediction with rewind/replay just to find what I did wrong.

I’m struggling to get non-predicted simulation to look good. For some reason the SmoothCorrection code for character does not look very good for Vehicles. There’s a jitter in the replicated position I can’t explain. I dont know if it’s in my head or if something is truly different, but the fact that I get this jitter in a 0 ping situation in the editor is pretty baffling.

I also haven’t bothered with client side prediction yet because the simulation almost always diverges after very little little time. Without springs! I’m guessing enhanced determinism might fix this, but with a simple flying vehicle the problem seems a bit worse than what I would expect (fixed timestepping is on the client, matches the server’s tick rate).

Hi guys, has anyone achieved the ideal replication of the movement of a physical object?
Just after reading the article Gaffer “State Synchronization”, I made my replication, but I do not like jerking on clients when two physical objects interact.

I apologize for my bad English, this is Google-translator.

I call @[COLOR=#005590]0lento, has something to say?
[/COLOR]

0lento

Hey man, can you tell me?

My current progress on Client side prediction, it took me over a month to get it to this state :stuck_out_tongue:
Still need to find a way to handle dynamic collisions.

Nice work!!, How did you get this? Are you correcting the position on server by adding extra forces on the car to constraint the movements?

Nice work Blue Man :slight_smile:

What kind of environments have you tested that in? Everything seems to fall apart when testing between two different machines running at vastly different framerates, or are you using a modded engine?

Basically client sends a request to server and server responds with a real position of the client. When the information arrives client then preforms Rewind/replay and then it uses a smoothing algorithm to correct the client.

I tested it with the client at 10 fps and server at 60 fps and vice versa, only smoothing was more obvious but when fps is over 10 everything is working fine. I am using a launcher version of the engine.