欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

physx中判断actor是否会发生碰撞

程序员文章站 2024-03-16 15:43:52
...

一、物理碰撞模拟方法

通过模拟一个真实的碰撞,但是不体现碰撞的特性,通过回调的方式来获取到对应的actor的指针来判断是否碰撞,但是要忽略掉当前的碰撞。

  1. 设置分类

    const PxFilterData collisionGroupIgnore(0, 0, 0, 1); // 分类自己怎么定义都可以
    
  2. 设置形状shape中的分类,方便在filtershape函数中做过滤

    PxRigidDynamic* createIgnoreDynamic(const PxTransform& t, const PxGeometry& geometry, const PxVec3& velocity = PxVec3(0))
    {
    	PxRigidDynamic* dynamic = PxCreateDynamic(*gPhysics, t, geometry, *gMaterial, 10.0f);
    
    	dynamic->userData = new int;
    
    	int shapeNb = dynamic->getNbShapes();
    	cout << "shapeNb:" << shapeNb << endl;
    	PxShape * shape = nullptr;
    	dynamic->getShapes(&shape, 1);
    	if (shape) {
    		cout << "shape is not null" << endl;
    		// 设置shape的FilterData,用在filtershape做匹配
    		shape->setSimulationFilterData(collisionGroupIgnore); 
    	}
    	else {
    		cout << "shape is null" << endl;
    	}
    		
    	memcpy(dynamic->userData, &userid, sizeof(int));
    	userid++;
    	
    	// 场景中添加零件
    	gScene->addActor(*dynamic);
    	return dynamic;
    }
    
    
    
    
  3. 设置filterShader的回调,从此处可以获取到碰撞的actor,返回值设置PxFilterFlag::eKILL即可放弃此次碰撞。

    class ContactFilterCallback : public PxSimulationFilterCallback {
    
    
    public:
    	virtual PxFilterFlags pairFound(
            PxU32 pairID, 
            PxFilterObjectAttributes attributes0, 
            PxFilterData filterData0, 
    		const PxActor* a0, 
            const PxShape* s0, 
    		PxFilterObjectAttributes attributes1, 
            PxFilterData filterData1, 
    		const PxActor* a1, 
            const PxShape* s1, 
            PxPairFlags& pairFlags) override
    	{
    		cout << "pairFound !!!!!!!!!" << endl;
    		cout << "pairFound actor0:" << *(int *)(a0->userData) << " actor1:" << *(int *)(a1->userData) << endl;
    		//return PxFilterFlag::eKILL; // 将该碰撞事件丢弃,此时就没有碰撞效果了
    		return PxFilterFlag::eSUPPRESS; // 对象的边界体积重叠,或者直到其中一个碰撞对象的过滤相关数据发生更改,就忽略该碰撞对
    	}
    
    
    	virtual void pairLost(PxU32 pairID, PxFilterObjectAttributes attributes0, PxFilterData filterData0, PxFilterObjectAttributes attributes1, PxFilterData filterData1, bool objectRemoved) override
    	{
    		
    	}
    
    
    	virtual bool statusChange(PxU32& pairID, PxPairFlags& pairFlags, PxFilterFlags& filterFlags) override
    	{
    		return false;
    	}
    
    };
    
    
    ContactFilterCallback gContactFilterCallback;
    
    
  4. 设置场景过滤条件函数

    在场景配置中设置过滤函数:sceneDesc.filterShader = filterShader;

    static PxFilterFlags filterShader(
    	PxFilterObjectAttributes attributes0,
    	PxFilterData filterData0,
    	PxFilterObjectAttributes attributes1,
    	PxFilterData filterData1,
    	PxPairFlags& pairFlags,
    	const void* constantBlock,
    	PxU32 constantBlockSize)
    {
    	// 默认对所有为过滤的碰撞产生默认回调
    	pairFlags	= PxPairFlag::eCONTACT_DEFAULT;
    	pairFlags  |= PxPairFlag::eNOTIFY_TOUCH_FOUND;	// 普通的触碰,调用回调
    	if (filterData0 == collisionGroupIgnore || filterData1 == collisionGroupIgnore)
    	{
    		cout << "filterShader this is ignore shape" << endl;
    		return PxFilterFlag::eCALLBACK; // 调用filterShader的回调
    	}
    
    	pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT;  // 检测到CCD碰撞的时候
    	pairFlags |= PxPairFlag::eNOTIFY_TOUCH_CCD;		// 触碰且CCD,调用回调
    	pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;	// 普通的触碰,调用回调
    	return PxFilterFlag::eDEFAULT;
    }
    
    
    
  5. 设置场景过滤函数的回调

    sceneDesc.filterCallback = &gContactFilterCallback;

  6. 运行调试即可

