[Question/Request] Change vehicle wheels friction at runtime

I’ve spent quite a long while finding a solution for that. What I found is that dynamic and static friciton can be modified via FContactModifyCallback in C++ code. You set up a callback function that will be called by PhysX when two objects collide. You can then, within that callback modify the friction properties. This way I can even control friction on per object basis.

Create a class with a proper callback:

class FPhysicalContactsModifier : public FContactModifyCallback
{
    public:

    FPhysicalContactsModifier();
    ~FPhysicalContactsModifier();

    void onContactModify(
                physx::PxContactModifyPair* const pairs, 
                physx::PxU32 count) override;
};

Code to setup the callback:

auto* PhysicsScene = GetWorld()->GetPhysicsScene()
if (auto* PhysXScene = PhysicsScene->GetPxScene())
{
       SCOPED_SCENE_WRITE_LOCK(PhysXScene);
        
       // Note: to enable contact-modification on given body, 
       // call: BodyInstance->SetContactModification(true);
       PhysXScene->setContactModifyCallback(&PhysicalContactsModifier);
}

You also have to enable contact-modification for each BodyInstance you are interested in:

BodyInstance->SetContactModification(true);

And then in FPhysicalContactsModifier::onContactModify you can change friction properties of a specific contact between two physical actors.

Pair.contacts.setStaticFriction(contactIdx, 0.0f);
Pair.contacts.setDynamicFriction(contactIdx, 0.0f);

You then probably want to know which UE4 actors are colliding. You can learn that by translating PxActor* to AActor*:

AActor* PhysicsUtils::PxActorToActor(const physx::PxRigidActor& PxActor)
{
    if (FPhysxUserData::IsGarbage(PxActor.userData))
        return nullptr;

    auto* BodyInstance = FPhysxUserData::Get<FBodyInstance>(PxActor.userData);
            
    if (BodyInstance && BodyInstance->OwnerComponent.IsValid())
    {
        auto* OwnerActor = BodyInstance->OwnerComponent->GetOwner();

        return OwnerActor;
    }

    return nullptr;
}
1 Like