Using PhysX Contact Modifiers

I’m having trouble understanding how to add a specific piece of code. The PhysX docs show that I can use a Callback to change the behavior of certain collision interactions, here, specifically Contact Modification.

My problem is that the class I need to derive from isn’t something I can include, as it’s pre compiled? I’m not really sure how this works. The UE4 GitHub shows the PhysX file, but VS2019’s solution explorer shows PhysX as a single thing, not the files that make it up.

Do I need to build 4.27 from source to have access to this, or is there something else I’m missing.

The goal is to stabilize high velocity collisions, which should technically be smooth. I’ve played with seemingly all the setting exposed to the editor for PhysX, but it hasn’t fixed what I need.

The plan is to take specific sets of collisions using said Callback and either remove or limit only the local Z velocity of the de-penetration.

Any help is appreciated. I’m happy to explain what I’ve tried as they come up, but there’s a lot to list in a single post. Thank you.

EDIT: I managed to derive from the class I was looking for. I stumbled upon this, and I managed to get it to compile. Now I’m struggling to add the Contact Modify flag to the shape.

Contact Modifiers are global - they affect the entire physics scene not just specific bodies. Any filtering you want to do needs to be done from the virtual onContactModify function.

Here’s an example from my own code:

void FHT_PhysXContactModifyCallback::onContactModify(PxContactModifyPair* const pairs, PxU32 count)

	for (PxU32 Idx = 0; Idx < count; Idx++)
		PxContactModifyPair& ContactPair = pairs[Idx];

		const ECollisionChannel ChannelA = GetCollisionChannel(ContactPair.shape[0]->getQueryFilterData().word3);
		const ECollisionChannel ChannelB = GetCollisionChannel(ContactPair.shape[1]->getQueryFilterData().word3);

		// If vehicle is colliding with landscape, nuke friction and bounciness
		if ((ChannelA == ECC_Vehicle && ChannelB == HT_COLLISION_LANDSCAPE)
			|| (ChannelB == ECC_Vehicle && ChannelA == HT_COLLISION_LANDSCAPE))
			for (PxU32 CIdx = 0; CIdx < ContactPair.contacts.size(); CIdx++)
				ContactPair.contacts.setDynamicFriction(CIdx, 0.f);
				ContactPair.contacts.setStaticFriction(CIdx, 0.f);
				ContactPair.contacts.setRestitution(CIdx, 0.f);

And the associatted header:

#include "PhysXPublicCore.h"

class FHT_PhysXContactModifyCallback : public FContactModifyCallback
	virtual void onContactModify(PxContactModifyPair* const pairs, PxU32 count) override final;

class FHT_ContactModifyCallbackFactory : public IContactModifyCallbackFactory
	virtual FContactModifyCallback* Create(FPhysScene_PhysX* PhysScene) override final { return new FHT_PhysXContactModifyCallback(); }
	virtual void Destroy(FContactModifyCallback* Callback) override final { delete Callback; }

To enable to contact modifier, you need to set the static factory property. I do this at module startup time:

void FHTCoreModule::StartupModule()
	// Register PhysX Contact Modifier
	FPhysScene::ContactModifyCallbackFactory = MakeShared<FHT_ContactModifyCallbackFactory>();

As a note, Contact Modifiers are also available for Chaos, but the API is much more complicated and there’s no easy factory initializer currently.

1 Like

This is wonderful. After playing with the other post I stumbled upon (perhaps more, I can’t remember how many things I’ve dug through), I think I have something remotely similar. However your example seems to be a lot closer to exactly what I need.

You mention that Contact Modifiers are global, affecting the entire physics scene and not specific bodies. The PhysX docs here says you can “exempt certain pairs of objects from interacting, or to configure the SDK collision detection behavior in a particular way for an interacting pair”. It seems your code is using collision channels as a broad way to tell if it’s a vehicle/landscape interaction. I think that might work for what I’m doing, but how does what you’re doing differ from the docs, or does it?

Finally, what files are you putting these in? For me, the first two chunks of code are in a custom World Settings as used here. Where would I put the startup module?

Thank you. This gives me a few things to test with.