A quick one today to hopefully help someone else who is scratching their head about very weird LastRenderTime results in
UE 5.5!
TL;DR
In Unreal 5.5 if you disable Occlusion Queries, LastRenderTime on most Primitive Components will not be updated correctly.
This will cause Skeletal Animations not to play even though a skeletal mesh is definitely within the camera frustum,
and any other effects that rely on LastRenderTime will be erratic.
You must have Occlusion Queries enabled in Unreal Engine 5.5 to avoid this kind of behaviour:
Notice how the clearly visible skeleton isn’t animating until it enters the spotlight, and stops shortly after?
Why the f**k are my skeletons sliding around?
That was my reaction when upgrading from UE 5.4 to UE 5.5.4 yesterday. Suddenly my enemies were skidding around and not animating even though they were in frame, unless they got close enough to our character.
The default skeletal animation tick mode (VisibilityBasedAnimTickOption) is set to update the bones of a character ONLY
when they’re rendered. Makes sense, but something has to tell the character that they’ve been rendered - that’s what
LastRenderTime is on all primitive components. Turns out that unless the skeleton was close enough to the character,
that time wasn’t getting updated even though it was being rendered.
In the end I realised that my skeleton was only updating when within the bounds of a shadow casting light. Which meant
that only the shadow pass was updating LastRenderTime. Why??
What updates LastRenderTime?
The key function is FPrimitiveSceneInfo::UpdateComponentLastRenderTime, and that gets called in 4 places.
- One is in the raytracing code which is there to deal with things being seen in a reflection, so we’ll ignore that.
- Two are in the light shadow rendering code, which are clearly working.
- The last one is within the regular visibility code, and this is the one that’s not working properly.
The culprit
In SceneVisibility.cpp under FRelevancePacket::ComputeRelevance there are these lines:
// Update the last component render time only if we know for certain the primitive is un-occluded.
if (View.PrimitiveDefinitelyUnoccludedMap[BitIndex] || View.Family->EngineShowFlags.Wireframe)
{
const bool bUpdateLastRenderTimeOnScreen = true;
PrimitiveSceneInfo->UpdateComponentLastRenderTime(CurrentWorldTime, bUpdateLastRenderTimeOnScreen);
}
Notice how it only calls UpdateComponentLastRenderTime if the primitive component explicitly exists in a map of
unoccluded objects. The trouble is, when Occlusion Queries are disabled nothing gets added to that map, so visible
components will never get their LastRenderTime updated, until they end up within a shadow casting light’s bounds, where
the code for shadows will update it.
So yeah, don’t disable Occlusion Queries I guess. My project doesn’t need them (it’s top-down), but they have to be enabled in UE 5.5 to avoid this problem. You can turn Occlusion Queries on and off:
- In Project Settings > Engine - Rendering > Culling > Occlusion Culling, or
- By toggling
r.AllowOcclusionQueriesto 0 or 1 on the console
Hope that helps someone! This drove me mad for a day or so.