PhysX 3.2中的刚体模拟: TolerancesScale
在创建PhysX 3.2的PhysX SDK对象和PxScene对象的时候,我们会发现,跟PhysX 2.8时候相比,有一个多出来的参数特别醒目:
PX_INLINE physx::PxPhysics* PxCreatePhysics( physx::PxU32 version, physx::PxFoundation& foundation, const physx::PxTolerancesScale& scale, bool trackOutstandingAllocations = false, physx::PxProfileZoneManager* profileZoneManager = NULL); PX_INLINE PxSceneDesc::PxSceneDesc(const PxTolerancesScale& scale):
这个参数就是上面加粗的参数,PxTolerancesScale scale。这个参数干什么用的呢?
我们还是看看它的定义吧:
class PxTolerancesScale { public: /** brief The approximate size of objects in the simulation. */ PxReal length; /** brief The approximate mass of a length * length * length block. */ PxReal mass; /** brief The typical magnitude of velocities of objects in simulation. This is used to estimate */ PxReal speed; /** \brief constructor sets to default */ PX_INLINE PxTolerancesScale(); /** \brief Returns true if the descriptor is valid. \return true if the current settings are valid (returns always true). */ PX_INLINE bool isValid() const; };
从字面意思看,是SDK在模拟的时候,这个变量定义了容忍的各种变量数值的级别。但是要搞清楚这个问题,我们需要对刚体模拟的一些最基本的东西进行一番梳理:
首先,在物理世界中,有一个默认的加速度,施加给场景中的所有物体,这么说可能觉得弯弯绕的难听死了,呵呵,但是如果说是重力,那么大家就都明白了。在场景中的所有物体,都会受到重力的影响,而重力是多少呢?常用的是9.8?
没错,常用的是9.8,或者粗略一点,10,但是单位系统呢,哦,是m/s^2。
好的,暂且放下重力,再说下一个,看起来不太相关的东西,就是物体的大小。我们的编辑器中,都会有根据引擎设计的初衷而与生俱来就有的某个单位系统,这个单位系统,可以跟标准的国际单位制一致,也可以是按照一定比例的缩放,比如有的引擎是3个长度单位对应国际单位制中的1米,有的是10,有的是64,不一而足。
不一样的单位系统,就决定了创建出来的物体的大小就是完全不一样的,同样是一米大小的问题,对应到相应的引擎中,可以是3个长度单位,可以是10,也可以是64。
了解了这些,我们还要看看刚体的碰撞过程,当SDK检测到两个物体有重叠的空间之时(也就是有碰撞的时候),会如何来处理这检测到的碰撞呢?是所有的碰撞都义无反顾的生成弹开的力呢,还是为了更快的进入稳定状态,当物体之间的碰撞非常轻微的时候,直接忽略呢?PhysX SDK选择的是后者,并且通过PxSceneDesc::bounceThresholdVelocity定义什么样的相对速度,算是“非常轻微”。这个bounceThresholdVelocity,与scale相关。
还有根据碰撞点计算摩擦力的时候,如何合并相邻的碰撞点一起计算摩擦力的控制参数PxSceneDesc::contactCorrelationDistance,也与scale相关。
除了上面说到的这些,还有物体的质量、前面的文章中讲过的contactOffset和restOffset等,都会影响到模拟的表现。
---------------------------------------------------------------------------
上面的这些东西,虽然啰嗦,但是如果理解不透彻的话,会对如何合理的使用PxTolerancesSacle依然是一头雾水。我们创建的物理世界的时候,可以使用我们自己的单位系统,但是要让我们自己的单位系统创建出来的东西能够正常工作,最起码看起来是正常的,那么就需要合理的设置PxTolerancesScale中的参数,并且合理搭配其他能影响模拟表现的变量。具体来说:
Scale.length: 会影响PxSceneDesc::sweepEpsilonDistance的精度,两个Shape之间碰撞的判断精度(contact offset即两个shape嵌入深度,以及PxSceneDesc::contactCorrelationDistance)。
Scale.speed: 会影响对物体是否进入睡眠状态(sleep)的判断精度,以及碰撞是否足以导致反弹的判断精度(PxSceneDesc::bounceThresholdVelocity)。
Scale.mass: 暂时未使用,但是以后可能会使用。
如果以一个实例来说明使用的话,比如在某个引擎中,n个长度单位对应1m,那么,可以做这样的尝试:
scene.gravity.y = -9.8f*n;
Scale.speed = scene.gravity.y;
Scale.length = n;
同时,可以按照一定的百分比,比如2%或者3%来定义contactOffset和restOffse的大小,当然,restOffset取正还是取负,需要看游戏的设计需求了。
*这只是一个通用的实例,不一定适合所有的情况,但是如果发现在使用自己的单位系统后,即便是最普通的刚体模拟,也有奇怪或则不稳定的表现,那么就需要怀疑上面提到的这些变量的设置是否合适,并且逐一进行检查,找出原因。到现在为止,已经发现过因为contactOffset、restOffset或者gravity设置不合适,出现刚体抖动的问题了。