Camera Stutter with Async Physics

The camera is stuttering/glitching. We see the car visually snapping. (it happens a little all the time but it’s obvious at around 0:15 in the video).

[Attachment Removed]

Steps to Reproduce
Hello,

We have an issue on our project with camera stuttering. I created a new project using the Vehicle Template, and only by enabling Async physics, I can repro the issue as soon as fps are low/unstable enough.

Steps to repro:

  • Create a Vehicle project (UE 5.7.2)
  • Enable ‘Tick Physics Async’
  • Enable ‘Substepping’
  • Use 0,016667 for ‘Async Fixed Time Step Size’ and ‘Max Substep Delta Time’
  • Launch several clients (like 6) at once to make fps drop to 20-30 fps (and be unstable)(using Play From Here)
  • Notice the camera is stuttering.

This is more easily visible when turning.

Note that I also tried to just launch 1 client and use a MaxFPS to 30, but the issue do not occur that way. So it seems related to FPS being unstable.

Also note that it also happen even with Camera Lag disabled, even though it is less obvious. (at first I thought it could be related to this issue but it seems like it’s not)

Here are the only changes I made to the template project:

[Image Removed]

How could we fix this stuttering issue?

Of course, we do need Physics Async in our project, so disabling it is not an option.

Thank you for your help!

[Attachment Removed]

Hi Paul,

This could be to do with physics itself getting bogged down or the difference between game and physics is out of balance.

Try adding some logging here to see if this fires off during the test:

[Image Removed]

If so there is a setting for max number of physics ticks to run per game thread (which is set at 3 as default) (p.MaxPhysicsStepsPerGameTick), which you can bump up.

Otherwise is could be the physics itself getting bogged down potentially - there is a setting “EAsyncBlockMode” which can alter the behaviour.

Best

Geoff Stacey

Developer Relations

EPIC Games

[Attachment Removed]

Hello,

Thank you for your answer!

I tried adding logging where you said, but it doesn’t fire off in our project.

Actually, we enter FPhysicsSolverBase::AdvanceAndDispatch_External() but not the if DoNoBlock.

if (AsyncBlockMode == EAsyncBlockMode::DoNoBlock)Where is the setting EAsyncBlockMode?

[Attachment Removed]

Apologies, this is as default set to ‘0’ which is “BlockOnlyPastFrames” - you can see this from the AsyncPhysicsBlockMode CVar declared in PhysicsSolverBase.

I’ve been mulling how best to be able to capture this - and the probably it would be worth taking a look into Solver.NumPendingSolverAdvanceTasks in PhysicsSolverBase. That should give and indication of whether things are backing up.

It is worth pointing out though that when these kind of things happen, the only real solution is to run a performance pass to get this back to a minimum target perf.

Best

Geoff

[Attachment Removed]

I logged Solver.NumPendingSolverAdvanceTasks and (unfortunately) it stays at 0. So I’m guessing the issue comes from something else?

(I tried in our own project, not the template, since I needed to recompile.)

[Attachment Removed]

That is surprising. We may be able to diagnose this if you can take an insights capture during this situation and send that across (with an approximate frame number/ area when this happened).

[Attachment Removed]

Here is the insight capture and the video while capturing. As you can see the stutter is quite strong while deccelerating on the vanilla UE template (with the initial repro steps of the topic: Enable ‘Tick Physics Async’, Enable ‘Substepping’, Use 0,016667 for ‘Async Fixed Time Step Size’ and ‘Max Substep Delta Time’, launching 6 clients, and that’s it).

[Attachment Removed]

Hello!

Did you get the chance to look at the insights capture?

[Attachment Removed]

Hi Paul, I’ve looked at the trace, and repro’d it myself (ie launch lots of instances for 20-30fps) and I’m not getting the issue. The trace capture isn’t showing much out of the ordinary - but there are a couple of channels you can enable to make that trace more detailed - if you enable the tick box ‘stat named events’ and the chaoslocks channel that may help show what is happenning.

From the video, it looks like the car rotation is jumping a bit - so maybe capturing that in the data could help narrow this down? It doesn’t look like the camera is jumping here since the relative background movement doesn’t jump.

