Page 1 of 1

Any input on PhysX collision callbacks?

Posted: Mon Mar 12, 2018 6:56 am
by chriscalef
(Looking at you @ Timmy)

I just implemented some rocket PhysicsShapes for my attack helicopter, and have got them exploding on a destroy() timer, but would really prefer a collision callback. Started digging into it, first hoping I could just do a Torque onCollision, but found that to be a ShapeBase function which doesn't work for GameBase.

Then found this old thread:

https://www.garagegames.com/community/f ... ead/130395

But after poking around a bit, that thread looked pretty outdated, and I thought I should really ask Timmy about this before I burn any more brain cells. :-) My use case is: I have rockets with physx primitives attached, I would like to collide them with the ground plane or other physics shapes, and on collision call destroy() and blow some shit up.

Re: Any input on PhysX collision callbacks?

Posted: Mon Mar 12, 2018 7:25 am
by Timmy
Check out here @ chriscalef http://docs.nvidia.com/gameworks/conten ... ction.html, the PxSimulationEventCallback is what you want. Works along the lines of that old physx 2.x method in that thread you posted

Re: Any input on PhysX collision callbacks?

Posted: Mon Mar 12, 2018 7:50 am
by chriscalef
Ah, very interesting ^^^ thank you.

Re: Any input on PhysX collision callbacks?

Posted: Tue Mar 13, 2018 6:15 pm
by chriscalef
Right, now this is starting to ring some bells... I had collision callbacks working fine in PhysX 2.x, but do remember taking one look at the new system in 3.x and deciding to come back to that later. :-)

But "later" is now, so... gave it a pretty good try last night. It seems like I did all the things I should have to do, but am still failing to get a call to my onContact() function.

What I did:

1) Added inheritance from PxSimulationEventCallback to my Px3World class, like so:

Code: Select all

class Px3World : public PhysicsWorld, public physx::PxSimulationEventCallback
2) Added the following function definitions/declarations to keep up with the virtuals:

Code: Select all

virtual void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs); virtual void onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count) {} virtual void onConstraintBreak(physx::PxConstraintInfo*, physx::PxU32) {} virtual void onWake(physx::PxActor**, physx::PxU32) {} virtual void onSleep(physx::PxActor**, physx::PxU32) {}
3) Defined a new filterShader function, like so:

Code: Select all

static physx::PxFilterFlags MegamotionFilterShader( physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0, physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1, physx::PxPairFlags& pairFlags, const void* constantBlock, physx::PxU32 constantBlockSize) { pairFlags = physx::PxPairFlag::eCONTACT_DEFAULT; // trigger the contact callback for pairs (A,B) where // the filtermask of A contains the ID of B and vice versa. if ((filterData0.word0 & filterData1.word1) || (filterData1.word0 & filterData0.word1)) { pairFlags |= physx::PxPairFlag::eNOTIFY_TOUCH_FOUND; return physx::PxFilterFlag::eNOTIFY; } return physx::PxFilterFlag::eDEFAULT; }
You may note that I changed the SampleSubmarine version of this from a && to a || when it comes to the word0/word1 bit, because I am only telling my rockets to respond to the rest of the world, but not bothering to tell the rest of the world they have to respond to rockets. That seemed a little silly, and it seemed like right here was the only place it mattered... but I also tried just setting the filterShader up to send an eNOTIFY every damn time no matter what, and still didn't get any response.

4) Attached that filterShader to my sceneDesc object, like so:

Code: Select all

sceneDesc.filterShader = MegamotionFilterShader;
5) Added a new category to the Px3CollisionGroup enum, to cover my explosive objects:

Code: Select all

enum Px3CollisionGroup { PX3_DEFAULT = BIT(0), PX3_PLAYER = BIT(1), PX3_DEBRIS = BIT(2), PX3_TRIGGER = BIT(3), PX3_EXPLOSIVE = BIT(4), };
6) Assigned my rocket shapes to have that collision group as word0, and PX3_DEFAULT as word1.

7) Defined my onContact function in Px3World.cpp, for starters just to try to kick out a console message to let me know we're getting anything:

Code: Select all

