天天看點

PhysX3 User Guide 02 - Shapes

原文位址:http://www.cnblogs.com/mumuliang/archive/2011/06/02/2068523.html

Shape是PxGeometry的展現。一個Shape包括:PxGeometry, PxMetarial,和shape相對它所屬的actor的pose(orientation and positionActor),肯定是這個PxActor建立的。多個shape可以湊成一組(成為一個Compound)在同一個Actor中。   和PhysX 2.x類似, 建立Shape是需定義一個PxGeometry. 也就是說每一個Shape都有它自己的PxGeometry類型. PhysX既有的PxGeometry如下.

1)for static and dynamic Actors:Spheres, Capsules, Boxes, ConvexMeshes

2)for static Actors only:  Planes,  HeightFields,  TriangleMeshes

 (although TriangleMeshes can be used as kinematics in scene queries)

建立 simulation object or Shape 的步驟:

  1. 用SDK對象建立一個Actor,  (要給出它的pose (orientation and position))。
  2. 建立Shape需要的Geometry
  3. Actor建立Shape,們。(别忘了材質和shape的相對pose)
  4. 更新mass、inertia 等屬性。 (PhysX Extensions中有相關函數)
  5. 向Scene添加Actor。

 1 Spheres  

在某位置以某初始化速度扔出一個球體。 首先,俺們需要一個dynamic的actor PxRigidDynamic *  aSphereActor  =  thePhysics -> createRigidDynamic(PxTransform(position));  

然後是一個shape。描述sphere的geomety隻需要半徑足夠了,第二個材質是必須要的。

PxShape *  aSphereShape  =  aSphereActor -> createShape(PxSphereGeometry(radius), aMaterial);  

Actor加完所有的shape以後,就計算mass和inertia。

PxRigidBodyExt::updateMassAndInertia( * aSphereActor, sphereDensity);   

用Shape設定初始速度,這是個linear velocity vector:

aSphereShape -> setLinearVelocity(velocity);

将Actor加到場景中。 aScene -> addActor(aSphereActor);

 2 Capsules  

和Sphere相比, Capsule還需要一個height.   注意,初始化Capsule設定的是half height。建立Shape和Actor的方式同Sphere,略。 PxTransform pose;

pose.q  =  PxQuat(PxHalfPi, PxVec( 0 , 0 , 1 ));

PxShape *  aCapsuleShape  =  aCapsuleActor -> createShape(PxCapsuleGeometry(radius, halfHeight), aMaterial, pose);  

capsule的height預設是y方向的,要讓Capsule沿X方向延伸,将其繞Z軸旋轉90度。

 3 Boxes  

描述一個Box的隻需要3個參數。 PxShape *  aBoxShape  =  aBoxActor -> createShape(PxBoxGeometry(a / 2 , b / 2 , c / 2 ), aMaterial);  

a, b , c代表其邊長。

 4 Convex Meshes  

使用頂點vertex來描述Convex Mesh。建立一個金字塔形試試看. 首先定義其邊緣的頂點(extreme verteices)。 static   const  PxVec3 convexVerts[]  =  {PxVec3( 0 , 1 , 0 ),PxVec3( 1 , 0 , 0 ),PxVec3( - 1 , 0 , 0 ),PxVec3( 0 , 0 , 1 ),PxVec3( 0 , 0 , - 1 )};  

然後描述面上的點:

PxConvexMeshDesc convexDesc;

convexDesc.points.count  =   5 ;

convexDesc.points.stride  =   sizeof (PxVec3);

convexDesc.points.data  =  convexVerts;

convexDesc.flags  =  PxConvexFlag::eCOMPUTE_CONVEX;  

有了這些點PhysX SDK就可以計算出其餘相關的資料。俺們把這個過程叫做cooking。接下來叫你如何用PhysX cook a Convex Mesh,and it is done through a Stream objects。

PxCooking *  cooking  =  PxCreateCooking(PX_PHYSICS_VERSION, thePhysics -> getFoundation(), PxCookingParams());

MemoryWriteBuffer buf;

bool  status  =  cooking -> cookConvexMesh(convexDesc, buf);

