我所遭遇过的游戏中间件--PhysX
PhysX现在是Nvidia的物理中间件.其特点是简练且功能强大.当我最初拿到PHYSX的SDK时,就发现这个物理中间件比Havok要小很多,但该有的功能都有,甚至有软体softbody,这是Havok没有的功能.而后我便从Havok的坑跳到了PhysX的坑里.下面将我在PhysX里碰到的坑一一讲述下.
(1)Max导出插件
PhysX的Max导出插件做的不如Havok,最缺少的功能是无法对导出的模型进行矩阵变换.要知道Max的坐标系为Z轴向上右手坐标系,而游戏中的坐标系为Y轴向上的左手坐标系.并且,我这的美术在Max中建模时,会将模型放大100倍.那么导出的模型需要进行缩小.它的导出插件没有提供这一功能,我只好自己写,先说缩放,缩放碰到的最大的坑是,其惯性常量的缩放.惯性常量,这个东西物理课本上没有讲过啊.我以为惯性常量也应该缩小100倍的,后来发现转化出的刚体稳定性极差,有约束的刚体总会乱抖动.经过很长时间的纠结才发现惯性常量的缩放不是线性的变化.然后是Z轴向上右手坐标系到Y轴向上的左手坐标系的变换,这算是我写的最纠结的代码,本来变换原理很容易,只要将原始数据都乘上一个4*4变换矩阵就行.但这个变换矩阵很难找出来,因为我用我理论上求得的矩阵去处理,变换后的约束总是错的,很是奇怪,这矩阵我在自己的导出插件中使用过,没问题的.没办法,只好一个一个的试,试了一整天才将这个变换矩阵找出来.总之,到现在我也不知道为什么是这个矩阵.
(2)刚体的缩放
在PhysX中刚体是不能有缩放的,但刚体有为其设置矩阵的接口,设置给他的矩阵可以有缩放信息.但如果你真给刚体设置了有缩放信息的矩阵就等着吧,问题早晚会被发现的.刚体对传进去的变化矩阵只提取位置和旋转.出于对性能的考虑,PhysX不会对缩放进行处理,如果有了缩放则会导致其旋转的解析出错.缩放的变化越大,其旋转误差的角度也就越大.不过有个基于PhysX的中间件Apex是可以对布料中的变换矩阵传入缩放信息的.有关Apex我将在下一篇文章中介绍.
(3)Ragdoll木偶
本来Ragdoll通常是用来模拟角色死亡后,顺着地形躺的.我在的项目是一个舞蹈类游戏,没有杀戮.但Ragdoll同样有用,用它来模拟辫子,项链以及某些布料.我想所有搞过物理的人都会碰到,刷帧率低时,刚体会乱飞的情况,这个除了提高刷帧率还真没有什么可解决的方法.另一个问题是,角色出现瞬移时,刚体也会乱飞,这时需要给Ragdoll加下是否为teleport的状态,当teleport为true时调用刚体的SetTransform()接口,否则调用刚体的MoveToPose()接口.
(4)PhysX的文件保存
PhysX的Max导出插件可以将刚体模型保存成3种格式的文件,它提供了开源的代码能够解析这三种格式.有个问题是,它保存的文件是整个场景,而我这的需求是,保存具体的形状,刚体和约束数据即可.而且导出的文件中都会有一个地平面的静态刚体.我先写了个工具,可以删除导出文件中不需要的数据.后来又读了下PhysX对文件的解析方式的代码,发现它代码写的真不怎么样.于是很蛋疼地自定义了一套文件格式,保存物理的形状,刚体和约束数据.代码写的也相当纠结,主要是引擎有了很大的改动.不过想想也是值得的,至少这是脱离了平台的物理数据,以后可以用到Bullet的物理系统里.
(5)PhysX的物理更新
PhysX的物理更新需要调用两个函数simulate和fetchResults,之所以要调用两个函数,是因为其多线程并行处理.我们可以在simulate和fetchResults之间插入一些与物理不相关的代码.这样有助于提高引擎效率.当然所带来的问题是simulate和fetchResults之间绝对不能添加与物理相关的操作,比创建删除个物理对象什么的,有很多次令人纠结的崩溃就是因为在某个深深地堆栈回调中做的物理操作.
(6)布料
单纯用PhysX做布料效果并不太好,我记得我做过一个DEMO,布料像皮筋一样有弹性,角色一动起来,布料就会一颤一颤的.不过刚才提到过有个基于PhysX的中间件Apex也是Nvidia出的,用它做布料效果不错,我将在下一篇文章中介绍.