MagicPhysX icon indicating copy to clipboard operation
MagicPhysX copied to clipboard

No way to attach PxSimulationEventCallback / PxSimulationEventCallback

Open aguerrieri82 opened this issue 11 months ago • 3 comments

There is any way to implement PxSimulationEventCallback / PxSimulationEventCallback interfaces in c# to receive events / callbaks ?

I understand is not an easy task, I tried myself to rebuild the v-tables for PxContactModifyCallback / PxSimulationEventCallback interfaces without success (nothing is called back, no exceptions).

This what i've done so far:

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate void OnContactModifyDelegate(PxContactModifyPair* pairs, uint count);

_handler = (PxContactModifyCallback*)Marshal.AllocHGlobal(sizeof(PxSimulationEventCallback));

_handler->vtable_ = (void*)Marshal.AllocHGlobal(4 * sizeof(nint));
//first qword is 0, second is a pointer to the typeinfo, following the virtual functions. 
//No idea how to recover typeinfo descriptor pointer
((nint*)_handler->vtable_)[2] = Marshal.GetFunctionPointerForDelegate((OnContactModifyDelegate)OnContactModify);
((nint*)_handler->vtable_)[3] = Marshal.GetFunctionPointerForDelegate((VoidDelegate)Distructor);

aguerrieri82 avatar Mar 09 '24 19:03 aguerrieri82

I've been having the same issue, found out that the function PxSimulationFilterShader must also be set. However a variable sent to that function seems to be incorrectly set.

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate PxFilterFlags PxSimulationFilterShader(uint attributes0, PxFilterData filterData0, uint attributes1, PxFilterData filterData1, ref PxPairFlags pairFlags, IntPtr constantBlock, uint constantBlockSize);
    
static PxFilterFlags CustomFilterShader(uint attributes0, PxFilterData filterData0, uint attributes1, PxFilterData filterData1, ref PxPairFlags pairFlags, IntPtr constantBlock, uint constantBlockSize)
{
    return PxFilterFlags.Kill;
}

How the original physx version works is that you decide based on the attributes and filterdata what the PxPairFlags should be, in this case however pairFlags is a broken memory address.

Unfortunately we have to use a custom filter shader to properly assign the pairflags which if properly set calls the simulation event callback.

I have been at it for a while now, and still haven't been able to figure it out.

This is where I got the filter idea from NVIDIA Filter

NVIDIA Sim callback

You can enable the use of this contact modification callback by raising the flag PxPairFlag::eMODIFY_CONTACTS in the filter shader/callback (see PxSimulationFilterShader) for a pair of rigid body objects.

EDIT: The error i get with the pairflags variable is CORDBG_E_BAD_REFERENCE_VALUE

MartinPrograms avatar May 04 '24 14:05 MartinPrograms

Potential solution? https://github.com/EmbarkStudios/physx-rs/issues/145

Would have to make this in rust however, change the default there which would be sub optimal.

MartinPrograms avatar May 04 '24 14:05 MartinPrograms

Found it. I have On Contact working.

(small code dump about what I did) Creating the callbacks:

    var simcallback = new SimulationEventCallbackInfo();
        simcallback.collision_callback = (delegate* unmanaged[Cdecl]<void*, PxContactPairHeader*, PxContactPair*, uint, void>)Marshal.GetFunctionPointerForDelegate<CollisionCallback>(OnContactDelegateInstance).ToPointer();
        var callbackinfoithink = create_simulation_event_callbacks(&simcallback);
        sceneDesc.simulationEventCallback = callbackinfoithink;
        
        var thing = (delegate* unmanaged[Cdecl]<FilterShaderCallbackInfo*, PxFilterFlags>)Marshal.GetFunctionPointerForDelegate<CustomFilterShaderDelegate>(CustomFilterShaderInstance).ToPointer();
        enable_custom_filter_shader(&sceneDesc, thing, (uint)1);

And the actual callbacks:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void CustomFilterShaderDelegate(FilterShaderCallbackInfo* callbackInfo, PxFilterFlags filterFlags);
    
    static void CustomFilterShader(FilterShaderCallbackInfo* callbackInfo, PxFilterFlags filterFlags)
    {
        PxPairFlags flags = PxPairFlags.ContactDefault | PxPairFlags.NotifyTouchFound;
        
        callbackInfo->pairFlags[0] = flags;
    }
    
    public CustomFilterShaderDelegate CustomFilterShaderInstance = CustomFilterShader; // Assign the managed delegate to the unmanaged delegate instance
    
    
    
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    // public delegate*unmanaged[Cdecl]<void*, PxContactPairHeader*, PxContactPair*, uint, void> OnContactDelegate;
    public delegate void CollisionCallback(IntPtr userData, PxContactPairHeader pairHeader, PxContactPair contacts, uint flags);    

    static void OnContact(IntPtr userData, PxContactPairHeader pairHeader, PxContactPair contacts, uint flags)
    {
        // On Contact...
        // This took 7~ hours to get working.
Console.WriteLine("OnContact");
    }
    
    public CollisionCallback OnContactDelegateInstance = OnContact; // Assign the managed delegate to the unmanaged delegate instance

This is all based on the rust post from earlier, translated to C#. The 7 hours includes the hours before I found this issue.

MartinPrograms avatar May 04 '24 17:05 MartinPrograms