MeshShape.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Physics/Collision/Shape/MeshShape.h>
  5. #include <Jolt/Physics/Collision/Shape/ConvexShape.h>
  6. #include <Jolt/Physics/Collision/Shape/ScaleHelpers.h>
  7. #include <Jolt/Physics/Collision/Shape/SphereShape.h>
  8. #include <Jolt/Physics/Collision/RayCast.h>
  9. #include <Jolt/Physics/Collision/ShapeCast.h>
  10. #include <Jolt/Physics/Collision/ShapeFilter.h>
  11. #include <Jolt/Physics/Collision/CastResult.h>
  12. #include <Jolt/Physics/Collision/CollidePointResult.h>
  13. #include <Jolt/Physics/Collision/CollideConvexVsTriangles.h>
  14. #include <Jolt/Physics/Collision/CollideSphereVsTriangles.h>
  15. #include <Jolt/Physics/Collision/CastConvexVsTriangles.h>
  16. #include <Jolt/Physics/Collision/CastSphereVsTriangles.h>
  17. #include <Jolt/Physics/Collision/TransformedShape.h>
  18. #include <Jolt/Physics/Collision/ActiveEdges.h>
  19. #include <Jolt/Physics/Collision/CollisionDispatch.h>
  20. #include <Jolt/Physics/Collision/SortReverseAndStore.h>
  21. #include <Jolt/Core/StringTools.h>
  22. #include <Jolt/Core/StreamIn.h>
  23. #include <Jolt/Core/StreamOut.h>
  24. #include <Jolt/Core/Profiler.h>
  25. #include <Jolt/Core/UnorderedMap.h>
  26. #include <Jolt/Geometry/AABox4.h>
  27. #include <Jolt/Geometry/RayAABox.h>
  28. #include <Jolt/Geometry/Indexify.h>
  29. #include <Jolt/Geometry/Plane.h>
  30. #include <Jolt/Geometry/OrientedBox.h>
  31. #include <Jolt/TriangleSplitter/TriangleSplitterBinning.h>
  32. #include <Jolt/AABBTree/AABBTreeBuilder.h>
  33. #include <Jolt/AABBTree/AABBTreeToBuffer.h>
  34. #include <Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h>
  35. #include <Jolt/AABBTree/NodeCodec/NodeCodecQuadTreeHalfFloat.h>
  36. #include <Jolt/ObjectStream/TypeDeclarations.h>
  37. JPH_NAMESPACE_BEGIN
  38. #ifdef JPH_DEBUG_RENDERER
  39. bool MeshShape::sDrawTriangleGroups = false;
  40. bool MeshShape::sDrawTriangleOutlines = false;
  41. #endif // JPH_DEBUG_RENDERER
  42. JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(MeshShapeSettings)
  43. {
  44. JPH_ADD_BASE_CLASS(MeshShapeSettings, ShapeSettings)
  45. JPH_ADD_ATTRIBUTE(MeshShapeSettings, mTriangleVertices)
  46. JPH_ADD_ATTRIBUTE(MeshShapeSettings, mIndexedTriangles)
  47. JPH_ADD_ATTRIBUTE(MeshShapeSettings, mMaterials)
  48. JPH_ADD_ATTRIBUTE(MeshShapeSettings, mMaxTrianglesPerLeaf)
  49. }
  50. // Codecs this mesh shape is using
  51. using TriangleCodec = TriangleCodecIndexed8BitPackSOA4Flags;
  52. using NodeCodec = NodeCodecQuadTreeHalfFloat<1>;
  53. // Get header for tree
  54. static JPH_INLINE const NodeCodec::Header *sGetNodeHeader(const ByteBuffer &inTree)
  55. {
  56. return inTree.Get<NodeCodec::Header>(0);
  57. }
  58. // Get header for triangles
  59. static JPH_INLINE const TriangleCodec::TriangleHeader *sGetTriangleHeader(const ByteBuffer &inTree)
  60. {
  61. return inTree.Get<TriangleCodec::TriangleHeader>(NodeCodec::HeaderSize);
  62. }
  63. MeshShapeSettings::MeshShapeSettings(const TriangleList &inTriangles, const PhysicsMaterialList &inMaterials) :
  64. mMaterials(inMaterials)
  65. {
  66. Indexify(inTriangles, mTriangleVertices, mIndexedTriangles);
  67. Sanitize();
  68. }
  69. MeshShapeSettings::MeshShapeSettings(const VertexList &inVertices, const IndexedTriangleList &inTriangles, const PhysicsMaterialList &inMaterials) :
  70. mTriangleVertices(inVertices),
  71. mIndexedTriangles(inTriangles),
  72. mMaterials(inMaterials)
  73. {
  74. Sanitize();
  75. }
  76. void MeshShapeSettings::Sanitize()
  77. {
  78. // Remove degenerate and duplicate triangles
  79. UnorderedSet<IndexedTriangle> triangles;
  80. triangles.reserve(mIndexedTriangles.size());
  81. for (int t = (int)mIndexedTriangles.size() - 1; t >= 0; --t)
  82. {
  83. const IndexedTriangle &tri = mIndexedTriangles[t];
  84. if (tri.IsDegenerate() // Degenerate triangle
  85. || !triangles.insert(tri.GetLowestIndexFirst()).second) // Duplicate triangle
  86. mIndexedTriangles.erase(mIndexedTriangles.begin() + t);
  87. }
  88. }
  89. ShapeSettings::ShapeResult MeshShapeSettings::Create() const
  90. {
  91. if (mCachedResult.IsEmpty())
  92. Ref<Shape> shape = new MeshShape(*this, mCachedResult);
  93. return mCachedResult;
  94. }
  95. MeshShape::MeshShape(const MeshShapeSettings &inSettings, ShapeResult &outResult) :
  96. Shape(EShapeType::Mesh, EShapeSubType::Mesh, inSettings, outResult)
  97. {
  98. // Check if there are any triangles
  99. if (inSettings.mIndexedTriangles.empty())
  100. {
  101. outResult.SetError("Need triangles to create a mesh shape!");
  102. return;
  103. }
  104. // Check triangles
  105. for (int t = (int)inSettings.mIndexedTriangles.size() - 1; t >= 0; --t)
  106. {
  107. const IndexedTriangle &triangle = inSettings.mIndexedTriangles[t];
  108. if (triangle.IsDegenerate())
  109. {
  110. outResult.SetError(StringFormat("Triangle %d is degenerate!", t));
  111. return;
  112. }
  113. else
  114. {
  115. // Check vertex indices
  116. for (uint32 idx : triangle.mIdx)
  117. if (idx >= inSettings.mTriangleVertices.size())
  118. {
  119. outResult.SetError(StringFormat("Vertex index %u is beyond vertex list (size: %u)", idx, (uint)inSettings.mTriangleVertices.size()));
  120. return;
  121. }
  122. }
  123. }
  124. // Copy materials
  125. mMaterials = inSettings.mMaterials;
  126. if (!mMaterials.empty())
  127. {
  128. // Validate materials
  129. if (mMaterials.size() > (1 << FLAGS_MATERIAL_BITS))
  130. {
  131. outResult.SetError(StringFormat("Supporting max %d materials per mesh", 1 << FLAGS_MATERIAL_BITS));
  132. return;
  133. }
  134. for (const IndexedTriangle &t : inSettings.mIndexedTriangles)
  135. if (t.mMaterialIndex >= mMaterials.size())
  136. {
  137. outResult.SetError(StringFormat("Triangle material %u is beyond material list (size: %u)", t.mMaterialIndex, (uint)mMaterials.size()));
  138. return;
  139. }
  140. }
  141. else
  142. {
  143. // No materials assigned, validate that all triangles use material index 0
  144. for (const IndexedTriangle &t : inSettings.mIndexedTriangles)
  145. if (t.mMaterialIndex != 0)
  146. {
  147. outResult.SetError("No materials present, all triangles should have material index 0");
  148. return;
  149. }
  150. }
  151. // Check max triangles
  152. if (inSettings.mMaxTrianglesPerLeaf < 1 || inSettings.mMaxTrianglesPerLeaf > MaxTrianglesPerLeaf)
  153. {
  154. outResult.SetError("Invalid max triangles per leaf");
  155. return;
  156. }
  157. // Fill in active edge bits
  158. IndexedTriangleList indexed_triangles = inSettings.mIndexedTriangles; // Copy indices since we're adding the 'active edge' flag
  159. sFindActiveEdges(inSettings.mTriangleVertices, indexed_triangles);
  160. // Create triangle splitter
  161. TriangleSplitterBinning splitter(inSettings.mTriangleVertices, indexed_triangles);
  162. // Build tree
  163. AABBTreeBuilder builder(splitter, inSettings.mMaxTrianglesPerLeaf);
  164. AABBTreeBuilderStats builder_stats;
  165. AABBTreeBuilder::Node *root = builder.Build(builder_stats);
  166. // Convert to buffer
  167. AABBTreeToBuffer<TriangleCodec, NodeCodec> buffer;
  168. const char *error = nullptr;
  169. if (!buffer.Convert(inSettings.mTriangleVertices, root, error))
  170. {
  171. outResult.SetError(error);
  172. delete root;
  173. return;
  174. }
  175. // Kill tree
  176. delete root;
  177. // Move data to this class
  178. mTree.swap(buffer.GetBuffer());
  179. // Check if we're not exceeding the amount of sub shape id bits
  180. if (GetSubShapeIDBitsRecursive() > SubShapeID::MaxBits)
  181. {
  182. outResult.SetError("Mesh is too big and exceeds the amount of available sub shape ID bits");
  183. return;
  184. }
  185. outResult.Set(this);
  186. }
  187. void MeshShape::sFindActiveEdges(const VertexList &inVertices, IndexedTriangleList &ioIndices)
  188. {
  189. // A struct to hold the two vertex indices of an edge
  190. struct Edge
  191. {
  192. Edge(int inIdx1, int inIdx2) : mIdx1(min(inIdx1, inIdx2)), mIdx2(max(inIdx1, inIdx2)) { }
  193. uint GetIndexInTriangle(const IndexedTriangle &inTriangle) const
  194. {
  195. for (uint edge_idx = 0; edge_idx < 3; ++edge_idx)
  196. {
  197. Edge edge(inTriangle.mIdx[edge_idx], inTriangle.mIdx[(edge_idx + 1) % 3]);
  198. if (*this == edge)
  199. return edge_idx;
  200. }
  201. JPH_ASSERT(false);
  202. return ~uint(0);
  203. }
  204. bool operator == (const Edge &inRHS) const
  205. {
  206. return mIdx1 == inRHS.mIdx1 && mIdx2 == inRHS.mIdx2;
  207. }
  208. int mIdx1;
  209. int mIdx2;
  210. };
  211. JPH_MAKE_HASH_STRUCT(Edge, EdgeHash, t.mIdx1, t.mIdx2)
  212. // A struct to hold the triangles that are connected to an edge
  213. struct TriangleIndices
  214. {
  215. uint mNumTriangles = 0;
  216. uint mTriangleIndices[2];
  217. };
  218. // Build a list of edge to triangles
  219. using EdgeToTriangle = UnorderedMap<Edge, TriangleIndices, EdgeHash>;
  220. EdgeToTriangle edge_to_triangle;
  221. edge_to_triangle.reserve(ioIndices.size() * 3);
  222. for (uint triangle_idx = 0; triangle_idx < ioIndices.size(); ++triangle_idx)
  223. {
  224. IndexedTriangle &triangle = ioIndices[triangle_idx];
  225. for (uint edge_idx = 0; edge_idx < 3; ++edge_idx)
  226. {
  227. Edge edge(triangle.mIdx[edge_idx], triangle.mIdx[(edge_idx + 1) % 3]);
  228. TriangleIndices &indices = edge_to_triangle[edge];
  229. if (indices.mNumTriangles < 2)
  230. {
  231. // Store index of triangle that connects to this edge
  232. indices.mTriangleIndices[indices.mNumTriangles] = triangle_idx;
  233. indices.mNumTriangles++;
  234. }
  235. else
  236. {
  237. // 3 or more triangles share an edge, mark this edge as active
  238. uint32 mask = 1 << (edge_idx + FLAGS_ACTIVE_EGDE_SHIFT);
  239. JPH_ASSERT((triangle.mMaterialIndex & mask) == 0);
  240. triangle.mMaterialIndex |= mask;
  241. }
  242. }
  243. }
  244. // Walk over all edges and determine which ones are active
  245. for (const EdgeToTriangle::value_type &edge : edge_to_triangle)
  246. {
  247. uint num_active = 0;
  248. if (edge.second.mNumTriangles == 1)
  249. {
  250. // Edge is not shared, it is an active edge
  251. num_active = 1;
  252. }
  253. else if (edge.second.mNumTriangles == 2)
  254. {
  255. // Simple shared edge, determine if edge is active based on the two adjacent triangles
  256. const IndexedTriangle &triangle1 = ioIndices[edge.second.mTriangleIndices[0]];
  257. const IndexedTriangle &triangle2 = ioIndices[edge.second.mTriangleIndices[1]];
  258. // Find which edge this is for both triangles
  259. uint edge_idx1 = edge.first.GetIndexInTriangle(triangle1);
  260. uint edge_idx2 = edge.first.GetIndexInTriangle(triangle2);
  261. // Construct a plane for triangle 1 (e1 = edge vertex 1, e2 = edge vertex 2, op = opposing vertex)
  262. Vec3 triangle1_e1 = Vec3(inVertices[triangle1.mIdx[edge_idx1]]);
  263. Vec3 triangle1_e2 = Vec3(inVertices[triangle1.mIdx[(edge_idx1 + 1) % 3]]);
  264. Vec3 triangle1_op = Vec3(inVertices[triangle1.mIdx[(edge_idx1 + 2) % 3]]);
  265. Plane triangle1_plane = Plane::sFromPointsCCW(triangle1_e1, triangle1_e2, triangle1_op);
  266. // Construct a plane for triangle 2
  267. Vec3 triangle2_e1 = Vec3(inVertices[triangle2.mIdx[edge_idx2]]);
  268. Vec3 triangle2_e2 = Vec3(inVertices[triangle2.mIdx[(edge_idx2 + 1) % 3]]);
  269. Vec3 triangle2_op = Vec3(inVertices[triangle2.mIdx[(edge_idx2 + 2) % 3]]);
  270. Plane triangle2_plane = Plane::sFromPointsCCW(triangle2_e1, triangle2_e2, triangle2_op);
  271. // Determine if the edge is active
  272. num_active = ActiveEdges::IsEdgeActive(triangle1_plane.GetNormal(), triangle2_plane.GetNormal(), triangle1_e2 - triangle1_e1)? 2 : 0;
  273. }
  274. else
  275. {
  276. // More edges incoming, we've already marked all edges beyond the 2nd as active
  277. num_active = 2;
  278. }
  279. // Mark edges of all original triangles active
  280. for (uint i = 0; i < num_active; ++i)
  281. {
  282. uint triangle_idx = edge.second.mTriangleIndices[i];
  283. IndexedTriangle &triangle = ioIndices[triangle_idx];
  284. uint edge_idx = edge.first.GetIndexInTriangle(triangle);
  285. uint32 mask = 1 << (edge_idx + FLAGS_ACTIVE_EGDE_SHIFT);
  286. JPH_ASSERT((triangle.mMaterialIndex & mask) == 0);
  287. triangle.mMaterialIndex |= mask;
  288. }
  289. }
  290. }
  291. MassProperties MeshShape::GetMassProperties() const
  292. {
  293. // Object should always be static, return default mass properties
  294. return MassProperties();
  295. }
  296. void MeshShape::DecodeSubShapeID(const SubShapeID &inSubShapeID, const void *&outTriangleBlock, uint32 &outTriangleIndex) const
  297. {
  298. // Get block
  299. SubShapeID triangle_idx_subshape_id;
  300. uint32 block_id = inSubShapeID.PopID(NodeCodec::DecodingContext::sTriangleBlockIDBits(mTree), triangle_idx_subshape_id);
  301. outTriangleBlock = NodeCodec::DecodingContext::sGetTriangleBlockStart(&mTree[0], block_id);
  302. // Fetch the triangle index
  303. SubShapeID remainder;
  304. outTriangleIndex = triangle_idx_subshape_id.PopID(NumTriangleBits, remainder);
  305. JPH_ASSERT(remainder.IsEmpty(), "Invalid subshape ID");
  306. }
  307. uint MeshShape::GetMaterialIndex(const SubShapeID &inSubShapeID) const
  308. {
  309. // Decode ID
  310. const void *block_start;
  311. uint32 triangle_idx;
  312. DecodeSubShapeID(inSubShapeID, block_start, triangle_idx);
  313. // Fetch the flags
  314. uint8 flags = TriangleCodec::DecodingContext::sGetFlags(block_start, triangle_idx);
  315. return flags & FLAGS_MATERIAL_MASK;
  316. }
  317. const PhysicsMaterial *MeshShape::GetMaterial(const SubShapeID &inSubShapeID) const
  318. {
  319. // Return the default material if there are no materials on this shape
  320. if (mMaterials.empty())
  321. return PhysicsMaterial::sDefault;
  322. return mMaterials[GetMaterialIndex(inSubShapeID)];
  323. }
  324. Vec3 MeshShape::GetSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inLocalSurfacePosition) const
  325. {
  326. // Decode ID
  327. const void *block_start;
  328. uint32 triangle_idx;
  329. DecodeSubShapeID(inSubShapeID, block_start, triangle_idx);
  330. // Decode triangle
  331. Vec3 v1, v2, v3;
  332. const TriangleCodec::DecodingContext triangle_ctx(sGetTriangleHeader(mTree));
  333. triangle_ctx.GetTriangle(block_start, triangle_idx, v1, v2, v3);
  334. // Calculate normal
  335. return (v3 - v2).Cross(v1 - v2).Normalized();
  336. }
  337. void MeshShape::GetSupportingFace(const SubShapeID &inSubShapeID, Vec3Arg inDirection, Vec3Arg inScale, Mat44Arg inCenterOfMassTransform, SupportingFace &outVertices) const
  338. {
  339. // Decode ID
  340. const void *block_start;
  341. uint32 triangle_idx;
  342. DecodeSubShapeID(inSubShapeID, block_start, triangle_idx);
  343. // Decode triangle
  344. const TriangleCodec::DecodingContext triangle_ctx(sGetTriangleHeader(mTree));
  345. outVertices.resize(3);
  346. triangle_ctx.GetTriangle(block_start, triangle_idx, outVertices[0], outVertices[1], outVertices[2]);
  347. // Flip triangle if scaled inside out
  348. if (ScaleHelpers::IsInsideOut(inScale))
  349. swap(outVertices[1], outVertices[2]);
  350. // Calculate transform with scale
  351. Mat44 transform = inCenterOfMassTransform.PreScaled(inScale);
  352. // Transform to world space
  353. for (Vec3 &v : outVertices)
  354. v = transform * v;
  355. }
  356. AABox MeshShape::GetLocalBounds() const
  357. {
  358. const NodeCodec::Header *header = sGetNodeHeader(mTree);
  359. return AABox(Vec3::sLoadFloat3Unsafe(header->mRootBoundsMin), Vec3::sLoadFloat3Unsafe(header->mRootBoundsMax));
  360. }
  361. uint MeshShape::GetSubShapeIDBitsRecursive() const
  362. {
  363. return NodeCodec::DecodingContext::sTriangleBlockIDBits(mTree) + NumTriangleBits;
  364. }
  365. template <class Visitor>
  366. JPH_INLINE void MeshShape::WalkTree(Visitor &ioVisitor) const
  367. {
  368. const NodeCodec::Header *header = sGetNodeHeader(mTree);
  369. NodeCodec::DecodingContext node_ctx(header);
  370. const TriangleCodec::DecodingContext triangle_ctx(sGetTriangleHeader(mTree));
  371. const uint8 *buffer_start = &mTree[0];
  372. node_ctx.WalkTree(buffer_start, triangle_ctx, ioVisitor);
  373. }
  374. template <class Visitor>
  375. JPH_INLINE void MeshShape::WalkTreePerTriangle(const SubShapeIDCreator &inSubShapeIDCreator2, Visitor &ioVisitor) const
  376. {
  377. struct ChainedVisitor
  378. {
  379. JPH_INLINE ChainedVisitor(Visitor &ioVisitor, const SubShapeIDCreator &inSubShapeIDCreator2, uint inTriangleBlockIDBits) :
  380. mVisitor(ioVisitor),
  381. mSubShapeIDCreator2(inSubShapeIDCreator2),
  382. mTriangleBlockIDBits(inTriangleBlockIDBits)
  383. {
  384. }
  385. JPH_INLINE bool ShouldAbort() const
  386. {
  387. return mVisitor.ShouldAbort();
  388. }
  389. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  390. {
  391. return mVisitor.ShouldVisitNode(inStackTop);
  392. }
  393. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  394. {
  395. return mVisitor.VisitNodes(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, ioProperties, inStackTop);
  396. }
  397. JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, const void *inTriangles, int inNumTriangles, uint32 inTriangleBlockID)
  398. {
  399. // Create ID for triangle block
  400. SubShapeIDCreator block_sub_shape_id = mSubShapeIDCreator2.PushID(inTriangleBlockID, mTriangleBlockIDBits);
  401. // Decode vertices and flags
  402. JPH_ASSERT(inNumTriangles <= MaxTrianglesPerLeaf);
  403. Vec3 vertices[MaxTrianglesPerLeaf * 3];
  404. uint8 flags[MaxTrianglesPerLeaf];
  405. ioContext.Unpack(inTriangles, inNumTriangles, vertices, flags);
  406. int triangle_idx = 0;
  407. for (const Vec3 *v = vertices, *v_end = vertices + inNumTriangles * 3; v < v_end; v += 3, triangle_idx++)
  408. {
  409. // Determine active edges
  410. uint8 active_edges = (flags[triangle_idx] >> FLAGS_ACTIVE_EGDE_SHIFT) & FLAGS_ACTIVE_EDGE_MASK;
  411. // Create ID for triangle
  412. SubShapeIDCreator triangle_sub_shape_id = block_sub_shape_id.PushID(triangle_idx, NumTriangleBits);
  413. mVisitor.VisitTriangle(v[0], v[1], v[2], active_edges, triangle_sub_shape_id.GetID());
  414. // Check if we should early out now
  415. if (mVisitor.ShouldAbort())
  416. break;
  417. }
  418. }
  419. Visitor & mVisitor;
  420. SubShapeIDCreator mSubShapeIDCreator2;
  421. uint mTriangleBlockIDBits;
  422. };
  423. ChainedVisitor visitor(ioVisitor, inSubShapeIDCreator2, NodeCodec::DecodingContext::sTriangleBlockIDBits(mTree));
  424. WalkTree(visitor);
  425. }
  426. #ifdef JPH_DEBUG_RENDERER
  427. void MeshShape::Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const
  428. {
  429. // Reset the batch if we switch coloring mode
  430. if (mCachedTrianglesColoredPerGroup != sDrawTriangleGroups || mCachedUseMaterialColors != inUseMaterialColors)
  431. {
  432. mGeometry = nullptr;
  433. mCachedTrianglesColoredPerGroup = sDrawTriangleGroups;
  434. mCachedUseMaterialColors = inUseMaterialColors;
  435. }
  436. if (mGeometry == nullptr)
  437. {
  438. struct Visitor
  439. {
  440. JPH_INLINE bool ShouldAbort() const
  441. {
  442. return false;
  443. }
  444. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  445. {
  446. return true;
  447. }
  448. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  449. {
  450. UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
  451. return CountAndSortTrues(valid, ioProperties);
  452. }
  453. JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID)
  454. {
  455. JPH_ASSERT(inNumTriangles <= MaxTrianglesPerLeaf);
  456. Vec3 vertices[MaxTrianglesPerLeaf * 3];
  457. ioContext.Unpack(inTriangles, inNumTriangles, vertices);
  458. if (mDrawTriangleGroups || !mUseMaterialColors || mMaterials.empty())
  459. {
  460. // Single color for mesh
  461. Color color = mDrawTriangleGroups? Color::sGetDistinctColor(mColorIdx++) : (mUseMaterialColors? PhysicsMaterial::sDefault->GetDebugColor() : Color::sWhite);
  462. for (const Vec3 *v = vertices, *v_end = vertices + inNumTriangles * 3; v < v_end; v += 3)
  463. mTriangles.push_back({ v[0], v[1], v[2], color });
  464. }
  465. else
  466. {
  467. // Per triangle color
  468. uint8 flags[MaxTrianglesPerLeaf];
  469. TriangleCodec::DecodingContext::sGetFlags(inTriangles, inNumTriangles, flags);
  470. const uint8 *f = flags;
  471. for (const Vec3 *v = vertices, *v_end = vertices + inNumTriangles * 3; v < v_end; v += 3, f++)
  472. mTriangles.push_back({ v[0], v[1], v[2], mMaterials[*f & FLAGS_MATERIAL_MASK]->GetDebugColor() });
  473. }
  474. }
  475. Array<DebugRenderer::Triangle> & mTriangles;
  476. const PhysicsMaterialList & mMaterials;
  477. bool mUseMaterialColors;
  478. bool mDrawTriangleGroups;
  479. int mColorIdx = 0;
  480. };
  481. Array<DebugRenderer::Triangle> triangles;
  482. Visitor visitor { triangles, mMaterials, mCachedUseMaterialColors, mCachedTrianglesColoredPerGroup };
  483. WalkTree(visitor);
  484. mGeometry = new DebugRenderer::Geometry(inRenderer->CreateTriangleBatch(triangles), GetLocalBounds());
  485. }
  486. // Test if the shape is scaled inside out
  487. DebugRenderer::ECullMode cull_mode = ScaleHelpers::IsInsideOut(inScale)? DebugRenderer::ECullMode::CullFrontFace : DebugRenderer::ECullMode::CullBackFace;
  488. // Determine the draw mode
  489. DebugRenderer::EDrawMode draw_mode = inDrawWireframe? DebugRenderer::EDrawMode::Wireframe : DebugRenderer::EDrawMode::Solid;
  490. // Draw the geometry
  491. inRenderer->DrawGeometry(inCenterOfMassTransform * Mat44::sScale(inScale), inColor, mGeometry, cull_mode, DebugRenderer::ECastShadow::On, draw_mode);
  492. if (sDrawTriangleOutlines)
  493. {
  494. struct Visitor
  495. {
  496. JPH_INLINE Visitor(DebugRenderer *inRenderer, RMat44Arg inTransform) :
  497. mRenderer(inRenderer),
  498. mTransform(inTransform)
  499. {
  500. }
  501. JPH_INLINE bool ShouldAbort() const
  502. {
  503. return false;
  504. }
  505. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  506. {
  507. return true;
  508. }
  509. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  510. {
  511. UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
  512. return CountAndSortTrues(valid, ioProperties);
  513. }
  514. JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, const void *inTriangles, int inNumTriangles, uint32 inTriangleBlockID)
  515. {
  516. // Decode vertices and flags
  517. JPH_ASSERT(inNumTriangles <= MaxTrianglesPerLeaf);
  518. Vec3 vertices[MaxTrianglesPerLeaf * 3];
  519. uint8 flags[MaxTrianglesPerLeaf];
  520. ioContext.Unpack(inTriangles, inNumTriangles, vertices, flags);
  521. // Loop through triangles
  522. const uint8 *f = flags;
  523. for (Vec3 *v = vertices, *v_end = vertices + inNumTriangles * 3; v < v_end; v += 3, ++f)
  524. {
  525. // Loop through edges
  526. for (uint edge_idx = 0; edge_idx < 3; ++edge_idx)
  527. {
  528. RVec3 v1 = mTransform * v[edge_idx];
  529. RVec3 v2 = mTransform * v[(edge_idx + 1) % 3];
  530. // Draw active edge as a green arrow, other edges as grey
  531. if (*f & (1 << (edge_idx + FLAGS_ACTIVE_EGDE_SHIFT)))
  532. mRenderer->DrawArrow(v1, v2, Color::sGreen, 0.01f);
  533. else
  534. mRenderer->DrawLine(v1, v2, Color::sGrey);
  535. }
  536. }
  537. }
  538. DebugRenderer * mRenderer;
  539. RMat44 mTransform;
  540. };
  541. Visitor visitor { inRenderer, inCenterOfMassTransform.PreScaled(inScale) };
  542. WalkTree(visitor);
  543. }
  544. }
  545. #endif // JPH_DEBUG_RENDERER
  546. bool MeshShape::CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const
  547. {
  548. JPH_PROFILE_FUNCTION();
  549. struct Visitor
  550. {
  551. JPH_INLINE explicit Visitor(RayCastResult &ioHit) :
  552. mHit(ioHit)
  553. {
  554. }
  555. JPH_INLINE bool ShouldAbort() const
  556. {
  557. return mHit.mFraction <= 0.0f;
  558. }
  559. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  560. {
  561. return mDistanceStack[inStackTop] < mHit.mFraction;
  562. }
  563. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  564. {
  565. // Test bounds of 4 children
  566. Vec4 distance = RayAABox4(mRayOrigin, mRayInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  567. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  568. return SortReverseAndStore(distance, mHit.mFraction, ioProperties, &mDistanceStack[inStackTop]);
  569. }
  570. JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, const void *inTriangles, int inNumTriangles, uint32 inTriangleBlockID)
  571. {
  572. // Test against triangles
  573. uint32 triangle_idx;
  574. float fraction = ioContext.TestRay(mRayOrigin, mRayDirection, inTriangles, inNumTriangles, mHit.mFraction, triangle_idx);
  575. if (fraction < mHit.mFraction)
  576. {
  577. mHit.mFraction = fraction;
  578. mHit.mSubShapeID2 = mSubShapeIDCreator.PushID(inTriangleBlockID, mTriangleBlockIDBits).PushID(triangle_idx, NumTriangleBits).GetID();
  579. mReturnValue = true;
  580. }
  581. }
  582. RayCastResult & mHit;
  583. Vec3 mRayOrigin;
  584. Vec3 mRayDirection;
  585. RayInvDirection mRayInvDirection;
  586. uint mTriangleBlockIDBits;
  587. SubShapeIDCreator mSubShapeIDCreator;
  588. bool mReturnValue = false;
  589. float mDistanceStack[NodeCodec::StackSize];
  590. };
  591. Visitor visitor(ioHit);
  592. visitor.mRayOrigin = inRay.mOrigin;
  593. visitor.mRayDirection = inRay.mDirection;
  594. visitor.mRayInvDirection.Set(inRay.mDirection);
  595. visitor.mTriangleBlockIDBits = NodeCodec::DecodingContext::sTriangleBlockIDBits(mTree);
  596. visitor.mSubShapeIDCreator = inSubShapeIDCreator;
  597. WalkTree(visitor);
  598. return visitor.mReturnValue;
  599. }
  600. void MeshShape::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  601. {
  602. JPH_PROFILE_FUNCTION();
  603. // Test shape filter
  604. if (!inShapeFilter.ShouldCollide(inSubShapeIDCreator.GetID()))
  605. return;
  606. struct Visitor
  607. {
  608. JPH_INLINE explicit Visitor(CastRayCollector &ioCollector) :
  609. mCollector(ioCollector)
  610. {
  611. }
  612. JPH_INLINE bool ShouldAbort() const
  613. {
  614. return mCollector.ShouldEarlyOut();
  615. }
  616. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  617. {
  618. return mDistanceStack[inStackTop] < mCollector.GetEarlyOutFraction();
  619. }
  620. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  621. {
  622. // Test bounds of 4 children
  623. Vec4 distance = RayAABox4(mRayOrigin, mRayInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  624. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  625. return SortReverseAndStore(distance, mCollector.GetEarlyOutFraction(), ioProperties, &mDistanceStack[inStackTop]);
  626. }
  627. JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, [[maybe_unused]] uint8 inActiveEdges, SubShapeID inSubShapeID2)
  628. {
  629. // Back facing check
  630. if (mBackFaceMode == EBackFaceMode::IgnoreBackFaces && (inV2 - inV0).Cross(inV1 - inV0).Dot(mRayDirection) < 0)
  631. return;
  632. // Check the triangle
  633. float fraction = RayTriangle(mRayOrigin, mRayDirection, inV0, inV1, inV2);
  634. if (fraction < mCollector.GetEarlyOutFraction())
  635. {
  636. RayCastResult hit;
  637. hit.mBodyID = TransformedShape::sGetBodyID(mCollector.GetContext());
  638. hit.mFraction = fraction;
  639. hit.mSubShapeID2 = inSubShapeID2;
  640. mCollector.AddHit(hit);
  641. }
  642. }
  643. CastRayCollector & mCollector;
  644. Vec3 mRayOrigin;
  645. Vec3 mRayDirection;
  646. RayInvDirection mRayInvDirection;
  647. EBackFaceMode mBackFaceMode;
  648. float mDistanceStack[NodeCodec::StackSize];
  649. };
  650. Visitor visitor(ioCollector);
  651. visitor.mBackFaceMode = inRayCastSettings.mBackFaceMode;
  652. visitor.mRayOrigin = inRay.mOrigin;
  653. visitor.mRayDirection = inRay.mDirection;
  654. visitor.mRayInvDirection.Set(inRay.mDirection);
  655. WalkTreePerTriangle(inSubShapeIDCreator, visitor);
  656. }
  657. void MeshShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  658. {
  659. // First test if we're inside our bounding box
  660. AABox bounds = GetLocalBounds();
  661. if (bounds.Contains(inPoint))
  662. {
  663. // A collector that just counts the number of hits
  664. class HitCountCollector : public CastRayCollector
  665. {
  666. public:
  667. virtual void AddHit(const RayCastResult &inResult) override
  668. {
  669. // Store the last sub shape ID so that we can provide something to our outer hit collector
  670. mSubShapeID = inResult.mSubShapeID2;
  671. ++mHitCount;
  672. }
  673. int mHitCount = 0;
  674. SubShapeID mSubShapeID;
  675. };
  676. HitCountCollector collector;
  677. // Configure the raycast
  678. RayCastSettings settings;
  679. settings.mBackFaceMode = EBackFaceMode::CollideWithBackFaces;
  680. // Cast a ray that's 10% longer than the heigth of our bounding box
  681. CastRay(RayCast { inPoint, 1.1f * bounds.GetSize().GetY() * Vec3::sAxisY() }, settings, inSubShapeIDCreator, collector, inShapeFilter);
  682. // Odd amount of hits means inside
  683. if ((collector.mHitCount & 1) == 1)
  684. ioCollector.AddHit({ TransformedShape::sGetBodyID(ioCollector.GetContext()), collector.mSubShapeID });
  685. }
  686. }
  687. void MeshShape::sCastConvexVsMesh(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
  688. {
  689. JPH_PROFILE_FUNCTION();
  690. struct Visitor : public CastConvexVsTriangles
  691. {
  692. using CastConvexVsTriangles::CastConvexVsTriangles;
  693. JPH_INLINE bool ShouldAbort() const
  694. {
  695. return mCollector.ShouldEarlyOut();
  696. }
  697. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  698. {
  699. return mDistanceStack[inStackTop] < mCollector.GetEarlyOutFraction();
  700. }
  701. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  702. {
  703. // Scale the bounding boxes of this node
  704. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  705. AABox4Scale(mScale, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  706. // Enlarge them by the casted shape's box extents
  707. AABox4EnlargeWithExtent(mBoxExtent, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  708. // Test bounds of 4 children
  709. Vec4 distance = RayAABox4(mBoxCenter, mInvDirection, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  710. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  711. return SortReverseAndStore(distance, mCollector.GetEarlyOutFraction(), ioProperties, &mDistanceStack[inStackTop]);
  712. }
  713. JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2)
  714. {
  715. Cast(inV0, inV1, inV2, inActiveEdges, inSubShapeID2);
  716. }
  717. RayInvDirection mInvDirection;
  718. Vec3 mBoxCenter;
  719. Vec3 mBoxExtent;
  720. float mDistanceStack[NodeCodec::StackSize];
  721. };
  722. JPH_ASSERT(inShape->GetSubType() == EShapeSubType::Mesh);
  723. const MeshShape *shape = static_cast<const MeshShape *>(inShape);
  724. Visitor visitor(inShapeCast, inShapeCastSettings, inScale, inShapeFilter, inCenterOfMassTransform2, inSubShapeIDCreator1, ioCollector);
  725. visitor.mInvDirection.Set(inShapeCast.mDirection);
  726. visitor.mBoxCenter = inShapeCast.mShapeWorldBounds.GetCenter();
  727. visitor.mBoxExtent = inShapeCast.mShapeWorldBounds.GetExtent();
  728. shape->WalkTreePerTriangle(inSubShapeIDCreator2, visitor);
  729. }
  730. void MeshShape::sCastSphereVsMesh(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
  731. {
  732. JPH_PROFILE_FUNCTION();
  733. struct Visitor : public CastSphereVsTriangles
  734. {
  735. using CastSphereVsTriangles::CastSphereVsTriangles;
  736. JPH_INLINE bool ShouldAbort() const
  737. {
  738. return mCollector.ShouldEarlyOut();
  739. }
  740. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  741. {
  742. return mDistanceStack[inStackTop] < mCollector.GetEarlyOutFraction();
  743. }
  744. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  745. {
  746. // Scale the bounding boxes of this node
  747. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  748. AABox4Scale(mScale, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  749. // Enlarge them by the radius of the sphere
  750. AABox4EnlargeWithExtent(Vec3::sReplicate(mRadius), bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  751. // Test bounds of 4 children
  752. Vec4 distance = RayAABox4(mStart, mInvDirection, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  753. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  754. return SortReverseAndStore(distance, mCollector.GetEarlyOutFraction(), ioProperties, &mDistanceStack[inStackTop]);
  755. }
  756. JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2)
  757. {
  758. Cast(inV0, inV1, inV2, inActiveEdges, inSubShapeID2);
  759. }
  760. RayInvDirection mInvDirection;
  761. float mDistanceStack[NodeCodec::StackSize];
  762. };
  763. JPH_ASSERT(inShape->GetSubType() == EShapeSubType::Mesh);
  764. const MeshShape *shape = static_cast<const MeshShape *>(inShape);
  765. Visitor visitor(inShapeCast, inShapeCastSettings, inScale, inShapeFilter, inCenterOfMassTransform2, inSubShapeIDCreator1, ioCollector);
  766. visitor.mInvDirection.Set(inShapeCast.mDirection);
  767. shape->WalkTreePerTriangle(inSubShapeIDCreator2, visitor);
  768. }
  769. struct MeshShape::MSGetTrianglesContext
  770. {
  771. JPH_INLINE MSGetTrianglesContext(const MeshShape *inShape, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) :
  772. mDecodeCtx(sGetNodeHeader(inShape->mTree)),
  773. mShape(inShape),
  774. mLocalBox(Mat44::sInverseRotationTranslation(inRotation, inPositionCOM), inBox),
  775. mMeshScale(inScale),
  776. mLocalToWorld(Mat44::sRotationTranslation(inRotation, inPositionCOM) * Mat44::sScale(inScale)),
  777. mIsInsideOut(ScaleHelpers::IsInsideOut(inScale))
  778. {
  779. }
  780. JPH_INLINE bool ShouldAbort() const
  781. {
  782. return mShouldAbort;
  783. }
  784. JPH_INLINE bool ShouldVisitNode([[maybe_unused]] int inStackTop) const
  785. {
  786. return true;
  787. }
  788. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  789. {
  790. // Scale the bounding boxes of this node
  791. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  792. AABox4Scale(mMeshScale, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  793. // Test which nodes collide
  794. UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  795. return CountAndSortTrues(collides, ioProperties);
  796. }
  797. JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID)
  798. {
  799. // When the buffer is full and we cannot process the triangles, abort the tree walk. The next time GetTrianglesNext is called we will continue here.
  800. if (mNumTrianglesFound + inNumTriangles > mMaxTrianglesRequested)
  801. {
  802. mShouldAbort = true;
  803. return;
  804. }
  805. // Decode vertices
  806. JPH_ASSERT(inNumTriangles <= MaxTrianglesPerLeaf);
  807. Vec3 vertices[MaxTrianglesPerLeaf * 3];
  808. ioContext.Unpack(inTriangles, inNumTriangles, vertices);
  809. // Store vertices as Float3
  810. if (mIsInsideOut)
  811. {
  812. // Scaled inside out, flip the triangles
  813. for (const Vec3 *v = vertices, *v_end = v + 3 * inNumTriangles; v < v_end; v += 3)
  814. {
  815. (mLocalToWorld * v[0]).StoreFloat3(mTriangleVertices++);
  816. (mLocalToWorld * v[2]).StoreFloat3(mTriangleVertices++);
  817. (mLocalToWorld * v[1]).StoreFloat3(mTriangleVertices++);
  818. }
  819. }
  820. else
  821. {
  822. // Normal scale
  823. for (const Vec3 *v = vertices, *v_end = v + 3 * inNumTriangles; v < v_end; ++v)
  824. (mLocalToWorld * *v).StoreFloat3(mTriangleVertices++);
  825. }
  826. if (mMaterials != nullptr)
  827. {
  828. if (mShape->mMaterials.empty())
  829. {
  830. // No materials, output default
  831. const PhysicsMaterial *default_material = PhysicsMaterial::sDefault;
  832. for (int m = 0; m < inNumTriangles; ++m)
  833. *mMaterials++ = default_material;
  834. }
  835. else
  836. {
  837. // Decode triangle flags
  838. uint8 flags[MaxTrianglesPerLeaf];
  839. TriangleCodec::DecodingContext::sGetFlags(inTriangles, inNumTriangles, flags);
  840. // Store materials
  841. for (const uint8 *f = flags, *f_end = f + inNumTriangles; f < f_end; ++f)
  842. *mMaterials++ = mShape->mMaterials[*f & FLAGS_MATERIAL_MASK].GetPtr();
  843. }
  844. }
  845. // Accumulate triangles found
  846. mNumTrianglesFound += inNumTriangles;
  847. }
  848. NodeCodec::DecodingContext mDecodeCtx;
  849. const MeshShape * mShape;
  850. OrientedBox mLocalBox;
  851. Vec3 mMeshScale;
  852. Mat44 mLocalToWorld;
  853. int mMaxTrianglesRequested;
  854. Float3 * mTriangleVertices;
  855. int mNumTrianglesFound;
  856. const PhysicsMaterial ** mMaterials;
  857. bool mShouldAbort;
  858. bool mIsInsideOut;
  859. };
  860. void MeshShape::GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const
  861. {
  862. static_assert(sizeof(MSGetTrianglesContext) <= sizeof(GetTrianglesContext), "GetTrianglesContext too small");
  863. JPH_ASSERT(IsAligned(&ioContext, alignof(MSGetTrianglesContext)));
  864. new (&ioContext) MSGetTrianglesContext(this, inBox, inPositionCOM, inRotation, inScale);
  865. }
  866. int MeshShape::GetTrianglesNext(GetTrianglesContext &ioContext, int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials) const
  867. {
  868. static_assert(cGetTrianglesMinTrianglesRequested >= MaxTrianglesPerLeaf, "cGetTrianglesMinTrianglesRequested is too small");
  869. JPH_ASSERT(inMaxTrianglesRequested >= cGetTrianglesMinTrianglesRequested);
  870. // Check if we're done
  871. MSGetTrianglesContext &context = (MSGetTrianglesContext &)ioContext;
  872. if (context.mDecodeCtx.IsDoneWalking())
  873. return 0;
  874. // Store parameters on context
  875. context.mMaxTrianglesRequested = inMaxTrianglesRequested;
  876. context.mTriangleVertices = outTriangleVertices;
  877. context.mMaterials = outMaterials;
  878. context.mShouldAbort = false; // Reset the abort flag
  879. context.mNumTrianglesFound = 0;
  880. // Continue (or start) walking the tree
  881. const TriangleCodec::DecodingContext triangle_ctx(sGetTriangleHeader(mTree));
  882. const uint8 *buffer_start = &mTree[0];
  883. context.mDecodeCtx.WalkTree(buffer_start, triangle_ctx, context);
  884. return context.mNumTrianglesFound;
  885. }
  886. void MeshShape::sCollideConvexVsMesh(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, [[maybe_unused]] const ShapeFilter &inShapeFilter)
  887. {
  888. JPH_PROFILE_FUNCTION();
  889. // Get the shapes
  890. JPH_ASSERT(inShape1->GetType() == EShapeType::Convex);
  891. JPH_ASSERT(inShape2->GetType() == EShapeType::Mesh);
  892. const ConvexShape *shape1 = static_cast<const ConvexShape *>(inShape1);
  893. const MeshShape *shape2 = static_cast<const MeshShape *>(inShape2);
  894. struct Visitor : public CollideConvexVsTriangles
  895. {
  896. using CollideConvexVsTriangles::CollideConvexVsTriangles;
  897. JPH_INLINE bool ShouldAbort() const
  898. {
  899. return mCollector.ShouldEarlyOut();
  900. }
  901. JPH_INLINE bool ShouldVisitNode([[maybe_unused]] int inStackTop) const
  902. {
  903. return true;
  904. }
  905. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  906. {
  907. // Scale the bounding boxes of this node
  908. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  909. AABox4Scale(mScale2, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  910. // Test which nodes collide
  911. UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  912. return CountAndSortTrues(collides, ioProperties);
  913. }
  914. JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2)
  915. {
  916. Collide(inV0, inV1, inV2, inActiveEdges, inSubShapeID2);
  917. }
  918. };
  919. Visitor visitor(shape1, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1.GetID(), inCollideShapeSettings, ioCollector);
  920. shape2->WalkTreePerTriangle(inSubShapeIDCreator2, visitor);
  921. }
  922. void MeshShape::sCollideSphereVsMesh(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, [[maybe_unused]] const ShapeFilter &inShapeFilter)
  923. {
  924. JPH_PROFILE_FUNCTION();
  925. // Get the shapes
  926. JPH_ASSERT(inShape1->GetSubType() == EShapeSubType::Sphere);
  927. JPH_ASSERT(inShape2->GetType() == EShapeType::Mesh);
  928. const SphereShape *shape1 = static_cast<const SphereShape *>(inShape1);
  929. const MeshShape *shape2 = static_cast<const MeshShape *>(inShape2);
  930. struct Visitor : public CollideSphereVsTriangles
  931. {
  932. using CollideSphereVsTriangles::CollideSphereVsTriangles;
  933. JPH_INLINE bool ShouldAbort() const
  934. {
  935. return mCollector.ShouldEarlyOut();
  936. }
  937. JPH_INLINE bool ShouldVisitNode([[maybe_unused]] int inStackTop) const
  938. {
  939. return true;
  940. }
  941. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  942. {
  943. // Scale the bounding boxes of this node
  944. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  945. AABox4Scale(mScale2, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  946. // Test which nodes collide
  947. UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  948. return CountAndSortTrues(collides, ioProperties);
  949. }
  950. JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2)
  951. {
  952. Collide(inV0, inV1, inV2, inActiveEdges, inSubShapeID2);
  953. }
  954. };
  955. Visitor visitor(shape1, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1.GetID(), inCollideShapeSettings, ioCollector);
  956. shape2->WalkTreePerTriangle(inSubShapeIDCreator2, visitor);
  957. }
  958. void MeshShape::SaveBinaryState(StreamOut &inStream) const
  959. {
  960. Shape::SaveBinaryState(inStream);
  961. inStream.Write(static_cast<const ByteBufferVector &>(mTree)); // Make sure we use the Array<> overload
  962. }
  963. void MeshShape::RestoreBinaryState(StreamIn &inStream)
  964. {
  965. Shape::RestoreBinaryState(inStream);
  966. inStream.Read(static_cast<ByteBufferVector &>(mTree)); // Make sure we use the Array<> overload
  967. }
  968. void MeshShape::SaveMaterialState(PhysicsMaterialList &outMaterials) const
  969. {
  970. outMaterials = mMaterials;
  971. }
  972. void MeshShape::RestoreMaterialState(const PhysicsMaterialRefC *inMaterials, uint inNumMaterials)
  973. {
  974. mMaterials.assign(inMaterials, inMaterials + inNumMaterials);
  975. }
  976. Shape::Stats MeshShape::GetStats() const
  977. {
  978. // Walk the tree to count the triangles
  979. struct Visitor
  980. {
  981. JPH_INLINE bool ShouldAbort() const
  982. {
  983. return false;
  984. }
  985. JPH_INLINE bool ShouldVisitNode([[maybe_unused]] int inStackTop) const
  986. {
  987. return true;
  988. }
  989. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  990. {
  991. // Visit all valid children
  992. UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
  993. return CountAndSortTrues(valid, ioProperties);
  994. }
  995. JPH_INLINE void VisitTriangles([[maybe_unused]] const TriangleCodec::DecodingContext &ioContext, [[maybe_unused]] const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID)
  996. {
  997. mNumTriangles += inNumTriangles;
  998. }
  999. uint mNumTriangles = 0;
  1000. };
  1001. Visitor visitor;
  1002. WalkTree(visitor);
  1003. return Stats(sizeof(*this) + mMaterials.size() * sizeof(Ref<PhysicsMaterial>) + mTree.size() * sizeof(uint8), visitor.mNumTriangles);
  1004. }
  1005. void MeshShape::sRegister()
  1006. {
  1007. ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::Mesh);
  1008. f.mConstruct = []() -> Shape * { return new MeshShape; };
  1009. f.mColor = Color::sRed;
  1010. for (EShapeSubType s : sConvexSubShapeTypes)
  1011. {
  1012. CollisionDispatch::sRegisterCollideShape(s, EShapeSubType::Mesh, sCollideConvexVsMesh);
  1013. CollisionDispatch::sRegisterCastShape(s, EShapeSubType::Mesh, sCastConvexVsMesh);
  1014. CollisionDispatch::sRegisterCastShape(EShapeSubType::Mesh, s, CollisionDispatch::sReversedCastShape);
  1015. CollisionDispatch::sRegisterCollideShape(EShapeSubType::Mesh, s, CollisionDispatch::sReversedCollideShape);
  1016. }
  1017. // Specialized collision functions
  1018. CollisionDispatch::sRegisterCollideShape(EShapeSubType::Sphere, EShapeSubType::Mesh, sCollideSphereVsMesh);
  1019. CollisionDispatch::sRegisterCastShape(EShapeSubType::Sphere, EShapeSubType::Mesh, sCastSphereVsMesh);
  1020. }
  1021. JPH_NAMESPACE_END