We have built a system where we re-use skeletal and static mesh components for characters, by pooling them individually on a global actor and attaching them to different actors on demand in order to avoid having to pay the initialization cost for these components. When they are not in use they are marked as invisible. This is used for character clothing as well as items.
We’ve been facing some issues with motion vectors in this regard, and were wondering if what we’re seeing is working as expected or we’re using it incorrectly.
* When making a pooled mesh visible again some frames after hiding it for re-use, we find that the previous transform is still picked up and used as the previous transform for motion vector calculations. From looking at the render code it appears like these are only cleaned up if they are at least 10 frames old, but this seems a little odd, as using a 10 frame old transform as a previous transform will generate a wrong velocity value since the delta time is used from a single frame only?
-> We’ve been able to work around this one by calling ResetSceneVelocity() just before setting the visibility to false for the object, this ensures the velocity is instantly removed from the velocity data buffer.
* When calling ResetSceneVelocity in the same frame we update the transform of the same primitive, it appears like the previous transform is not correctly cleared from the primitive. The call to ResetSceneVelocity does clean up the velocity data, however the position update is later received during the render scene update (FScene::Update), where it re-initializes the velocity data using the old previous velocity.
> PrimitiveSceneInfo->bRegisteredWithVelocityData = true;
> VelocityData.UpdateTransform(PrimitiveSceneInfo, LocalToWorld, PrimitiveSceneProxy->GetLocalToWorld());
-> We’re able to work around this by using ResetSceneVelocity along with MarkRenderStateDirty, as the proxy re-creation path uses the LocalToWorld as the default value for the previous transform.
> VelocityData.UpdateTransform(PrimitiveSceneInfo, PrimitiveTransforms[PrimitiveIndex], PrimitiveTransforms[PrimitiveIndex]);
As the code documentation for ResetSceneVelocity indicates that it’s for use when teleporting objects, it feels strange that it can’t be used for this. How is this supposed to be used?
* When creating a mesh component, and moving it in the same frame a scene velocity is immediately generated from this movement delta. We’re spawning/constructing an item from code, and then attaching it to a character socket. Since the movement is in a single frame, I was expecting this to be coalesced on the render side, as it is on other frames besides the one where the meshes are spawned. However as RegisterComponent immediately registers a primitive scene proxy with the initial transform, and further moves call MarkRenderTransformDirty it ends up the case that a velocity is generated as 2 transforms are set for this proxy in a single frame. Is there a way to delay creation of the render proxy until we’ve attached the item to the character?
-> We were able to work around this by calling MarkRenderStateDirty() after the final transform is set, which appears to avoid the bad initial transform from ending up in scene velocity as the proxy is destroyed before it reaches the scene add.
* Calling ClearMotionVectors does not work when it’s called before another update to the mesh (for example before the animation blueprint ticks) because motion vectors are only cleared when EBoneTransformUpdateMethod::ClearMotionVector is the last update in the list.
-> We work around this by calling the function after the skeletal meshes have finished ticking
All of the above feel quite hard to work with in the way that we’re using the API’s, which indicates that we’re likely using them wrong. Would you be able to advise how to correctly manage the scene velocity for these cases?
[Attachment Removed]