二、通过Geometry和Tranform来判断是否会出现碰撞

在physx中,有通过geometry+transform的api来获取两个几何体是否出现内嵌,我们可以通过这种方式来获取两个actor是否回发生碰撞。

physx里面有两种,一种只判断内嵌,一种是判断内嵌的深度,api分别如下

// 判断是否内嵌
bool PxGeometryQuery::overlap(const PxGeometry & geom0,
const PxTransform & pose0,
const PxGeometry & 	geom1,
const PxTransform & pose1 
);


// 判断是否内嵌,并求出内嵌深度
bool PxGeometryQuery::computePenetration	(	PxVec3 & 	direction,
PxF32 & 	depth,
const PxGeometry & 	geom0,
const PxTransform & 	pose0,
const PxGeometry & 	geom1,
const PxTransform & 	pose1 
)	
    

调用方式如下

int myOverlap(PxRigidActor * actor, PxGeometry &geom, PxTransform &trans)
{
	if (!actor) {
		cout << "actor is null" << endl;
		return -1;
	}
	bool isOverlapping = false;
	PxTransform pole = actor->getGlobalPose();
	const PxU32 numShapes = actor->getNbShapes();
	if (numShapes <= 0){
		cout << "Shape num is <= 0" << endl;
		return -1;
	}
	PxShape** shapes = (PxShape**)malloc(sizeof(PxShape*)*numShapes);
	actor->getShapes(shapes, numShapes);
	for (PxU32 i = 0; i < numShapes; i++)
	{
		PxShape* shape = shapes[i];
		cout << "shape[" << i << "]:" << shape->getGeometryType() << endl;;
		PxGeometry &geometry = shape->getGeometry().any();
		isOverlapping = PxGeometryQuery::overlap(geometry, pole, geom, trans);
		if (isOverlapping) {
			cout << "myOverlap isOverlapping:" << isOverlapping << endl;
			break;
		}
		cout << "myOverlap isOverlapping:" << isOverlapping << endl;
	}
	free(shapes);
	return isOverlapping;
}


int myOverlap(PxRigidActor * actor0, PxRigidActor * actor1)
{
	if (!actor0 || !actor1) {
		cout << "actor is null" << endl;
		return -1;
	}

	PxTransform pole0 = actor0->getGlobalPose();
	PxTransform pole1 = actor1->getGlobalPose();
	const PxU32 numShapes0 = actor0->getNbShapes();
	const PxU32 numShapes1 = actor1->getNbShapes();
	if (numShapes0 <= 0 || numShapes1 <= 0) {
		cout << "test Shape num is <= 0" << endl;
		return -1;
	}
	PxShape* shapes0 = NULL;
	actor->getShapes(&shapes0, 1);
	PxShape* shapes1 = NULL;
	actor->getShapes(&shapes1, 1);

	PxGeometry &geometry0 = shapes0->getGeometry().any();
	PxGeometry &geometry1 = shapes1->getGeometry().any();

	bool isOverlapping = PxGeometryQuery::overlap(geometry0, pole0, geometry1, pole1);
	cout << "testShapeGetGeometry isOverlapping:" << isOverlapping << endl;

	return isOverlapping;
}
相关标签: c/c++ physx physx