给物体创建射线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即可。