TSimCallbackObject and disabling FContactPairModifier

I create my version of :

public Chaos::TSimCallbackObject<Chaos::FSimCallbackNoInput, Chaos::FSimCallbackNoOutput, Chaos::ESimCallbackOptions::ContactModification>

Its registered and works most of the time. But it doesnt work all of the time.

OnContactModification_Internal is called with a single contact pair that I can disabled using FContactPairModifier::Disable, which works fine between a dynamic physics enabled static mesh and the character capsule. However, there still seems to be contacts that are not ignored for the Skeletal Mesh Physics elements. These residual contacts seem to force my static mesh to stick to elements of the characters skeletal mesh.

Ive tried pretty much everything I can think of, but nothing I can do seems to work. Ive reduced it to disabling all contacts and I sill have collisions. I can confirm no game code is fired for this.

void FSimulationCallbackContactDisablerObject::OnContactModification_Internal(Chaos::FCollisionContactModifier& Modifier)
{
    for (Chaos::FContactPairModifier& ContactPairModifier : Modifier)
    {
        ContactPairModifier.Disable();
    }
}

[Attachment Removed]

Hi Nicolas, to debug, can you disable the CCD side and see if this stops the issue you are seeing?

Best

Geoff Stacey

Developer Relations

EPIC Games

[Attachment Removed]

Hi Nicolas,

CCD affecting this makes sense. Essentially the whole point of CCD is to stop collisions being missed when objects move fast. It does this by kind of ‘stopping’ the body just before it penetrates which is what you’ve been seeing - the non ccd collision side is done after that. Keep an eye out for your physics getting ‘stuck’ - ie one of the bodies (such as an arm) penetrating a mesh but the others being stopped etc.

Can I confirm a little more about your use case here? Why are you disabling these?

Best

Geoff

[Attachment Removed]

We need a way to disable physics completely between 2 specific actors where the normal rules of responses should normally apply.

Consider an AI (with preset Pawn, which blocks Throwables) throwing an item (with preset Throwable, which blocks Pawns) that might spawn inside the AI at first and be impulsed towards the thrown direction. We don’t want the item to collide with the thrower but we want it to collide with other AIs (other Pawns). So using the established system to disable the collision between the thrower and the thrown, without it impacting the general ruleset of collisions, couldn’t be done.

Normally this is done via what Chaos exposed here (contact modifying callbacks). This is also the case in PhysX or Havok, as well as other proprietary engines I’ve worked on, so when I saw the hooks for this I gravitated naturally to this solution. I’ve never had to disable anything else than the actual contact though, so that’s where I got stuck.

If you have any better solution, I’m all ears.

[Attachment Removed]

Hi Nicolas and a Happy New year.

You could avoid the CCD issue altogether in this case by adding these bodies to an exclusion map, which would then work not that specific AI character only and not the class of actors. This would need to enable the ChaosCollisionManager in the engine to work, and then you can add/remove using FChaosEngineInterface::AddDisabledCollisionsFor_AssumesLocked as needed.

You can disable to CCD side specifically in a callback, but you’d need to store the FGeometryParticleHandle somewhere and use the OnCCDModification_Internal callback in tandem with the normal one you’ve already used.

The difference in implementation for this way vs other engines could be the position based nature of the solver, I think PhysX used to clamp impulses to avoid the CCD specific issue.

Hope that all helps!

Geoff

[Attachment Removed]

That’s interesting. Could you specify what exactly do you mean when you mention “Enable the ChaosCollisionManager”? Is this a toggleable setting or something else?

Also, after looking into AddDisabledCollisionsFor_AssumesLocked, I have a couple questions.

  1. Mainly, it uses body arrays. Unless we know with precision what actor we have, which we usually dont, and if we did it could change down the line, I’m uncertain how to ensure we collect all body instances of a generic actor. I can get them for a skeletal mesh, a static mesh, capsule component, etc. and so forth, but it doesn’t cover data that can be added/removed in the future. For example if for some reason someone adds a new collision component in BP to my hypothetical AI character, I wouldn’t know about it.
  2. You mention I can disable the CCD but I’d need a FGeometryParticleHandle. However, I’ve disabled the full midphase and I needed none of that, and everything seems to work. Did I disable something I shouldn’t have?
  3. Disabling in the callback allows me to ask what actor is associated and disable that way, allowing to store actors instead of body list, which is much more future safe. Is it a bad idea?
  4. The name of the function implies I shouldn’t be using it at any random moment. Using it in the tick (pre or post phys) I assume is correct?
    [Attachment Removed]

