Ignore physics collision with specific actors?

I’m trying to get it so a physics actor can ignore specific actors, but I can’t find any ways to do it. IgnoreActorWhenMoving doesn’t affect physics, so that won’t do. Any ideas?

Also, collision channels won’t do, as there are only 32 available to use. I intend to use more than 32 groups of actors to ignore collisions

first, make sure you are using PhysX engine, then add PhysX and APEX to your project’s dependency module, create a new subclass of AWorldSettings, your class may look like this:

UCLASS()
class UEPORTAL_API ANewWorldSettings : public AWorldSettings
{
	GENERATED_BODY()

public:
	ANewWorldSettings(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); // don't forget Super(ObjectInitializer )

public:
	struct IgnorePair
	{
		TWeakObjectPtr<USceneComponent> obj1;
		TWeakObjectPtr<USceneComponent> obj2;
	};
private:
	
	TArray<IgnorePair> ignoreComponents;
public:
	const TArray<IgnorePair>& GetIgnoreComponents();

	bool IgnoreBetween(USceneComponent* a, USceneComponent* b);
	
	bool RemoveIgnoreBetween(USceneComponent* a, USceneComponent* b);
};

in the .cpp file, you need to add two include files “Engine/World.h” and “Physics/PhysicsFiltering.h”. In the constructor of you new WorldSettings class, set GSimulationFilterShader to your own filter function.
you function may declare like this:

    static PxFilterFlags PhysXSimFilterShaderPortal(PxFilterObjectAttributes attributes0, PxFilterData filterData0,
    	PxFilterObjectAttributes attributes1, PxFilterData filterData1,
    	PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize);

PxFilterObjectAttributes ::word2 contains component’s unique id which can be used to identify a specific component, check if attributes0 and attributes1 are contained in you WorldSetting’s ignoreComponents array.
you code may like this:

static PxFilterFlags PhysXSimFilterShaderPortal(PxFilterObjectAttributes attributes0, PxFilterData filterData0,
	PxFilterObjectAttributes attributes1, PxFilterData filterData1,
	PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{

	ANewWorldSettings* settings = nullptr;
	if (AYouCharacterClass::currentWorld && AYouCharacterClass::currentWorld->GetWorldSettings())
	{
		settings = Cast<ANewWorldSettings>(AYouCharacterClass::currentWorld->GetWorldSettings());
	}
	if (settings != nullptr)
	{
		const auto& ignoreComponents = settings->GetIgnoreComponents();

		for (int i = 0; i < ignoreComponents.Num(); ++i)
		{
			const auto& pair = ignoreComponents[i];
			if (pair.obj1.IsValid() && pair.obj2.IsValid())
			{
				if ((pair.obj1->GetUniqueID() == filterData0.word2 && pair.obj2->GetUniqueID() == filterData1.word2) ||
					(pair.obj2->GetUniqueID() == filterData0.word2 && pair.obj1->GetUniqueID() == filterData1.word2))
				{
					return PxFilterFlag::eKILL;
				}
			}
		}
	}

        ...Other Part...

}

the other part of the filter you can copy code from PhysXSimFilterShader() in PhysScene_PhysX.cpp.
AYouCharacterClass can be any UObject class, make sure you will create its instance after the world initialized and do not destroy it unitl the world destroyed. You can set the static member currentWorld by using AYouCharacterClass::GetWorld() in AYouCharacterClass::BeginPlay() method. Do not use GEngine->GetWorld() instead of AYouCharacterClass::currentWorld in the filter otherwise you will get a null value.
then implement add and remove methods. You can get a instance reference of WorldSettings by using GetWorld() methoed of UObjects which will be create in this world (not GEngine->GetWorld(), because the instance of UEngine attached to no world), and cast to your WorldSettings class.
if you want to use add and move method in BP, create a BlueprintCommonFunction class and add a static add method and a static remove methed like this:

UFUNCTION(BlueprintCallable, Category = YourCategory, meta = (WorldContext = WorldContextObject))
         static bool IgnoreBetween(UObject * WorldContextObject, USceneComponent* a, USceneComponent* b);

UFUNCTION(BlueprintCallable, Category = YourCategory, meta = (WorldContext = WorldContextObject))
         static bool RemoveIgnoreBetween(UObject * WorldContextObject, USceneComponent* a, USceneComponent* b);

then in .cpp file, by using UWorld * World = GEngine->GetWorldFromContextObject(WorldContextObject) you can get the current world, then you can get the worldsettings.

finally, set the default world setting classes to your world setting class in project settings.

CharacterMovement has their own physics logic, so you if you just add character’s collision and some other physics object to the ignoreComponents array pair by pair, the physic body will be affected by your character when your character is moving, but if you don’t move your character, just make the character’s ignore physics objects move to the character, the physics objects won’t be affected by the character, but the character will be still affected by the physics objects. Override CharacterMovement class or use IgnoreActorWhenMoving() method to avoid this problem
Camera spring arm has their own physics logic too, if you want to get correct result, you need to override SpringArmComponent class.

1 Like