PxConvexMesh *  convexMesh  =  thePhysics -> createConvexMesh(MemoryReadBuffer(buf.data));

cooking -> release();  

現在有了ConvexMesh,就可以用它建立一個Convex的Shape了。

PxShape *  aConvexShape  =  aConvexActor -> createShape(PxConvexMeshGeometry(convexMesh, PxMeshScale()), aMaterial, aTransform); PxConvexMeshGeometry的第二個參數用以控制ConvexMesh的縮放。  

 5 Planes  

Plane把空間分成以上和以下。凡是低于plane物體就會和它碰撞. 俺們常用它來建立地面或者模拟的世界的邊界。Plane這種Geometry根本不需要參數.隻要把它放到某處就可以了。它是static的。當然是static。 PxRigidStatic *  aPlaneActor  =  thePhysics -> createRigidStatic(pose);

PxShape *  aPlaneShape  =  aPlaneActor -> createShape(PxPlaneGeometry(), aMaterial);

 6 Heightfields  

如名, 地形就可以用方形網格采樣的高度值描述。 PxHeightFieldSample *  samples  =  (PxHeightFieldSample * )alloc( sizeof (PxHeightFieldSample) * (numRows * numCols));  

每個樣本(方格子)都有一個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.

當然,還要知道每個方向有多少樣本高度。 PxHeightFieldDesc hfDesc;

hfDesc.format  =  PxHeightFieldFormat::eS16_TM;

hfDesc.nbColumns  =  numCols;

hfDesc.nbRows  =  numRows;

hfDesc.samples.data  =  samples;

hfDesc.samples.stride  =   sizeof (PxHeightFieldSample);  

目前隻支援提及的格式。eS16_TM?

Heightfields不需要cooking, 但也有一個内部對象需要初始化: PxHeightField *  aHeightField  =  thePhysics -> createHeightField(hfDesc);  

接下來就可以用Geometry建立shape:

PxHeightFieldGeometry hfGeom(aHeightField, PxMeshGeometryFlags(), heightScale, rowScale, colScale);  

Heightfield也是static的.

PxRigidStatic *  aHeightFieldActor  =  mSDK -> createRigidStatic(pose);

PxShape *  aHeightFieldShape  =  aHeightFieldActor -> createShape(hfGeom, aMaterial);  

如果是 multi-material的heightfields, 需用另一個函數來create Shape

PxShape *  aHeightFieldShape  =  aHeightFieldActor -> createShape(hfGeom, aMaterialArray, nbMaterials);  

 7 Triangle Meshes  

也是要先有三角面的頂點vertices,然後像convexes一樣,需要cooking。

PxTriangleMeshDesc meshDesc;

meshDesc.points.count  =  nbVerts;

meshDesc.triangles.count  =  nbFaces;

meshDesc.points.stride  =   4 * 3 ;

meshDesc.triangles.stride  =   4 * 3 ;

meshDesc.points.data  =  verts;

meshDesc.triangles.data  =  indices;

PxCooking *  cooking  =  PxCreateCooking(PX_PHYSICS_VERSION, thePhysics -> getFoundation(), PxCookingParams());

MemoryWriteBuffer buf;

bool  status  =  cooking -> cookTriangleMesh(meshDesc, buf);

PxTriangleMesh *  triangleMesh  =  thePhysics -> createTriangleMesh(MemoryReadBuffer(buf.data));

cooking -> release();

strides表示points和triangle都是3個一組的4位元組長的資料。   

Triangle meshe是static. 但是可以用作kinematics。(譬如水面?)

PxRigidStatic *  aTriMeshActor  =  thePhysics -> createRigidStatic(pose);

PxShape *  aTriMeshShape  =  aTriMeshActor -> createShape(PxTriangleMeshGeometry(triangleMesh), aMaterial);  

Triangle meshe也可以縮放. 

索引可能是32bit也可以是16bit,視mesh的三角數目而定。用PxTriangleMesh::has16BitTriangleIndices()可以檢視其具體情況.

 8 Compound Shapes 

