Jump to content

Any input on PhysX collision callbacks?


chriscalef

Recommended Posts

(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/forums/viewthread/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.

Link to comment
Share on other sites

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:

 

class Px3World : public PhysicsWorld, public physx::PxSimulationEventCallback

 

2) Added the following function definitions/declarations to keep up with the virtuals:

 

	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:

 

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:

 

    sceneDesc.filterShader = MegamotionFilterShader;

 

5) Added a new category to the Px3CollisionGroup enum, to cover my explosive objects:

 

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:

 

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?

Link to comment
Share on other sites

AHA!


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

 

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

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();
}
}

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...