void Px3World::onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs) { Con::printf("WE HAVE A CONTACT!!!"); for (physx::PxU32 i = 0; i < nbPairs; i++) { const physx::PxContactPair& cp = pairs[i]; if (cp.events & physx::PxPairFlag::eNOTIFY_TOUCH_FOUND) { Con::printf("WE HAVE A ROCKET CONTACT!!!"); } } }
Now, given all of the above, I would presume that whenever my filter shader sets a pair flag to eNOTIFY_TOUCH_FOUND, and/or (?) returns a value of eNOTIFY, that my onContact function should get a callback.

So far, no dice. Anything you can see that I might have missed?

Re: Any input on PhysX collision callbacks?

Posted: Tue Mar 13, 2018 6:38 pm
by chriscalef
AHA!

Hehe, google is my friend. Turns out the missing ingredient was this:

Code: Select all

sceneDesc.simulationEventCallback = this;
(With "this" being my Px3World object.)

Still many details to resolve, but the function is getting called, so we got a foot in the door anyway. :D

Re: Any input on PhysX collision callbacks?

Posted: Wed Mar 14, 2018 8:30 am
by chriscalef
Well, just to follow up, I got my rockets to explode on contact, but no thanks to all the fancy PhysX FilterShader logic, so far. The only useful output I've been able to get out of my custom filter is to always report all collisions to my callback function, at which point I can make sense of them in Torque.

While I did manage to construct a case where a rocket intersection with ground found a word0/word1 match and actually reported to me based on that, it was only in an empty world where I dropped my rocket onto the groundplane with no forward velocity. This could probably be debugged on the PhysX side, but time is precious, so for now I'm just setting things up to always notify. I'm not running a giant world simulation, so I don't think performance at this layer is going to be a major factor.

But anyway, back in my onContact function, it is possible to convert the PhysX actors' userData pointers back into sceneObjects and then PhysicsShapes, and from there get my shape IDs from my database and decide if we are rockets or not, and then destroy and cause ragdolls in nearby humanoids if yes. So fundamental objective has been met.

Re: Any input on PhysX collision callbacks?

Posted: Wed Mar 14, 2018 12:58 pm
by Timmy
This weekend i'll try and set aside a few hours to do up a demo for ya showing usage of the filter system and callback stuff, can't promise but will try ;) . If you don't already use it you will need this PR though https://github.com/GarageGames/Torque3D/pull/2186 (i'm sure it will get accepted one day into the main repo). Will let ya know how i get on.

Re: Any input on PhysX collision callbacks?

Posted: Thu Mar 15, 2018 2:44 am
by chriscalef
Cool, thanks Timmy! No worries if you can't get to it, for my limited performance needs I think my callback-heavy solution is going to be fine, but it would still be nice to know how to do it the right way.

Re: Any input on PhysX collision callbacks?

Posted: Thu Mar 15, 2018 9:21 am
by Timmy
What ya want to do is to tie it into using this https://github.com/GarageGames/Torque3D ... UserData.h

Re: Any input on PhysX collision callbacks?

Posted: Fri Mar 16, 2018 3:19 am
by chriscalef
Huh, yeah I found that class and figured out how to use it to get back to my sceneObject in my onContact function. I don't understand what to do with the Signal type, however.

Here is my current attempt at an onContact class. I also got confused re: the failure of dynamic_cast to cast my void userData pointer into a PhysicsUserData pointer, but static_cast seemed to work so I went with that.

As you can see, all I'm doing for now is testing to see if either of the shapes in the collision is using my rocket shapeID, and if so destroying it.

Code: Select all

void Px3World::onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs) { PhysicsShape *shape0=NULL, *shape1=NULL; PhysicsUserData *user0, *user1; physx::PxActor *actor0, *actor1; actor0 = pairHeader.actors[0]; actor1 = pairHeader.actors[1]; void *userData0 = actor0->userData; void *userData1 = actor1->userData; user0 = static_cast<PhysicsUserData *>(userData0); user1 = static_cast<PhysicsUserData *>(userData1); shape0 = dynamic_cast<PhysicsShape *>(user0->getObject()); shape1 = dynamic_cast<PhysicsShape *>(user1->getObject()); if (shape0) { if (shape0->mShapeID == 23) shape0->destroy(); } if (shape1) { if (shape1->mShapeID == 23) shape1->destroy(); } }