MeshShape.cpp 39 KB

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