MeshShape.cpp 40 KB

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