GetTrianglesContext.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Physics/Collision/Shape/Shape.h>
  6. JPH_NAMESPACE_BEGIN
  7. class PhysicsMaterial;
  8. /// Implementation of GetTrianglesStart/Next that uses a fixed list of vertices for the triangles. These are transformed into world space when getting the triangles.
  9. class GetTrianglesContextVertexList
  10. {
  11. public:
  12. /// Constructor, to be called in GetTrianglesStart
  13. GetTrianglesContextVertexList(Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, Mat44Arg inLocalTransform, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices, const PhysicsMaterial *inMaterial) :
  14. mLocalToWorld(Mat44::sRotationTranslation(inRotation, inPositionCOM) * Mat44::sScale(inScale) * inLocalTransform),
  15. mTriangleVertices(inTriangleVertices),
  16. mNumTriangleVertices(inNumTriangleVertices),
  17. mMaterial(inMaterial),
  18. mIsInsideOut(ScaleHelpers::IsInsideOut(inScale))
  19. {
  20. static_assert(sizeof(GetTrianglesContextVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");
  21. JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextVertexList)));
  22. JPH_ASSERT(inNumTriangleVertices % 3 == 0);
  23. }
  24. /// @see Shape::GetTrianglesNext
  25. int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)
  26. {
  27. JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);
  28. int total_num_vertices = min(inMaxTrianglesRequested * 3, int(mNumTriangleVertices - mCurrentVertex));
  29. if (mIsInsideOut)
  30. {
  31. // Store triangles flipped
  32. for (const Vec3 *v = mTriangleVertices + mCurrentVertex, *v_end = v + total_num_vertices; v < v_end; v += 3)
  33. {
  34. (mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
  35. (mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
  36. (mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
  37. }
  38. }
  39. else
  40. {
  41. // Store triangles
  42. for (const Vec3 *v = mTriangleVertices + mCurrentVertex, *v_end = v + total_num_vertices; v < v_end; v += 3)
  43. {
  44. (mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
  45. (mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
  46. (mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
  47. }
  48. }
  49. // Update the current vertex to point to the next vertex to get
  50. mCurrentVertex += total_num_vertices;
  51. int total_num_triangles = total_num_vertices / 3;
  52. // Store materials
  53. if (outMaterials != nullptr)
  54. for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)
  55. *m = mMaterial;
  56. return total_num_triangles;
  57. }
  58. /// Helper function that creates a vertex list of a half unit sphere (top part)
  59. template <class A>
  60. static void sCreateHalfUnitSphereTop(A &ioVertices, int inDetailLevel)
  61. {
  62. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);
  63. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);
  64. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);
  65. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);
  66. }
  67. /// Helper function that creates a vertex list of a half unit sphere (bottom part)
  68. template <class A>
  69. static void sCreateHalfUnitSphereBottom(A &ioVertices, int inDetailLevel)
  70. {
  71. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);
  72. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);
  73. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);
  74. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);
  75. }
  76. /// Helper function that creates an open cylinder of half height 1 and radius 1
  77. template <class A>
  78. static void sCreateUnitOpenCylinder(A &ioVertices, int inDetailLevel)
  79. {
  80. const Vec3 bottom_offset(0.0f, -2.0f, 0.0f);
  81. int num_verts = 4 * (1 << inDetailLevel);
  82. for (int i = 0; i < num_verts; ++i)
  83. {
  84. float angle1 = 2.0f * JPH_PI * (float(i) / num_verts);
  85. float angle2 = 2.0f * JPH_PI * (float(i + 1) / num_verts);
  86. Vec3 t1(Sin(angle1), 1.0f, Cos(angle1));
  87. Vec3 t2(Sin(angle2), 1.0f, Cos(angle2));
  88. Vec3 b1 = t1 + bottom_offset;
  89. Vec3 b2 = t2 + bottom_offset;
  90. ioVertices.push_back(t1);
  91. ioVertices.push_back(b1);
  92. ioVertices.push_back(t2);
  93. ioVertices.push_back(t2);
  94. ioVertices.push_back(b1);
  95. ioVertices.push_back(b2);
  96. }
  97. }
  98. private:
  99. /// Recursive helper function for creating a sphere
  100. template <class A>
  101. static void sCreateUnitSphereHelper(A &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, int inLevel)
  102. {
  103. Vec3 center1 = (inV1 + inV2).Normalized();
  104. Vec3 center2 = (inV2 + inV3).Normalized();
  105. Vec3 center3 = (inV3 + inV1).Normalized();
  106. if (inLevel > 0)
  107. {
  108. int new_level = inLevel - 1;
  109. sCreateUnitSphereHelper(ioVertices, inV1, center1, center3, new_level);
  110. sCreateUnitSphereHelper(ioVertices, center1, center2, center3, new_level);
  111. sCreateUnitSphereHelper(ioVertices, center1, inV2, center2, new_level);
  112. sCreateUnitSphereHelper(ioVertices, center3, center2, inV3, new_level);
  113. }
  114. else
  115. {
  116. ioVertices.push_back(inV1);
  117. ioVertices.push_back(inV2);
  118. ioVertices.push_back(inV3);
  119. }
  120. }
  121. Mat44 mLocalToWorld;
  122. const Vec3 * mTriangleVertices;
  123. size_t mNumTriangleVertices;
  124. size_t mCurrentVertex = 0;
  125. const PhysicsMaterial * mMaterial;
  126. bool mIsInsideOut;
  127. };
  128. /// Implementation of GetTrianglesStart/Next that uses a multiple fixed lists of vertices for the triangles. These are transformed into world space when getting the triangles.
  129. class GetTrianglesContextMultiVertexList
  130. {
  131. public:
  132. /// Constructor, to be called in GetTrianglesStart
  133. GetTrianglesContextMultiVertexList(bool inIsInsideOut, const PhysicsMaterial *inMaterial) :
  134. mMaterial(inMaterial),
  135. mIsInsideOut(inIsInsideOut)
  136. {
  137. static_assert(sizeof(GetTrianglesContextMultiVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");
  138. JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextMultiVertexList)));
  139. }
  140. /// Add a mesh part and its transform
  141. void AddPart(Mat44Arg inLocalToWorld, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices)
  142. {
  143. JPH_ASSERT(inNumTriangleVertices % 3 == 0);
  144. mParts.push_back({ inLocalToWorld, inTriangleVertices, inNumTriangleVertices });
  145. }
  146. /// @see Shape::GetTrianglesNext
  147. int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)
  148. {
  149. JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);
  150. int total_num_vertices = 0;
  151. int max_vertices_requested = inMaxTrianglesRequested * 3;
  152. // Loop over parts
  153. for (; mCurrentPart < mParts.size(); ++mCurrentPart)
  154. {
  155. const Part &part = mParts[mCurrentPart];
  156. // Calculate how many vertices to take from this part
  157. int part_num_vertices = min(max_vertices_requested, int(part.mNumTriangleVertices - mCurrentVertex));
  158. if (part_num_vertices == 0)
  159. break;
  160. max_vertices_requested -= part_num_vertices;
  161. total_num_vertices += part_num_vertices;
  162. if (mIsInsideOut)
  163. {
  164. // Store triangles flipped
  165. for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)
  166. {
  167. (part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
  168. (part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
  169. (part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
  170. }
  171. }
  172. else
  173. {
  174. // Store triangles
  175. for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)
  176. {
  177. (part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
  178. (part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
  179. (part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
  180. }
  181. }
  182. // Update the current vertex to point to the next vertex to get
  183. mCurrentVertex += part_num_vertices;
  184. // Check if we completed this part
  185. if (mCurrentVertex < part.mNumTriangleVertices)
  186. break;
  187. // Reset current vertex for the next part
  188. mCurrentVertex = 0;
  189. }
  190. int total_num_triangles = total_num_vertices / 3;
  191. // Store materials
  192. if (outMaterials != nullptr)
  193. for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)
  194. *m = mMaterial;
  195. return total_num_triangles;
  196. }
  197. private:
  198. struct Part
  199. {
  200. Mat44 mLocalToWorld;
  201. const Vec3 * mTriangleVertices;
  202. size_t mNumTriangleVertices;
  203. };
  204. StaticArray<Part, 3> mParts;
  205. uint mCurrentPart = 0;
  206. size_t mCurrentVertex = 0;
  207. const PhysicsMaterial * mMaterial;
  208. bool mIsInsideOut;
  209. };
  210. JPH_NAMESPACE_END