在physx中创建射线raycase,并获取碰撞点

6 篇文章 0 订阅

给物体创建射线ray

通过raycastSingle函数去获取发射的射线是否会碰到物体,不需要特殊处理的可以不使用回调。

不用回调的版本

// origin是起点, unitDir是方向
int RayCaseSingle(PxVec3 &origin, PxVec3 &unitDir)
{
	PxRaycastHit hitInfo; // 返回的点,法向量信息等都在这里
	PxReal maxDist = FLT_MAX; // 最大射线距离
	//PxHitFlag::eMESH_ANY //返回任一次的射线与mesh的交互,因为是raycaseSingle,设不设置这个无所谓
	// 获取点, 法向量,还有UV信息
	PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV ;
	
	bool isRayHit = PxSceneQueryExt::raycastSingle(*gScene,
		origin,
		unitDir,
		maxDist,
		hitFlags,
		hitInfo
	);
	if (isRayHit) {

		cout << "=====hitInfo.x: " << hitInfo.position.x << " y: " << hitInfo.position.y << " z: " << hitInfo.position.z << endl;
		PxVec3 pose = actor->getGlobalPose().p;
		cout << "actor x:" << pose.x << " y:" << pose.y << " z:" << pose.z << endl;
	}
	else
		cout << "rayHit is not hit" << endl;

	return isRayHit;
}

带回调版本的射线

因为我设置的是从物体的身体里面发射出来的,所以我需要特殊处理一下,将该物体过滤一下,让这个物体对于射线而言是一个忽略状态。

  • 设置一个用于全局过滤的变量
const PxFilterData collisionGroupIgnore(0, 0, 0, 1); // 用于忽略物体,内容自定义
  • 下面是回调配置
class  PxSenceRayCallback : public PxSceneQueryFilterCallback
{

public:
	virtual PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override
	{
		cout << "hit preFilter" << endl;
		if (shape->getSimulationFilterData() == collisionGroupIgnore)
		{
			cout << "ignore data" << endl;
			return PxQueryHitType::Enum::eNONE; //should ignore this shape
		}
			
		return PxQueryHitType::Enum::eBLOCK;

		//eNONE   //should ignore this shape
		//eTOUCH // 要使用这个要有缓冲区
		//eBLOCK // 射线发出有hit需要返回用这个
	}

	virtual PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override
	{
		cout << "hit postFilter" << endl;

		return PxQueryHitType::Enum::eBLOCK;
	}

};

PxSenceRayCallback gSenceRay;

  • 下面是封装好的调用api
bool GetShapeSimulationFilterData(PxRigidActor *actor, PxFilterData &filterdata)
{
	const PxU32 numShapes = actor->getNbShapes();
	if (numShapes <= 0) {
		return false;
	}
	PxShape* shapes = NULL;
	actor->getShapes(&shapes, 1);

	filterdata = shapes->getSimulationFilterData();
	return true;
}

bool SetShapeSimulationFilterData(PxRigidActor *actor, const PxFilterData &filterdata)
{
	const PxU32 numShapes = actor->getNbShapes();
	if (numShapes <= 0) {
		return false;
	}
	PxShape* shapes = NULL;
	actor->getShapes(&shapes, 1);

	shapes->setSimulationFilterData(filterdata);
	PxFilterData oldFilterdata = shapes->getSimulationFilterData();
	return true;
}
// 此处使用actor进行传入是为了测试方便
int RayCaseSingle(PxRigidActor * actor, PxVec3 &unitDir)
{

	PxVec3 origin = actor->getGlobalPose().p ;
	PxRaycastHit hitInfo; // 返回的点,法向量信息等都在这里
	PxReal maxDist = FLT_MAX; // 最大射线距离
	PxU32 maxHits = 1; // 返回的最多命中个数
	
	//PxHitFlag::eMESH_ANY //返回任一次的射线与mesh的交互,因为是raycaseSingle,设不设置这个无所谓
	// 获取点, 法向量,还有UV信息
	PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV ;
	
	PxQueryFilterData filterdata = PxQueryFilterData();
	// 因为我是从actor的中心发出的射线,会碰到自身的actor,使用回调忽略掉自身的actor
	filterdata.flags |= PxQueryFlag::ePREFILTER; // 设置回调信息,可以用作特殊处理
	// 获取之前的filterdata暂存一下
	PxFilterData oldFilterdata;
	GetShapeSimulationFilterData(actor, oldFilterdata);
	// 设置碰撞忽略
	SetShapeSimulationFilterData(actor, collisionGroupIgnore);
	
	bool isRayHit = PxSceneQueryExt::raycastSingle(*gScene,
		origin,
		unitDir,
		maxDist,
		hitFlags,
		hitInfo,
		filterdata,
		&gSenceRay
	);
	if (isRayHit) {

		cout << "=====hitInfo.x: " << hitInfo.position.x << " y: " << hitInfo.position.y << " z: " << hitInfo.position.z << endl;
		PxVec3 pose = actor->getGlobalPose().p;
		cout << "actor x:" << pose.x << " y:" << pose.y << " z:" << pose.z << endl;
	}
	else
		cout << "rayHit is not hit" << endl;
	// 还原回来
	SetShapeSimulationFilterData(actor, oldFilterdata);
	return isRayHit;
}

你以为这样就结束了嘛?

有个小坑!!!!!

shape这个变量是一个坑,为什么这么说呢? 它使用下面这个接口创建的时候,不能使用setSimulationFilterData这个函数!!!!!!!!!!!!!!!!!!这个函数在过滤的时候,非常重要。 不过呢,使用userdata定义自己的结构代替也可以。

PX_FORCE_INLINE PxShape* PxPhysics::createShape	(	const PxGeometry & 	geometry,
const PxMaterial & 	material,
bool 	isExclusive = false,
PxShapeFlags 	shapeFlags = PxShapeFlag::eVISUALIZATION | PxShapeFlag::eSCENE_QUERY_SHAPE | PxShapeFlag::eSIMULATION_SHAPE 
)	

如果之前创建刚体是用的这种方法,那么setSimulationFilterData就会无法调用,会提示警告。
shared shapes attached to actors are not writable.

void createBody(const PxTransform& t, PxGeometry& geometry)
{
	PxShape* shape = NULL;
	// 创建出形状 
	shape = gPhysics->createShape(geometry, *gMaterial);
    PxRigidDynamic* dynamic = gPhysics->createRigidDynamic(t);
    dynamic->attachShape(*shape);
    PxRigidBodyExt::updateMassAndInertia(*dynamic, 10.0f);
    // 场景中添加演员
    gScene->addActor(*dynamic);
	shape->release();
}

需要使用setSimulationFilterData接口的话,请使用下面的方法创建

void createBody(const PxTransform& t, PxGeometry& geometry)
{
    // 最后一个参数也就是使用 PxRigidBodyExt::updateMassAndInertia(*dynamic, 10.0f);设置的第二个参数
	PxRigidDynamic* dynamic = PxCreateDynamic(*gPhysics, t, geometry, *gMaterial, 10.0f);
    // 场景中添加演员
    gScene->addActor(*dynamic);
	shape->release();
}

如果想要使用回调进行过滤,又无法使用setSimulationFilterData接口的情况下,在shape变量中有userdata指针,可以通过给他定义自己想要的结构或者数据, 然后在回调里面调用shape指针,判断使用自己设置好的userdata即可。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值