MeshShape.cpp 39 KB

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