Morning Nicolas,

RE CVars:

They are indeed toggleable settings. There are a LOT of “CVars” in the code for allowing tuning. There’s over a thousand in Chaos alone.

https://dev.epicgames.com/documentation/en\-us/unreal\-engine/console\-variables\-cplusplus\-in\-unreal\-engine?application\_version\=5\.7

I’d suggest just altering it in the defaultengine.ini file in the project for simplicity if this is the route you are interested in.

I’ve actually found a CVar this morning which will actually give you what you are looking for in an easier manner.

bChaosCollisionModiferBeforeCCD found in the PBDRigidsEvolutionGBP.cpp file will alter the modifier behaviour to run before the CCD system, which means no need for any CCD awareness in that manner.

RE other questions (which may not be relevant now)

  1. Apologies I skipped a bit of context here and may have made some assumptions :smiley: - In my head the code which would be spawning a new object for something like a projectile would also need have access (indirect or not) to the specific Actor it is due to be spawned inside. From there you would have access to the specific bodies to collect and then add to the code (and the new body you’d be spawning)
  2. No, you are completely correct. The issue would be if you needed some information about the collision (ie for a probe/callback) then you’d need to do this. Since you just want to ignore it disabling this is fine.
  3. In a sense it depends on the scope you want to do this at - ie there is not a 1:1 correlation between actors and bodies
  4. You need to use all the _assumedLocked type functions with a lock already in place - a common way to do that is with the FPhysicsCommand::ExecuteWrite function. Theres a few examples in the code of that - ie UShapeComponent::CreateShapeBodySetupIfNeeded()

[Attachment Removed]

Ok this is starting to make much more sense.

In my specific case, I’m working on a live game that is already running and I’d prefer not change the whole physics ordering pipeline. On a new project, yeah that would be good, but now? Feels dangerous :stuck_out_tongue:

Followup on questions:

  1. Actually your assumption is correct. What I meant was collecting body instances from actors is difficult EVEN if you know the actor. Different components have different number of bodies, they aren’t all used, etc. Let’s say I have a Character, I can get the bodies of the skeletal mesh, but I also need the body of the capsule. Maybe now a data person adds some sort of colliding shape to my character in BP and I dont collect that. Etc. I’m wondering if there’s the equivalent of “GetAllBodyInstances” on either the AActor class or UPrimitiveComponent class that could help for that.
  2. What I actually do is something like this:
void FSimulationCallbackContactDisablerObject::OnMidPhaseModification_Internal(Chaos::FMidPhaseModifierAccessor& Modifier)
{
	Chaos::FPhysicsSolverBase* BaseSolver = GetSolver();
	Chaos::FPhysicsSolver* RealSolver = static_cast<Chaos::FPhysicsSolver*>(BaseSolver);
	FPhysScene_Chaos* PhysScene = static_cast<FPhysScene_Chaos*>(RealSolver->PhysSceneHack);
 
	UWorld* World = PhysScene->GetOwningWorld();
	if (!IsValid(World))
	{
		return;
	}
 
	USomeSubsystem* SomeSubsystem= World->GetSubsystem<USomeSubsystem>();
	if (!IsValid(SomeSubsystem))
	{
		return;
	}
 
	Modifier.VisitMidPhases([SomeSubsystem, PhysScene](Chaos::FMidPhaseModifier& MidPhaseModifier)
	{
		Chaos::FGeometryParticleHandle* Particle0 = nullptr;
		Chaos::FGeometryParticleHandle* Particle1 = nullptr;
		MidPhaseModifier.GetParticles(&Particle0, &Particle1);
 
		if (Particle0 == nullptr || Particle1 == nullptr)
		{
			return;
		}
 
		AActor* Actor0 = PhysScene->GetOwningComponent<UPrimitiveComponent>(Particle0->PhysicsProxy())->GetOwner();
		AActor* Actor1 = PhysScene->GetOwningComponent<UPrimitiveComponent>(Particle1->PhysicsProxy())->GetOwner();
		if (!IsValid(Actor0) || !IsValid(Actor1))
		{
			return;
		}
 
		if (SomeSubsystem->IsContactPairDisabled(Actor0, Actor1)) // Lookup gameplay code array stored on gameplay code side
		{
			MidPhaseModifier.Disable();
		}
	});
}