Compound組合了多個Shape到一個Actor中. 要建立一個Compound Shap隻需多次調用PxRigidActor::createShape()即可。隻是不要忘記最後要計算mash和intertia什麼的。 在North Pole Sample中的雪人就是compound對象. compound到一起的shape之間有些是可以分離的。

例如雪人中,有些會被雪球砸中分開。這需要設定一個PxSimulationFilterShader的pairFlags. 然後在可分離的shape被擊中後在simulation filter function中做如下工作:

if  (needsContactReport(filterData0, filterData1))

{

pairFlags  |=  PxPairFlag::eNOTIFY_TOUCH_FOUND;

}  

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. (迷惑 =“=)

That way, the pair will be passed to the  PxSimulationEventCallback::onContact() function which is implemented in the Sample. All we want to do here is to remember which detachable Shapes were touched in this frame so far. After simulation, we can iterate over that list again and actually detach the according Shapes from their respective Actor. Note that the Shape has a local (in Actor space) pose and the Actor has a world pose. Furthermore, a PxShape cannot exist on its own, it is always bound to an Actor. That means, that when you detach a Shape you have to provide a new Actor for it to continue to exist. The new Actor will have the global pose of the old Shape (in the Compound Actor) and the new local pose is identity. There is a helper extension to calculate the global pose of a Shape. The Geometry and Material needed to create the copy of the Shape in the new Actor can be retreived from the detaching Shape. PxShape *  shape  =   < theDetachingShapeYouKnow >

PxTransform pose  =  PxShapeExt::getGlobalPose( * shape);

PxRigidDynamic *  newActor  =  mSDK -> createRigidDynamic(pose);

PxMaterial *  mat;

shape -> getMaterials( & mat, 1 );

PxConvexMeshGeometry convexGeom;

if (shape -> getConvexMeshGeometry(convexGeom))

{

PxShape *  newShape  =  newActor -> createShape(convexGeom, * mat);

PxRigidBodyExt::updateMassAndInertia( * newActor, 1 );

aScene -> addActor( * newActor));

newActor -> addForce(PxVec3( 0 ,. 1 , 0 ),PxForceMode::eFORCE);

shape -> release();

}  

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.

Note here that you can only change dynamic properties of an Actor after it has been added to a Scene. Kinematic properties like velocities can be set before that though.

 9 Mass Computation  

恩,看出來了,actor的mass是需要計算的。用它, PxRigidBodyExt::updateMassAndInertia(). 它會計算和設定

  1. actor的mass
  2. 重心,center of mass
  3. 最大靜摩擦力? the principal moments of inertia

To illustrate different mass properties we will look at the Wobbly Snowmen in the North Pole Sample. The principle of a roly-poly toy is the low center of mass, moving the object back in upright position after it has been tilted. Usually, most of the body is just an empty shell, and the bottom is filled with some heavy material. The Wobbly Snowmen come in different flavors, depending on how the mass properties are set: The first Snowman is basically mass-less. There is just a little sphere with a relatively high mass at the bottom of the Actor. This results in a quite rapid movement due to the small resulting moments of inertia. The Snowman feels light. The second example uses the mass of the bottom snowball only, resulting in a bigger inertia. Later on, the center of mass is moved to the bottom of the actor. This is by no means physically correct, but we only approximate things here. The resulting Snowman feels a bit more filled. The third and fourth example use all basic shapes to calculate the mass. The difference is that one calculates the moments of inertia first (from the real center of mass) and then the center of mass is moved to the bottom. The other calculates the moments of inertia about the low center of mass that we pass to the calculation routine. Note how much slower the wobbling is for the second case although both have the same mass. This is because the head accounts for much more in the moment of inertia (the distance from the center of mass squared). The last Snowmans mass properties are set up manually. After constructing the compound, we set the mass and center of mass. For the moments of inertia, which tell us ‘how much resistance there is to change the orientation about an axis’, we use rough values which create the desired behavior (of course, for real you would integrate the moments properly!). The Snowman shall wobble back and forth only, which is around the X axis in this case. The resulting tensor diagonal values will have a small value in X, and high values in Y and Z: There is small resistance to rotate about X, but a high resistance to rotate about Y and Z.