来自:The PhysX SDK.chm/Guide/Collision Detection/Meshes/Cooking
创建三角网格,首先要把它cook成某种固定格式,在这种格式下SDK才能高效的进行冲突检测。cooking的过程可能会非常慢,因此cooking操作通常是离线的并且只做一次,完成以后,将结果数据generated stream保存成文档形式,下一次只需要载入。
使用PPU进行cook,另外有一些注意事项。详见Mesh Paging章节。
实用程序使用NxCooking库cook网格。首先要调用如下接口初始化一个NxCooking库的对象:
static NxCookingInterface* gCooking = NxGetCookingLib(NX_PHYSX_SDK_VERSION);
gCooking->NxInitCooking();
gCooking->NxInitCooking();
然后,用一个NxTriangleMeshDesc对象描述一个网格,将其作为参数传递给函数NxCookTriangleMesh(),该函数会处理网格描述并通过用户实现的stream——NxStream是PhysX要求用户实现的一个读写操作的接口——然后stream就能将其写入文件或内存。
//Build physical model
NxTriangleMeshDesc bunnyDesc;
bunnyDesc.numVertices = BUNNY_NBVERTICES;
bunnyDesc.numTriangles = BUNNY_NBFACES;
bunnyDesc.pointStrideBytes = sizeof(NxVec3);
bunnyDesc.triangleStrideBytes = 3*sizeof(NxU32);
bunnyDesc.points = gBunnyVertices;
bunnyDesc.triangles = gBunnyTriangles;
bunnyDesc.flags = 0;
gCooking->NxCookTriangleMesh(bunnyDesc, UserStream("c:\\cooked.bin", false));
NxTriangleMeshDesc bunnyDesc;
bunnyDesc.numVertices = BUNNY_NBVERTICES;
bunnyDesc.numTriangles = BUNNY_NBFACES;
bunnyDesc.pointStrideBytes = sizeof(NxVec3);
bunnyDesc.triangleStrideBytes = 3*sizeof(NxU32);
bunnyDesc.points = gBunnyVertices;
bunnyDesc.triangles = gBunnyTriangles;
bunnyDesc.flags = 0;
gCooking->NxCookTriangleMesh(bunnyDesc, UserStream("c:\\cooked.bin", false));
接下来,当应用程序需要创建三角面mesh时,通过下面的函数载入stream保存的mesh数据。
bunnyTriangleMesh = gPhysicsSDK->createTriangleMesh(UserStream("c:\\tmp.bin", true));
NxCookConvexMesh()/NxCookClothMesh()和NxCookTriangleMesh()用法一样一样的。
注意: cooking操作受精度影响很大,很依赖于浮点运算单元FPU的模式。跨平台的话,要保证FPU的精度和舍入方式是一致的。
上例中,没有设置flag成员。flag可以设置一些特殊标志。例如
- NX_MF_FLIPNORMALS – 索引列表中三个顶点的顺序反向(默认是逆时针),即法线反向
- NX_MF_16_BIT_INDICES – 顶点索引数据长度16bit而不是32bit
- NX_MF_CONVEX – 允许将mesh看做convex,并自动优化
三角面的法线没有显式的描述出来,它可以这样算出来
(v1 – v0) x (v2 – v0)
v0,v1,v2是三角形的三个顶点。逆时针顺序counter-clockwise(右手法则right handed coordinate system)还是顺时针顺序,这个算法都是一样的。
网格注意事项:
- 确保法线的朝向,别反了。冲突检测只能正确计算正面过来的shape。
- 顶点不要重复。如果俩三角形共享一个顶点,这个点只能在顶点列表中出现一次,只不过是在索引列表中索引两次。因为重复的顶点对PhysX来说,它就是两个点,这就会造成冲突检测错误。
- 不要用T-Joint和non-manifold edge。(因为这两个东西都会要求三角面中的共享点被看做两个点。)
- 一旦网格cook完成了,质量mass和inertia tensor也都计算出来了。
- 同一个网格中的不同三角面的材质可以不同。详见Material章节
然后就可以用mesh创建shape并Actor了。关键就是把triangle mesh shape description的meshdata设置为前面cooking后的mesh就O了。
NxTriangleMeshShapeDesc bunnyShapeDesc;
bunnyShapeDesc.meshData= bunnyTriangleMesh;
NxBodyDesc bodyDesc;
NxActorDesc actorDesc;
actorDesc.shapes.pushBack(&bunnyShapeDesc);
actorDesc.body= &bodyDesc;
actorDesc.density= 1.0f;
NxActor* newActor = gScene->createActor(actorDesc);
bunnyShapeDesc.meshData= bunnyTriangleMesh;
NxBodyDesc bodyDesc;
NxActorDesc actorDesc;
actorDesc.shapes.pushBack(&bunnyShapeDesc);
actorDesc.body= &bodyDesc;
actorDesc.density= 1.0f;
NxActor* newActor = gScene->createActor(actorDesc);