Which allows me to be 100% sure 2 actors will not collide, even if some data person adds or removes bodies inside them. So I correct myself, I do use FGeometryParticleHandle but they are handed to me by the visit function. I’m hoping that’s the intended use of it?

3. There may not be a 1:1 correlation but there’s a 1:X correlation, correct? 1 actor contains multiple bodies.

4. Perfect! I had already done that exactly because of the example you mentioned. Though to be fair, it’s the only one example in the code, so “few” is incorrect :stuck_out_tongue: (I think…)

[Attachment Removed]

I occasionally make sense, albeit rarely :smiley:

Agreed that this does pose a risk for a live deployment, although if vital it is one which you should be able to scan the code for any uses of that callback to ensure nothing relies on the alternal method. Overall though I get the hesitancy and I’d probably do the same.

  1. All of the body type components derive from UPrimitiveComponent, and there are iterators in the Actor (such as ForEachComponent) which would enable you to gather all of these, and then gather the bodies from the GetBodyInstance. You may need to do some subtyping to get the objects with multiple bodies though.
  2. It’d work, but keep an eye out for performance drops using this method. It may be fine though.
  3. There is a 1:X correlation (for the instances of the bodies.
  4. There are similar examples for the other _internal suffixed functions, but they are all very similar :slight_smile:

Best

Geoff

[Attachment Removed]

That covers it!

I think the only thing that’s annoying is the subtyping for the classes that contain multiple body instances. A part from the SkeletalMesh and other project specific classes, do you have any documentation or exhaustive list that I could check to make sure I’m not missing any?

[Attachment Removed]

Great stuff!

Here are the derived classes. Yep, it is annoying and something which we are keen to improve. No imminent arrival though.

[Image Removed]

Unsure how open you folks are to engine modifications, but in your case you could do a UPrimitiveComponent level GatherAllBodies type function (or Iterator class if being fancy), and then override for the multiple body classes.

There is also scope for adding a help class and having type based overloads:

ie

GatherAllBodies(USkinnedMeshComponent*)

GatherAllBodies(UMeshComponent*)

This would avoid needing to alter the engine itself. For the skinned/skeletal meshes, you’d get the bone names from this class, and then pass each one found into the function to get body. Again - I’d check perf here since that could be a slowish method, but equally - it could be fine.

Best

Geoff

[Attachment Removed]

Perfect!

Thanks!

[Attachment Removed]

My pleasure Nicolas!

All the best

Geoff

[Attachment Removed]

This was the problem. Disabling the contacts is not enough to disable everything. You ALSO need to disable the CCD.

For posterity, this is what works in code now:

class FSimulationCallbackContactDisablerObject : public Chaos::TSimCallbackObject<
	Chaos::FSimCallbackNoInput,
	Chaos::FSimCallbackNoOutput,
	Chaos::ESimCallbackOptions::ContactModification |
	Chaos::ESimCallbackOptions::MidPhaseModification>
{
 
private:
	virtual void OnMidPhaseModification_Internal(Chaos::FMidPhaseModifierAccessor& Modifier) override;
	virtual void OnContactModification_Internal(Chaos::FCollisionContactModifier& Modifier) override;
};
void FSimulationCallbackContactDisablerObject::OnMidPhaseModification_Internal(Chaos::FMidPhaseModifierAccessor& Modifier)
{
	Modifier.VisitMidPhases([](Chaos::FMidPhaseModifier& MidPhaseModifier)
	{
		MidPhaseModifier.Disable();
	});
}
 
void FSimulationCallbackContactDisablerObject::OnContactModification_Internal(Chaos::FCollisionContactModifier& Modifier)
{
	ContactPairModifier.Disable();
}

If you see anything wrong with this (especially behaviors that come out of disabling the midphase completely instead of just the CCD), please tell me :sweat_smile:

[Attachment Removed]