Motion Blur Artifacts on APEX Cloth

We have APEX cloth on our character and it’s causing artifacts with the motion blur.

Just from the visual result, it seems to me like the cloth is not being rendered into the velocity buffer. The pixels are blurred based on whatever the velocity of the pixels behind it would normally be, e.g. in a situation where the camera is orbiting the character, the cloth has blur when it overlaps the scene but not where it overlaps the character.

I appreciate the technical difficulty of getting the correct velocity in there for cloth, and we don’t require that the velocity buffer actually have the correct velocity based on the cloth simulation, just that it at least holds the velocity it would have if it were the normal skinned vertices. That said, it appears that previous world positions are calculated for cloth in the VertexFactoryGetPreviousWorldPosition function inside GpuSkinVertexFactory.usf. If that’s the case, is there any reason why the cloth would be failing to render to the velocity target?

I’ve investigated a bit further now. The mesh is certainly getting rendered to the velocity buffer.

With the default setup, when the character and cloth are stationary, motion blur is rendered correctly even with the camera orbiting. When the character and cloth are moving (camera fixed, with the character in the center of the screen, and a fixed view direction independent of character orientation) the cloth motion blurs out even though its velocity should be zero with respect to the camera.

Looking at everything in the shaders, it all seems correct so I don’t know what’s going on. Interestingly, even though it’s obviously incorrect, if I modify VertexFactoryGetPreviousWorldPosition inside GpuSkinVertexFactory.usf so that the cloth position is calculated as Intermediates.SimulatedPosition + View.PreViewTranslation rather than Intermediates.SimulatedPosition + View.PrevPreViewTranslation, then I get the opposite problem. With that change, the cloth motion blurs when the camera orbits (as to be expected with that change), but there is no motion blur when the character moves.

Any guidance here would be much appreciated.

So, I have a solution here, but it is certainly not ideal. The crux of the issue is that:

float4(Intermediates.SimulatedPosition + View.PrevPreViewTranslation, 1)

is not equal to:

mul( mul(float4(Intermediates.SimulatedPosition,1), Primitive.WorldToLocal), PreviousLocalToWorld )

Replacing the instance of the former with the latter seems to fix the issue. Can someone perhaps provide a more computationally efficient option?

Hi BrainDx, I entered UE-14233 as a task to look into this, it might not be as straightforward as that (we had similar issues on landscape).

Thanks. Could you provide some insight as to why “WorldPosition + View.PrevPreViewTranslation” doesn’t yield the correct point in PreviousWorldTranslated space, and “WorldPositionWorldToLocalPreviousLocalToWorld” seems to do a better job? What part of the transform is missing in the first calculation?

I think it’s related to getting the previous world position; check VertexFactoryGetPreviousWorldPosition on LocalVertexFactory.usf.

I fixed this in the main branch, as of changelist 2524871. This will make it to 4.9.

I see that this CL made it into 4.8. I’ve migrated my project and the behavior still occurs.

I took a look at the changes you made in CL 2524871 and it looks like it’s mostly just cleanup, collapsing some lines into lerps and defining some initial values. Unless I’m missing something, it doesn’t seem to actually change anything from a functional point of view (at least not when ClothBlendWeight == 1.0, as it is in this case).

I’ve opened a pull request with the fix that I run with locally:
https://github.com/EpicGames/UnrealEngine/pull/1239

2018 - still doesn’t fixed.