Essentially when it jumps, we’d want to know the start and end transform of the car for a sequence of frames, plus the interpolation factor and the frame timestamp - from there you can test if it is jumping based on the physics or some other clock.

That being said, is there an expectation of the game holding up visually at 20fps?

Best

Geoff

[Attachment Removed]

Thank you for your answer!

I made a new trace with named events & chaoslocks channel (and a video with it). Not really sure what to look for, so here it is!

20fps is definitely really low, but I’m having the issue at like 30-33 fps, which could still make sense for low-end hardware I guess.

About capturing more data (camera transform and interpolation factor) where and how would you do that please? I’m guessing logging everything in the tick is not really the way to go with async physics.

(Too bad you don’t repro on your side, did you also enable substepping, as I mentioned in the initial repro steps?)

[Attachment Removed]

Hi Paul,

Repro wise all followed, and the traces have the channels I’d expect now. The physics doesn’t look to be struggling, which would lean into your analysis of not finding the number of pending tasks increasing. I’ve replayed the video a number of times to try and see if this may be the camera (as in I can see the car glitching.. but I can’t be 100% certain about if the background is, which would point to the camera if they both are). What I’d suggest doing is recording the transform change (especially the turning rate and the position), and comparing it to the previous frame and tick (plus do the same with the camera) - that should tell you which of these it is.

Best

Geoff

[Attachment Removed]

Here is a video with print on Pawn Location, Speed and TurnRate

using

float Speed = GetMesh()->GetPhysicsLinearVelocity().Length();
float TurnRate = GetMesh()->GetPhysicsAngularVelocityInDegrees().Z;

and also CameraComponent Transform, with Delta Time & Frame number,

and Delta values with previous frame.

Looking frame by frame, we see a visual glitch for example at frame 34980 - 34981 - 34982.

FPS drop to 26 on frame 34981, and it feels like the cam gets closer for 1 frame.

CameraComponent is recovered quickly with:

	if (APlayerController* PC = Cast<APlayerController>(GetController()))
	{
		if (AActor* ViewTarget = PC->GetViewTarget())
		{
			TArray<UCameraComponent*> Cameras;
			ViewTarget->GetComponents<UCameraComponent>(Cameras);
 
			for (UCameraComponent* CameraCpt : Cameras)
			{
				if (CameraCpt && CameraCpt->IsActive())
				{
					CameraComponent = CameraCpt;
					break;
				}
			}
		}
	}

(note: by default in the project, Camera Lag is disabled, but Camera Rotation Lag is enabled.)

Honestly not too sure what to make of this, but tell me if you want me to add infos. (or if the way I get speed/turnrate is incorrect)

[Attachment Removed]

Thanks Paul - would you be able to send me this output in a text file, it’ll make parsing it a bit easier

[Attachment Removed]

Hi Geoff,

sure, here is another capture with video, trace and output log.

Many stutters but for example Frame 14110 - 14111 - 14112 seems a strong one. (fps going 32 - 22 - 26 on the Stat FPS display, 40 / 11 / 57 in my output).

[Attachment Removed]

Hello!

Did the new video+trace+output bring anything interesting?

[Attachment Removed]

Hi Paul,

Kind of - but I’ve had to do some digging. On the camera spring arm on the blueprint, can you ensure “Clamp to Max Physics Delta Time” and “Use Camera Lag Substepping” are both ticked please and see if that makes a difference?

Best

Geoff

[Attachment Removed]

Hello, thanks for coming back to me!

Unfortunately, I tried to check “Clamp to Max physics Delta time” (“Use Camera Lag Substepping” is true by default) but it did not help (still on the template project with no changes).

Note that in our own project, we also have the issue and we are not using a Spring Arm component.

[Attachment Removed]

Very strange. I’ve actually just had something similar come in which puts the issue higher up in the code - can you bump the Max Substep Delta Time to 1.0 and see if that fixes the issue? If so you have run into the same slightly non-intuitive issue with overloading a parameter between normal and async physics!

Best

Geoff

[Attachment Removed]

I tried it (with and without the changes on Spring arms) but it still stutters/jitters quite a lot. With 6 clients and around 30 fps.

If I reduce to 3 clients, it goes up to 60 fps, and then its smooth. So same behaviour.

[Attachment Removed]