http://www.cnblogs.com/mumuliang/archive/2011/06/02/2068453.html
倒数第二个参数,PxTolerancesScale, 是创建场景中的物体的默认Tolerances。
Note 与2.x不同的是,3.要求分配的内存是16位对齐(We now require that the memory that is returned be 16-byte aligned! )。windows上可以用 _aligned_malloc. 控制台系统(console systems)上的malloc()返回的已经是16位对其的空间,因此不许特别处理。
6 Basic Actors
然后就可以用这个材质创建个最简单的static geometry,地面。
略
1)for static and dynamic Actors:Spheres, Capsules, Boxes, ConvexMeshes
(although TriangleMeshes can be used as kinematics in scene queries)
创建 simulation object or Shape 的步骤:
然后是一个shape。描述sphere的geomety只需要半径足够了,第二个材质是必须要的。
Actor加完所有的shape以后,就计算mass和inertia。
用Shape设置初始速度,这是个linear velocity vector:
capsule的height默认是y方向的,要让Capsule沿X方向延伸,将其绕Z轴旋转90度。
3 Boxes
a, b , c代表其边长。
4 Convex Meshes
然后描述面上的点:
有了这些点PhysX SDK就可以计算出其余相关的数据。俺们把这个过程叫做cooking。接下来叫你如何用PhysX cook a Convex Mesh,and it is done through a Stream objects。
现在有了ConvexMesh,就可以用它创建一个Convex的Shape了。
5 Planes
每个样本(方格子)都有一个16位的整数值和2个材质(一个方格划分成2个三角面)。这是一种特殊的已经定义了的材质,PxHeightFieldMaterial::eHOLE. 如果你用float型描述高度(也木有关系?),there is the possibility to set the used scale later on with the Geometry. Since there are two ways to split a rectangle into two triangles, the split diagonal can be selected with the tesselation flag.
目前只支持提及的格式。eS16_TM?
接下来就可以用Geometry创建shape:
Heightfield也是static的.
如果是 multi-material的heightfields, 需用另一个函数来create Shape
7 Triangle Meshes
Triangle meshe是static. 但是可以用作kinematics。(譬如水面?)
Triangle meshe也可以缩放.
例如雪人中,有些会被雪球砸中分开。这需要设置一个PxSimulationFilterShader的pairFlags. 然后在可分离的shape被击中后在simulation filter function中做如下工作:
needsContactReport 是一个用来在每个shape的simulationFilterData中测试flags的工具函数helper function. 这些flags是一早在创建Shape时用setDetachable和setSnowball设置的。Contact notification is requested if one of the Shapes is detachable and the other is marked as a snowball. (迷惑 =“=)
Obviously, you need several PxGeometry types and a selection code if you don’t know in advance which kind of Shape you are going to detach. As usual the mass properties need to be set after adding Shapes to an Actor. And eventually you can release the old detaching Shape completely.
在突发情况(有外力情况?)下,PhysX 的dynamics slover(dynamic物体的计算器?)可能会没办法正确操作joint定义的Actor之间约束关系。这显然不太妙。你可以启用kinematic projection(运动投影?),它会尝试纠正。但Projection并非物理过程,它不会遵守动量守恒也不会管图形是否碰撞。实际应用中应该避免使用projection,但它在改善什么什么效果时很有用。-_-b
projection也是默认不可用的。启用方法如下,首先设置会引起joint被project的临界linear tolerance和angular tolerance,然后开启那啥constraint flag.
- if just a single degree of angular freedom is unlocked, the result is always equivalent to a revolute joint. It is recommended that if just one angular freedom is unlocked, it should be the twist degree, because the joint has various configuration options and optimizations that are designed for this case.
- if both swing degrees of freedom are unlocked but the twist degree remains locked, the result is a zero-twist joint. The x-axis of actor1 swings freely away from the x-axis of actor0 but twists to minimize the rotation required to align the two frames. This creates a kind of isotropic universal joint which avoids the problems of the usual ‘engineering style’ universal joint (see below) that is sometimes used as a kind of twist constraint. There is a nasty singularity at π radians (180 degrees) swing, so a swing limit should be used to avoid the singularity.
- if one swing and one twist degree of freedom are unlocked but the remaining swing is kept locked, a zero-swing joint results (often also called a universal joint.) If for example the SWING1 (y-axis rotation) is unlocked, the x-axis of actor1 is constrained to remain orthogonal to the z-axis of actor0. In character applications, this joint can be used to model an elbow swing joint incorporating the twist freedom of the lower arm or a knee swing joint incorporating the twist freedom of the lower leg. In vehicle applications, these joints can be used as ‘steered wheel’ joints in which the child actor is the wheel, free to rotate about its twist axis, while the free swing axis in the parent acts as the steering axis. Care must be taken with this combination because of anisotropic behavior and singularities (beware the dreaded gimbal lock) at angles of π/2 radians (90 degrees), making the zero-twist joint a better behaved alternative for most use cases.
- if all three angular degrees are unlocked, the result is equivalent to a spherical joint.
- The cylindrical joint (with axis along the common x-axis of the two constraint frames) is given by the combination:
d6joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
- the point-on-plane joint (with plane axis along the x-axis of actor0’s constraint frame) is given by the combination:
d6joint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eZ, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
- the point-on-line joint (with axis along the x-axis of actor0’s constraint frame) is given by the combination:
d6joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
d6joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
- 目标位置,在actor0的constraint frame中定义。target position, specified in actor0’s constraint frame
- 目标速度,也定义在actor0的constraint frame中。target velocity, specified in actor0’s constraint frame
- 弹性?spring
- 阻尼。damping
- 能提供的最大力。forceLimit - the maximum force the drive can apply
- 加速标志。acceleration drive flag
- 角速度,定义在actor0的constraint frame。An angular velocity target specified relative to actor0’s constraint frame
- 目标姿态。定义在同上。An orientation target specified relative to actor0’s constraint frame
- SLERP或扭摆drive的配置。drive specifications for SLERP (slerpDrive), swing (swingDrive) and twist (twistDrive):
- 弹性。spring - amount of torque needed to move the joint to its target orientation proportional to the angle from the target (not used for a velocity drive).
- 阻尼。damping - applied to the drive spring (used to smooth out oscillations about the drive target).
- 那啥。forceLimit - maximum torque applied when driving towards a velocity target (not used for an orientation drive)
- 那啥。acceleration drive flag
f = m*a (force = mass * acceleration) 力= 质量*加速度 0-0
如果是想立刻让一个物体运动,给它初速度是最直接的。还有个更直接的办法是设动量momentum,如果你不知道物体的质量的话,这种方法可能更方便, 只是要知道速度的话还得要质量。
- 注意 PxRigidDynamic::moveKinematic() 和 PxRigidBody::setGlobalPose() 的区别. setGlobalPose()也会将Actor移动到指定位置,但不会引起其他对象的变化。尤其是,它根本不会阻挡别的物体运动,而是会穿墙而过。但这个setGlobalPose()还是会被用到, 如果仅仅是想把某个东西移动到某个位置时。.
- kinematic actor是会推开别人的,如果有人挡道的话,但是其他物体不会反作用于kinematic物体。也就是说kinematic actor的出现,让其他dynamic actor表现为static actor或者kinematic actor. 譬如,一个dynamic豆腐会把冲过来的kinematic脑袋撞个坑?。
- kinematic 和 static actor之间木有相互作用和碰撞。
有两种方式查询场景中的碰撞collision:批处理batched和非批处理non-batched。非批处理查询又称single shot queries,使用PxScene类的接口,是PxScene的一项常规功能。批处理查询是使用PxBatchQuery对象,PS3上只有批处理查询一种方式。
Raycast queries
查询中用户定义的射线ray会与整个场景相交intersected with the whole scene。PhysX有三种射线:
- raycastAny
- raycastSingle
- raycastMultiple
查询碰撞collision时,返回的最主要的信息是一个布尔是非值,表示碰没碰上,若需获取更多信息,比如射线是不是穿过了什么之类的,就可以用raycastAny。至于交点的确切信息、相交的是个啥形状,这些都不是raycastAny关心的内容,它只关心一件事,是不是有击中发生(there was a hit)。人工智能中的视线查询(line-of-sight queries)就是一个典型应用。
raycastSingle比raycastAny先进一些,通过它可以知道第一个被击中的是个嘛。譬如说子弹击中的情形。
raycastMultiple是最高级的。ray会hit到的所有物体都可以得到。好比说穿甲子弹。
注意:* solid物体(sphere, capsule, box, convex)是封闭的closed(即它们包括它们的边界boundaries)
* plane是封闭的半空间 closed halfspace
* heightfield也是封闭的,并且是solid物体。
射线投射在solid物体上,射线是有终点的。射线ray和solid物体的相交intersection会引发一个击中报告hit report。
下表显示了不同物体对射线是否会产生hit report报告的反应是不同的。比如只要起点位于plane内部,即平面以下,无论射线终点在哪儿,也不会有plane被hit的report返回。
Sweep Queries
Queries中Shape会以一指定的方向扫sweep过去,并报告是否与场景Scene有碰撞collision。也有三种sweep方式:
- sweepAny
- sweepSingle
- sweepMultiple
它们的区别也和3种ray之间的区别一样。
目前支持sweep的形状Shape有box, sphere和capsule。
Overlap Queries
overlap query返回的是和场景发生碰撞的物体所接触到的其他物体。有两种overlap
- overapAny
- overlapMultiple
overlapAny 也叫placement API,特别适用于只知道场景的体积是不是空的情况。
overlapMultiple并不会在第一次hit后停下来,而是会返回其后所有被碰到的物体。
没有overlapSingle,因为没必要。overlap并没固定一个具体的方向,因此也就不能得到某个方向上的最近或最远,因此single木有存在的意义。(难道时间上也木有排序的意义么?)
overlap接受box,sphere和capsule三种形状。
Filtering
有几种方法可以把场景中不需要的Shape过滤掉。query与filter有关的参数有:
- 结构体PxSceneQueryFilterData,包括PxSceneQueryFilterFlags和PxFilterData
- PxSceneQueryFilterCallback选项
这些灵活多变的filter机制允许用户锁心所欲的自定义过滤行为。俺们来看几个例子:
首先PxSceneQueryFilterFlag::eSTATIC 和 PxSceneQueryFilterFlag::eDYNAMIC 标志提供了第一层过滤。它们表示query是针对场景中的static还是dynamic对象。如果想query全部static或dynamic对象时,这显然比一个一个往filtering callback中加对象要方便。例如,爆炸效果可以球体的overlapMultiple来扫全场景中的dynamic对象(打开PxSceneQueryFilterFlag::eDYNAMIC标志),对static对象只需要给他们加个外力什么的就可以了。
第二个层次上的过滤由PxFilterData提供,它是一个128位的掩码。query会拿shape的掩码跟自己比较,通过才将shape纳入本次query。shape通过的情况有两种:1,query的掩码为零;2,shape的掩码和query的掩码按位与的结果非零(其实非零即等于掩码,掩码通常是只有1位为1)。
filter callback可以建立更灵活的过滤规则。filter callback需实现PxSceneQueryFilterCallback后传给query。然后场景查询可以在需要时调用其。调用时机可能是计算碰撞前也可能是其后,视实际情况。当然在计算之前就决定是不是要丢弃shape的开销是要小一些,但有时候计算以后的结果是你的判断条件之一。设置callback调用时机使用这俩filter标志:PxSceneQueryFilterFlag::ePREFILTER 或 PxSceneQueryFilterFlag::ePOSTFILTER .
filter callback会返回一个PxSceneQueryHitType 。该值可能为:
- eNONE,表示shape不许参与后面的query处理。
- eBLOCK,表示shape是hit最终结束在的物体blocking hit,凡是比该shape更远的shape都不必参与query。(从后文来看该shape并没有被过滤掉,仍然是参与query的。)
- eTOUCH,表示shape是一个touching hit,参与query处理,除非后续filter callback给它过滤掉了。
eNONE和eBLOCK比较简单。NONE就丢弃shape不参与query,BLOCK就将shape加入query。eTOUCH是新增加的值,为了处理像子弹穿过窗户(打碎窗户但继续向前)这样的情形。显而易见eTOUCH只对造成Multiple hits的query有效。
Caching
PxSceneQueryCache 可以用来加速某些情况下的query,尤其是raycastAny, raycastSingle 和 sweepSingle .它的工作方式是:在缓存中定义了一些shape,甚至三角面(三角面和shape都会被首先测试)。高度时序性的query会因此得到显著的效率提升。解决这类时序问题的一个好方法是将上一帧的query结果放在query缓存对象中。
例如,人工智能的可见度query很可能连续几帧都返回同一个遮挡物blocking shape。那俺们就可以给到这个raycastAny(视线的query常用racycatAny,前面有讲)一个恰当的PxSceneQueryCache,然后呢,query会在检查其他shape之前就马上发现它hit了缓存中的这个shape,然后query就返回了。
再譬如,在缓存中存放上一次的closest hit,这会大大提高query查找closest hit的效率。
Batched Queries
批查询使用的是PxPatchQuery对象的接口。 顾名思义,就是可以把多个Query组合在一起,然后一次执行(调用PxBatchQuery::execute())。批查询基本上和非批查询是一样的。他俩的区别主要是:
- PS3的SPUs只能跑批查询
- 硬编码的过滤方程(hardcoded filtering equation) 不能用于批查询。取而代之的是两个filter shader:PxBatchQueryPreFilterShader 和 PxBatchQueryPostFilterShader。
查询结果先写入PxPatchQueryDesc中用户指定的缓冲区,后以同样的顺序输出到PxPatchQuery对象。
事件是最简单的模拟回调。程序可以只监听而不做反应。用户在callback中添加的代码只有一个问题:你未必能如愿修改SDK中的状态!(only one restriction? -_-b)后台进行物理模拟时,也可以进行写操作——这有点意外吧,因为SDK都是双缓冲形式的,新状态都是写入了非活动状态的后缓冲中。但是,event是在fetchResults()内部被调用的而不是在模拟线程simulation thread,这就有可能后缓冲中有些操作在模拟线程中已经做过了。将来的升级版本可能会基于单个事件在此问题上做一些改进,但目前还是只有先把需要作为事件结果返回的写操作缓存起来,并且在fetchResult()返回后执行。(糊里糊涂的#v#)
监听事件有两步:1,写一个继承于 PxSimulationEventCallback的子类,定义需要的回调函数。对Sleep/Wake事件或是约束破坏事件constraint break event, 这是唯一的一个步骤。
2,onContactNotify 和 onTrigger 事件,还需要在filter shader callback为需要接受该事件的物体设置一个标志。下一节collision filtering会细说。
这是SampleSubmarine工程中的使用contact notify function的例子:
几乎所有实际应用中,都需要设置不计算某些相互作用的物体,或者让SDK以某种特殊的方式进行冲突检测。在潜水艇的例程中,如上文说道的,需要在潜水艇touch到了一个水雷或水雷链的时候得到通知be notified,以便引爆它们。再有,钳爪AI也需要知道它是不碰touch到了heightfield。
首先俺们看看shader system,SampleSubmarine中实现了一个filter shader