BsPhysXMesh.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "BsPhysXMesh.h"
  2. #include "RTTI/BsPhysXMeshRTTI.h"
  3. #include "Mesh/BsMeshData.h"
  4. #include "RenderAPI/BsVertexDataDesc.h"
  5. #include "BsPhysX.h"
  6. #include "Math/BsAABox.h"
  7. #include "foundation/PxAllocatorCallback.h"
  8. #include "geometry/PxTriangleMesh.h"
  9. #include "geometry/PxConvexMesh.h"
  10. #include "cooking/PxConvexMeshDesc.h"
  11. #include "extensions/PxDefaultStreams.h"
  12. using namespace physx;
  13. namespace bs
  14. {
  15. /**
  16. * Attempts to cook a convex mesh from the provided mesh data. Assumes the mesh data is not null and contains vertex
  17. * positions as well as face indices. If the method returns true the resulting convex mesh will be output in the @p
  18. * data buffer, and its size in @p size. The data buffer will be allocated used the generic allocator and is up to the
  19. * caller to free it.
  20. */
  21. bool cookConvex(PxCooking* cooking, const SPtr<MeshData>& meshData, UINT8** data, UINT32& size)
  22. {
  23. SPtr<VertexDataDesc> vertexDesc = meshData->getVertexDesc();
  24. // Try to create hull from points
  25. PxConvexMeshDesc convexDesc;
  26. convexDesc.points.count = meshData->getNumVertices();
  27. convexDesc.points.stride = vertexDesc->getVertexStride();
  28. convexDesc.points.data = meshData->getElementData(VES_POSITION);
  29. convexDesc.flags |= PxConvexFlag::eCOMPUTE_CONVEX;
  30. PxDefaultMemoryOutputStream output;
  31. if (cooking->cookConvexMesh(convexDesc, output))
  32. {
  33. size = output.getSize();
  34. *data = (UINT8*)bs_alloc(size);
  35. memcpy(*data, output.getData(), size);
  36. return true;
  37. }
  38. // Try inflating the convex mesh
  39. convexDesc.flags |= PxConvexFlag::eINFLATE_CONVEX;
  40. if (cooking->cookConvexMesh(convexDesc, output))
  41. {
  42. size = output.getSize();
  43. *data = (UINT8*)bs_alloc(size);
  44. memcpy(*data, output.getData(), size);
  45. return true;
  46. }
  47. // Nothing works, just compute an AABB
  48. AABox box;
  49. auto vertIter = meshData->getVec3DataIter(VES_POSITION);
  50. do
  51. {
  52. box.merge(vertIter.getValue());
  53. }
  54. while (vertIter.moveNext());
  55. Vector3 aabbVerts[8];
  56. aabbVerts[0] = box.getCorner(AABox::FAR_LEFT_BOTTOM);
  57. aabbVerts[1] = box.getCorner(AABox::FAR_RIGHT_BOTTOM);
  58. aabbVerts[2] = box.getCorner(AABox::FAR_RIGHT_TOP);
  59. aabbVerts[3] = box.getCorner(AABox::FAR_LEFT_TOP);
  60. aabbVerts[4] = box.getCorner(AABox::NEAR_LEFT_BOTTOM);
  61. aabbVerts[5] = box.getCorner(AABox::NEAR_RIGHT_BOTTOM);
  62. aabbVerts[6] = box.getCorner(AABox::NEAR_RIGHT_TOP);
  63. aabbVerts[7] = box.getCorner(AABox::NEAR_LEFT_TOP);
  64. convexDesc.points.count = 8;
  65. convexDesc.points.stride = sizeof(Vector3);
  66. convexDesc.points.data = &aabbVerts[0];
  67. convexDesc.flags &= ~PxConvexFlag::eINFLATE_CONVEX;
  68. if (cooking->cookConvexMesh(convexDesc, output))
  69. {
  70. size = output.getSize();
  71. *data = (UINT8*)bs_alloc(size);
  72. memcpy(*data, output.getData(), size);
  73. return true;
  74. }
  75. return false;
  76. }
  77. /**
  78. * Attempts to cook a triangle or convex mesh from the provided mesh data. Will log a warning and return false if it is
  79. * unable to cook the mesh. If the method returns true the resulting convex mesh will be output in the @p data buffer,
  80. * and its size in @p size. The data buffer will be allocated used the generic allocator and is up to the caller to
  81. * free it.
  82. */
  83. bool cookMesh(const SPtr<MeshData>& meshData, PhysicsMeshType type, UINT8** data, UINT32& size)
  84. {
  85. if (meshData == nullptr)
  86. return false;
  87. PxCooking* cooking = gPhysX().getCooking();
  88. if (cooking == nullptr)
  89. {
  90. LOGWRN("Attempting to cook a physics mesh but cooking is not enabled globally.");
  91. return false;
  92. }
  93. SPtr<VertexDataDesc> vertexDesc = meshData->getVertexDesc();
  94. if (!vertexDesc->hasElement(VES_POSITION))
  95. {
  96. LOGWRN("Provided PhysicsMesh mesh data has no vertex positions.");
  97. return false;
  98. }
  99. if (type == PhysicsMeshType::Convex)
  100. {
  101. if(!cookConvex(cooking, meshData, data, size))
  102. {
  103. LOGWRN("Failed cooking a convex mesh. Perpahs it is too complex? Maximum number of convex vertices is 256.");
  104. return false;
  105. }
  106. }
  107. else
  108. {
  109. PxTriangleMeshDesc meshDesc;
  110. meshDesc.points.count = meshData->getNumVertices();
  111. meshDesc.points.stride = vertexDesc->getVertexStride();
  112. meshDesc.points.data = meshData->getElementData(VES_POSITION);
  113. meshDesc.triangles.count = meshData->getNumIndices() / 3;
  114. meshDesc.flags |= PxMeshFlag::eFLIPNORMALS;
  115. IndexType indexType = meshData->getIndexType();
  116. if (indexType == IT_32BIT)
  117. {
  118. meshDesc.triangles.stride = 3 * sizeof(PxU32);
  119. meshDesc.triangles.data = meshData->getIndices32();
  120. }
  121. else
  122. {
  123. meshDesc.triangles.stride = 3 * sizeof(PxU16);
  124. meshDesc.triangles.data = meshData->getIndices16();
  125. meshDesc.flags |= PxMeshFlag::e16_BIT_INDICES;
  126. }
  127. PxDefaultMemoryOutputStream output;
  128. if (!cooking->cookTriangleMesh(meshDesc, output))
  129. return false;
  130. size = output.getSize();
  131. *data = (UINT8*)bs_alloc(size);
  132. memcpy(*data, output.getData(), size);
  133. }
  134. return true;
  135. }
  136. PhysXMesh::PhysXMesh(const SPtr<MeshData>& meshData, PhysicsMeshType type)
  137. :PhysicsMesh(meshData, type)
  138. { }
  139. void PhysXMesh::initialize()
  140. {
  141. if(mInternal == nullptr) // Could be not-null if we're deserializing
  142. mInternal = bs_shared_ptr_new<FPhysXMesh>(mInitMeshData, mType);
  143. PhysicsMesh::initialize();
  144. }
  145. void PhysXMesh::destroy()
  146. {
  147. mInternal = nullptr;
  148. PhysicsMesh::destroy();
  149. }
  150. FPhysXMesh::FPhysXMesh()
  151. :FPhysicsMesh(nullptr, PhysicsMeshType::Convex)
  152. {
  153. }
  154. FPhysXMesh::FPhysXMesh(const SPtr<MeshData>& meshData, PhysicsMeshType type)
  155. :FPhysicsMesh(meshData, type)
  156. {
  157. // Perform cooking if needed
  158. if (meshData != nullptr)
  159. cookMesh(meshData, mType, &mCookedData, mCookedDataSize);
  160. initialize();
  161. }
  162. FPhysXMesh::~FPhysXMesh()
  163. {
  164. if (mCookedData != nullptr)
  165. {
  166. bs_free(mCookedData);
  167. mCookedData = nullptr;
  168. mCookedDataSize = 0;
  169. }
  170. if (mTriangleMesh != nullptr)
  171. {
  172. mTriangleMesh->release();
  173. mTriangleMesh = nullptr;
  174. }
  175. if (mConvexMesh != nullptr)
  176. {
  177. mConvexMesh->release();
  178. mConvexMesh = nullptr;
  179. }
  180. }
  181. void FPhysXMesh::initialize()
  182. {
  183. if (mCookedData != nullptr && mCookedDataSize > 0)
  184. {
  185. PxPhysics* physx = gPhysX().getPhysX();
  186. PxDefaultMemoryInputData input(mCookedData, mCookedDataSize);
  187. if (mType == PhysicsMeshType::Convex)
  188. mConvexMesh = physx->createConvexMesh(input);
  189. else
  190. mTriangleMesh = physx->createTriangleMesh(input);
  191. }
  192. }
  193. SPtr<MeshData> FPhysXMesh::getMeshData() const
  194. {
  195. SPtr<VertexDataDesc> vertexDesc = VertexDataDesc::create();
  196. vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  197. if (mConvexMesh == nullptr && mTriangleMesh == nullptr)
  198. return MeshData::create(0, 0, vertexDesc);
  199. UINT32 numVertices = 0;
  200. UINT32 numIndices = 0;
  201. if(mConvexMesh != nullptr)
  202. {
  203. numVertices = mConvexMesh->getNbVertices();
  204. UINT32 numPolygons = mConvexMesh->getNbPolygons();
  205. for (UINT32 i = 0; i < numPolygons; i++)
  206. {
  207. PxHullPolygon face;
  208. bool status = mConvexMesh->getPolygonData(i, face);
  209. assert(status);
  210. numIndices += (face.mNbVerts - 2) * 3;
  211. }
  212. }
  213. else // Triangle
  214. {
  215. numVertices = mTriangleMesh->getNbVertices();
  216. numIndices = mTriangleMesh->getNbTriangles() * 3;
  217. }
  218. SPtr<MeshData> meshData = MeshData::create(numVertices, numIndices, vertexDesc);
  219. auto posIter = meshData->getVec3DataIter(VES_POSITION);
  220. UINT32* outIndices = meshData->getIndices32();
  221. if (mConvexMesh != nullptr)
  222. {
  223. const PxVec3* convexVertices = mConvexMesh->getVertices();
  224. const UINT8* convexIndices = mConvexMesh->getIndexBuffer();
  225. for (UINT32 i = 0; i < numVertices; i++)
  226. posIter.addValue(fromPxVector(convexVertices[i]));
  227. UINT32 numPolygons = mConvexMesh->getNbPolygons();
  228. for (UINT32 i = 0; i < numPolygons; i++)
  229. {
  230. PxHullPolygon face;
  231. bool status = mConvexMesh->getPolygonData(i, face);
  232. assert(status);
  233. const PxU8* faceIndices = convexIndices + face.mIndexBase;
  234. for (UINT32 j = 2; j < face.mNbVerts; j++)
  235. {
  236. *outIndices++ = faceIndices[0];
  237. *outIndices++ = faceIndices[j];
  238. *outIndices++ = faceIndices[j - 1];
  239. }
  240. }
  241. }
  242. else
  243. {
  244. const PxVec3* vertices = mTriangleMesh->getVertices();
  245. for (UINT32 i = 0; i < numVertices; i++)
  246. posIter.addValue(fromPxVector(vertices[i]));
  247. if(mTriangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES)
  248. {
  249. const UINT16* indices = (const UINT16*)mTriangleMesh->getTriangles();
  250. UINT32 numTriangles = numIndices / 3;
  251. for (UINT32 i = 0; i < numTriangles; i++)
  252. {
  253. // Flip triangles as PhysX keeps them opposite to what Banshee expects
  254. outIndices[i * 3 + 0] = (UINT32)indices[i * 3 + 0];
  255. outIndices[i * 3 + 1] = (UINT32)indices[i * 3 + 2];
  256. outIndices[i * 3 + 2] = (UINT32)indices[i * 3 + 1];
  257. }
  258. }
  259. else
  260. {
  261. const UINT32* indices = (const UINT32*)mTriangleMesh->getTriangles();
  262. UINT32 numTriangles = numIndices / 3;
  263. for (UINT32 i = 0; i < numTriangles; i++)
  264. {
  265. // Flip triangles as PhysX keeps them opposite to what Banshee expects
  266. outIndices[i * 3 + 0] = indices[i * 3 + 0];
  267. outIndices[i * 3 + 1] = indices[i * 3 + 2];
  268. outIndices[i * 3 + 2] = indices[i * 3 + 1];
  269. }
  270. }
  271. }
  272. return meshData;
  273. }
  274. RTTITypeBase* FPhysXMesh::getRTTIStatic()
  275. {
  276. return FPhysXMeshRTTI::instance();
  277. }
  278. RTTITypeBase* FPhysXMesh::getRTTI() const
  279. {
  280. return getRTTIStatic();
  281. }
  282. }