SetNumActiveBodies() does not trigger an UpdateViews() in Chaos's FPBDRigidsSOAs

Hi, we ran into an issue with Chaos rigid particles being disabled (usually via SetNumActiveBodies) but still sticking around in the ActiveParticlesView that Chaos uses to iterate and simulate those particles.

Skeletons on characters switching LOD levels, often will switch from a skeleton with a movable piece of hair connected to the rest of the skeleton via a joint. When switching to a lower LOD that then disables that moving piece of hair, it fires SetNumActiveBodies() which will call SetEnabled(false) on the FActorHandle that refers to the particle in the simulation. This is fine, however it doesn’t seem to propogate that disabling to the ActiveParticlesMap that the Rigidbody AnimNodes simulation.

When FSimulation::Simulate() is called, it does check for ActorsDirty and does know to recheck joints, but it does not check for enabled/disabled particles that have happened since last time. So often what happens is the particle is disabled via SetNumActiveBodies(), EnableDisableJoints() sees this, and disables the joint holding the particle in place, but the disabled particle remains in the ActiveParticlesView, and continues getting simulated (falling due to gravity) also without the joint being enabled to hold it into place.

This is fine for LOD things for the most part since this unwanted simulation goes unnoticed (as it’s part of a skeleton we aren’t rendering due to the LOD swap). But when the LOD is switched back, the particle that was being simulated against its will now has the joint re-enabled, and snaps it back to position. However it renders the hair as stretched to the void for one frame before the joint works its magic.

We have solved this by adding a function called EnableDisableParticles() in the same vein as EnableDisableJoints() that will force the views to be updated and not continue to simulate particles that are newly disabled. We call this function right before EnableDisableJoints() is called to make sure the views are in a good state first before joints are enabled/disabled.

We are asking if this is intended behaviour or if there’s plans to look into this side of things?
We do see that SetNumActiveBodies() does mark ActorsDirty to true, and it seems like the intention is that this should be picked up via the FSimulation::Simulate(), but I can’t see how ParticleViews would be updated to handle RigidParticles that are newly disabled/enabled from being removed/added from the views.

Any info or thoughts on this are welcome. Thanks.