Shapes
Shapes描述了 Actor空间范围和碰撞性能。
他们在物理运算引擎用于三个地方:
1交叉测试,确定刚性物体的接触特性,
2例如光线投影Raycasts的场景查询测试,
3定义碰撞器体积——用于在其他形体与其相交时生成通知
Shapes属于引用计数,参见应用计数
每个形状包含PxGeometry的对象和一个PxMaterial的引用,在创建的时候必须被同时声明。
下面的代码创建了一个形状包含了球面几何和一个特定的材料:
PxShape* shape = physics.createShape(PxSphereGeometry(1.0f), myMaterial, false);
myActor.attachShape(*shape);
shape->release();
PxRigidActor:CreateShape()方法和上面三行代码等效。
createShape的false参数通知SDK工具这个shape不会被其他的Actor所共享。当你有许多完全一样几何的Actor时,你可以使用共享来减少模拟所需要的内存。但是共享shapes有一个十分严重的限制,当一个被共享的shape被添加到Actor中之后,你不能够更新他的属性。
你能够通过制定shape的标记来随意的配置shape。一个Shape被缺省设置为:
一个模拟形状(支持模拟期间迭代的联系)
场景查询形状(支持场景查询)
调试渲染下的可视化
当一个几何物体被规定为一个Shape之后,这个几何对象就被复制到shape之中。几何体被制定为一个shape时有一些限制,决定于shape的标识和Actor父对象的种类。
三角网,高度地面和平板 集合体不支持附着在动态Actor上的模拟形状,除非动态actor被定义为运动学的。
三角网和高度领域几何体不支持碰撞器shape
看下面的片段。
像下面一样吧shape从actor中分离出来。
myActor。detachShape(*shape)note
在之前Px的版本中release()被用于从actor中分离shape,并且摧毁它。这种release的用噶在Px3.3版本中被禁止并且不再会在以后版本中支持
模拟形状和场景查询形状
shapes会被单独设置去在场景测试和查询两者中同时或者单独合作。在默认情况下,一个形状会被两者分享。
下面的未完成的代码设置了一个PxShape的实例,因此他不再参与形状的交叉测试:
void disableShapeInContact(PxShape *shape)
{
shape->setFlag(PXShapeFlag::eSIMULATION_SHAPE,false);
}
一个PxShape的实例能够被设置成参与两个形状之间的交叉测试
void disableShapeInContact(PxShape *shape)让PxShape的实例不能参与场景查询测试
{
shape->setFlag(PXShapeFlag::eSIMULATION_SHAPE,true);
}
void disableShapeInSceneQuery(PxShape *shape){ shape->setFlag(PxShapeFlag::eSCENE_QUREY_SHAPE,false);}
最后的,一个PsShape的实例也可以被重新设置为可以参与场景测试
void enableShapeInSceneQuery(PxShape *shape){
shape->setFlag(PxShapeFlag::eSCENE_QUREY_SHAPE,true);
}
笔记
如果形状的actor的移动中名不能够被模拟器控制,例如,这个shape已经被仅仅用作场景查询,并且被手动移动,之后内存能够在禁用actor模拟器的时候被保存(查询PxActorFlag::eDISABLE_SIMULATION)
触发器形状
触发器器的形状在场景模拟器中毫无作用。相反的,他们的职责是汇报是否有两个形状重叠。
交叉中不会产生触体,结果是接触体并不能够被触发器器的shape获取。另外,因为触发器在模拟器中没有起作用,sdk并不会允许eSIMULATION_SHAPE eTRIGGER_SHAPE 的标识被同时标上。换言之,如果一个标识被标记了,之后要准备标记另一个的时候就会被静止,并且会输出一个错误信息。
触发器的形状被用在 SanpleSubmarine中,判断潜水艇是否触碰到了大陆。在下面的代码中代表了大陆PxActor有自己的配置为触发器shape的隐藏形状
PsShape *treasureshape;
gTreasureActor->getShapes(&treasureShape,1);
treasureShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE,false);
treasureShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE,true);
触发器之间的重叠在本例中通过启用PxSimulationEventCallback::onTrigger被获取到。(这是PxSmpleSubmarine中的类,PxSimulationEventCallback的子类
void SampleSubmarine::onTrigger(PxTriggerPair* pairs, PxU32 count)上面的代码在涉及触发器形状的重叠的两者间遍历。如果发现大陆碰到了潜水艇,标识就会被设置为真。
{
for(PxU32 i=0; i < count; i++)
{
// ignore pairs when shapes have been deleted
if (pairs[i].flags & (PxTriggerPairFlag::eDELETED_SHAPE_TRIGGER | PxTriggerPairFlag::eDELETED_SHAPE_OTHER))
continue;
if((&pairs[i].otherShape->getActor() == mSubmarineActor) && (&pairs[i].triggerShape->getActor() == gTreasureActor))
{
gTreasureFound = true;
}
}
}
动力学 三角网格(平板,高度地面)
我们能够创建一个动力学的 PxRigidDynamic(他拥有一个三角网格)。如果这个模型拥有一个模拟器模型标识,这个actor一定是动力学的。如果你改变了标识使得不在模拟状态,你甚至可以选择动态学的标识。
为了建立动力学三角网格
PxRigidDynamic *meshActor =getPhysics().createRigidDynamic(PxTransform(1.0f));
PxShape *meshShape;
if(meshActor)
{
meshActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC,true);
PxTriangleMeshGeomtry triGeom;
triGeom.triangleMesh = triangleMesh;
meshShape = meshActor->createShape(triGeom, defaultMaterial);
getScene().addActor(*meshActor);
PxConvexMeshGeometry convexGeom = PxConvexMeshGeometry(convexBox);
convexShape = meshActor->createShape(convexGeom,defaultMaterial);
convexShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
}
// 改变为动力学
meshShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
convexShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true);
meshActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, false);
几何体
PxGeometry类定义了一个拥有固定位置和方向的立体或者表面。典型的,当在模型或者场景查询中被使用是,一个变幻解释了几何帧。
对于主要对象,例如凸起网格,三角网格或者是高度地面,Px允许多重几何体引用单网格,并支持单实例缩放。
note
每一个网格都是引用技术(巴拉巴拉...
球体
PxSphereGeometry有一个属性指定,半径,并且中心在原点。
盒子
(这部分太繁杂,稍后补全..)
高度地形
如名字,地心可以用网格采样的高度值来描述
PxHeightFieldSample *samples = (PxHeightFieldSampel*)alloc(sizeof(PxHeightFieldSample)*(numRows*numCols));每个样本(方格子)都有一个16位的整数值和2个材质(一个方格划分成2个三角面)以及一个镶嵌的标识。
标识和材质涉及到下方的单元,顶点,沿对角线分割的三角形和三角形的材质。
这是一种特殊的已经定义了的材质,PxHeightFieldMaterial::eHOLE. 说明了高度地形的山洞?如果你用float型描述高度(也木有关系?)
例
棋盘标识 | 结果 |
---|---|
0,0,0
0,0,0
0,0,0
|
|
1,1,1
1,1,1
1,1,1
|
|
0,1,0
1,0,1
0,1,0
|
为了告诉系统各个方向的高度取样,使用一个描述者来实例化PxHeighField对象:
PxHeightFieldDesc hfDesc;
hfDesc.format = PxHeightFieldFormat::eS16_TM;
hfDesc.nbColumns = numCols;
hfDesc.nbRows = numRows;
hfDesc.thickness = -10.0f;
hfDesc.samples.data = samples;
hfDesc.samples.stride = sizeof(PxHeightFieldSample);
PxHeightField* aHeightField = theCooking->createHeightField(hfDesc, thePhysics->getPhysicsInsertionCallback());
为了避免使用高昂的持续碰撞检测,需要制定一个厚度。厚度在y轴扩展了碰撞体积,使得渗入地下的物体(不出现在表面)不会穿透。考虑到每一个与地形碰撞的物体,为了避免穿透,厚度必须包含那个最大物体的尺寸。
高度地形对象需要创建几何体和模型:
pxHeightFieldGeometry hfGeom(aHeightField,pxMeshGeometryFlags(),heightScale,rowScale,colScale);
PxShape *aHeightFieldShape = aHeightFiledActor->createShape(hGeom,aMaterialArray,nbMaterials);
排列大小告诉系统相关方向的采样点之间距离有多远,高度值也可以使用float型描述。
c这里使用reateShape()的一个变体,制定了材料高度的组数,将索引材料的每一个单元都用来解决和单元件的碰撞。也可以用他的单一变体实例取代,但是高度地形的材质目录都必须是一个单值或者是特殊值eHole。
生成接触
HeightFiled的碰撞产生于另一个模型包含在在他的垂直体积重(体积涵盖了表面和厚度)例如,如果一个物体相交于高度地形的一条边而不是表面,那么只会产生指向表面的接触信息。考虑这个有洞的高度地形例子。
在地形边界上三角形边的碰撞信息能够使用PxHeightFieldFlag::eNo_BOUNDARY_EDGES标识来禁用,使得多个heightfeild模型边缘碰撞更加有效。