MeshShape.cpp 49 KB

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