PhysX 3.2中的场景查询(2)-过滤

来源:互联网 发布:win10 v1703新手优化 编辑:程序博客网 时间:2024/06/18 08:44

场景查询,Scene Query,是物理引擎被非常广泛使用的一个功能,帮助我们查询到感兴趣的物体。在查询过程中,有一个事情非常重要,那就是如何过滤掉我们不感兴趣的物体,减少不必要的计算量--毕竟很多时候,我们的查询都是目的性很强的,只对某些类别的物体感兴趣,比如,计算一颗手雷爆炸伤害的时候,我们通常只需要查询出伤害范围内的动态物体即可,而对静态物体施加伤害没什么意义。这一篇中,我们就说说PhysX 3.2中场景查询的过滤。

 

PhysX中,场景查询可以有Raycast,Sweep,和Overlap检测三类,同时,这些查询又可以组织起来以批处理的方式的执行(Batch Query)。从场景查询过滤的角度看,过滤的过程与是哪一类查询没有关系,而与是单次执行,还是批处理执行有关。也就是说,正如我们在所有Raycast,Sweep和Overlap相关的API里面看到的这样的参数声明:

raycast*/sweep*/overlap*(        ...        const PxSceneQueryFilterData& filterData = PxSceneQueryFilterData(),        PxSceneQueryFilterCallback* filterCall = NULL,        ...);

对于单次执行的查询,不论是Raycast,还是Sweep或者Overlap查询,过滤的逻辑都是一样的;但是对于批处理的查询,处理方式则不一样,比单次查询要少一些步骤。

 

首先,我们先看单次执行的时候,过滤是如何执行的。在开始具体说明之前,有必要了解filterData和filterCallback的定义:

struct PxSceneQueryFilterFlag{enum Enum{eSTATIC= (1<<0), //查询静态物体eDYNAMIC= (1<<1), //查询动态物体 ePREFILTER= (1<<2), //定义prefilter过滤函数 ePOSTFILTER= (1<<3), //定义postfilter过滤函数 eMESH_MULTIPLE= (1<<4), //对于mesh,返回所有结果 eBACKFACE= (1<<5),//NOT CURRENTLY SUPPORTED};};struct PxSceneQueryFilterData{PX_INLINE PxSceneQueryFilterData() : flags(PxSceneQueryFilterFlag::eDYNAMIC | PxSceneQueryFilterFlag::eSTATIC) {}PX_INLINE PxSceneQueryFilterData(const PxFilterData& fd, PxSceneQueryFilterFlags f) : data(fd), flags(f) {}PX_INLINE PxSceneQueryFilterData(PxSceneQueryFilterFlags f) : flags(f) {}PxFilterData data;PxSceneQueryFilterFlags flags;};class PxSceneQueryFilterCallback{public:virtual PxSceneQueryHitType::Enum preFilter(const PxFilterData& filterData, PxShape* shape, PxSceneQueryFilterFlags& filterFlags) = 0;virtual PxSceneQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxSceneQueryHit& hit) = 0;virtual ~PxSceneQueryFilterCallback() {}};


通过上面的定义,我们可以看到,一个filterData包含两个域:PxFilterData类型的data和PxSceneQueryFilterFlags类型的flags。看到pxFilterData我们也许会觉得眼熟:这个不是在碰撞过滤中也出现过吗?是的没错,正是它。这里的过滤,也需要用到它。

对于flags,则正如其每一个标志位后面的注释写到的,会定义这一次查询,返回的结果以及是否需要用到过滤函数。

这样,filterCallback就很好理解了--它负责定义prefilter和postfilter这两个过滤函数。

 

有了上面这些基础概念,再来看PhysX SDK处理单次场景查询的流程,就非常好理解这些东西SDK是如何使用的了。单次场景查询的流程精简一下,我们可以当成这样的:

  对于需要处理的shape,进行初步计算是否会检测到 -- 是 --> 用filterData和prefilter函数判断是否需要保留-- 是 --> 计算详细的碰撞点数据--> 用postfilter函数决定这一步该如何处理这个shape

*如果某一步骤的判断结果是"否“的话,这个shape就会被忽略掉。

上面的这些步骤中,第一步,会使用PxSceneQueryFilterFlag::eSTATIC和PxSceneQueryFilterFlag::eDYNAMIC初步判断是否需要处理这个shape,比如,如果flags只要求处理eDYNAMIC类型的物体,那么静态物体这一步就会直接被过滤掉。

 

第二步,对filterData的使用规则是这样的:

a.如果传入的filterData每一个数据域都为0,进入prefilter(如果flags设置ePREFILTER)判断;

b.否则,用shape的queryFilterData(可以通过PxShape::setQueryFilterData设置)与传入的filterData相与,如果结果不为0,进入prefilter(如果flags设置ePREFILTER)判断,否则放弃这个shape。

进入prefilter后,就是我们自己实现的判断逻辑,然后根据返回值来告诉PhysX SDK,是否需要保留这个结果。如果返回PxSceneQueryHitType::eTOUCH 或者PxSceneQueryHitType::eBLOCK,就表示需要暂时保留这个shape,返回PxSceneQueryHitType::eNONE则放弃这个shape。

 

到postfilter函数这一步,跟prefilter函数类似,PhysX SDK也是通过判断flags是否设置了ePOSTFILTER来决定是否调用这个函数,同样的也是根据它的返回值来决定是否保留这个shape。

 

到这里,我们介绍的是单次查询时,PhysX SDK是如何执行过滤的。对于批处理查询,过程会省事一些。PhysX SDK会忽略filterData的判断,在判断是否需要进行详细碰撞点信息的计算时,会直接进入prefilter。

 

原创粉丝点击