Hair/Cloth sims bug out when using LODs

Unfortunately I don’t have a good way to provide a repro since the setup is fairly complicated and my knowledge of cloth setups is fairly limited, so I’m mostly hoping that this problem sounds familiar to someone that may know a solution.

We’ve been having issues for quite a while ever since LODs were added to cloth simulations on the main player characters. The problem manifests differently for the hair and cloth, but the result is the same: The simulation bugs out and becomes completely invisible, sometimes also causing the player character themselves to become completely invisible.

We’ve found and worked around the issue of the character vanishing by commenting out the call in USkeletalMeshComponent::CalcBounds() that includes the clothing bounds in the player bounds calculation around line 3010 ish where it’s doing AddClothingBounds(NewBounds, CachedBoundsTransform).

It appears that sometimes when clothing/hair swaps between LOD levels it ends up getting wild values that send its bounds off into NaN values, which results in the cloth and character vanishing completely. Omitting these invalid values from the character bounds stops them from vanishing, but the cloth/hair still breaks and vanishes.

I’ve also attempted to add some logic to CalcBounds() that forces a reset of the cloth when NaN values are detected, which sometimes fixes the issues, but not always. So a proper solution is still currently unknown.

FBoxSphereBounds clothingBounds(NewBounds);
AddClothingBounds(clothingBounds, CachedBoundsTransform);
if (clothingBounds.ContainsNaN())
{
	UE_LOG(LogSkeletalMesh, Warning, TEXT("NaN in mesh bounds detected! Resetting cloth sim for %s -> %s"), *GetOwner()->GetActorNameOrLabel(), *GetName());
	ClothTeleportMode = EClothingTeleportMode::TeleportAndReset;
}

Does any of this sound familiar? Are there any known ways to fix these issues with cloth sims and LODs?

The fact that the problem seems to happen on both cloth and hair systems, which are two completely independent systems (unless you are using cloth sim for hair), would probably suggest some issue in your game code.

The bound check is the last place where the NaN would end up, so you will have to try to find them back at the source.

Maybe try to check for NaNs in the transforms of the bones on which these simulations are hooked, and make sure there isn’t any missing bones in those LODs.

If you want a suggestion for implementing a more low level reset system, look at the new Cloth Asset system, since it has some options for NaN investigation and recovery.

Check \Engine\Plugins\ChaosClothAsset\Source\ChaosClothAssetEngine\Private\ChaosClothAsset\ClothSimulationProxy.cpp, you’ll see there the p.ChaosClothAsset.SimulationDataCheckFinite and p.ChaosClothAsset.SimulationDataResetOnNonFinite cvars, and the reset code if you search for bNeedResetClothFromNanCheck.

You’ll then have to retrofit a similar system into the ChaosClothingSimulation.cpp file. However this won’t fix the hair problems if they are based on a different type of simulation.

Confirmed with the art team we are using cloth for both the hair and actual clothing. Will look into the other things you mentioned and keep digging. Thanks for the info.

EDIT: No missing bones or bad values in the LODs from what we can tell, so still unsure what’s going wrong. I’ll just have to see about snagging that reset from the newer version and hope that does it.

Okay that’s useful to know.. In this case I can’t rule out a cloth bug. We’ll still need some more info or a reproducible to debug it though.

Unfortunately it’s super random even for us, so I don’t think I’ll be able to provide a repro. If that newer reset stuff ends up fixing it though I’ll make a new post here. Should hopefully get to that sometime next week.

OK that worked out. I did what you mentioned and copied the setup from ClothSimulationProxy.h/.cpp/.ispc into ChaosClothingSimulation.h/.cpp/.ispc, which required implementing a custom version of GetClothingSimulationDataAndCheckFinite() in the ispc to mimic TransformClothSimulDataAndCheckFinite() and some slight differences to how it is setup in the cpp, but for the most part it was very straightforward to move over. No more broken hair/cloth so I’m happy :smiley: Been fighting this problem for months. Thanks again!