GetTrianglesContext.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. static void sCreateHalfUnitSphereTop(std::vector<Vec3> &ioVertices, int inDetailLevel)
  60. {
  61. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);
  62. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);
  63. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);
  64. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);
  65. }
  66. /// Helper function that creates a vertex list of a half unit sphere (bottom part)
  67. static void sCreateHalfUnitSphereBottom(std::vector<Vec3> &ioVertices, int inDetailLevel)
  68. {
  69. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);
  70. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);
  71. sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);
  72. sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);
  73. }
  74. /// Helper function that creates an open cyclinder of half height 1 and radius 1
  75. static void sCreateUnitOpenCylinder(std::vector<Vec3> &ioVertices, int inDetailLevel)
  76. {
  77. const Vec3 bottom_offset(0.0f, -2.0f, 0.0f);
  78. int num_verts = 4 * (1 << inDetailLevel);
  79. for (int i = 0; i < num_verts; ++i)
  80. {
  81. float angle1 = 2.0f * JPH_PI * (float(i) / num_verts);
  82. float angle2 = 2.0f * JPH_PI * (float(i + 1) / num_verts);
  83. Vec3 t1(Sin(angle1), 1.0f, Cos(angle1));
  84. Vec3 t2(Sin(angle2), 1.0f, Cos(angle2));
  85. Vec3 b1 = t1 + bottom_offset;
  86. Vec3 b2 = t2 + bottom_offset;
  87. ioVertices.push_back(t1);
  88. ioVertices.push_back(b1);
  89. ioVertices.push_back(t2);
  90. ioVertices.push_back(t2);
  91. ioVertices.push_back(b1);
  92. ioVertices.push_back(b2);
  93. }
  94. }
  95. private:
  96. /// Recursive helper function for creating a sphere
  97. static void sCreateUnitSphereHelper(std::vector<Vec3> &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, int inLevel)
  98. {
  99. Vec3 center1 = (inV1 + inV2).Normalized();
  100. Vec3 center2 = (inV2 + inV3).Normalized();
  101. Vec3 center3 = (inV3 + inV1).Normalized();
  102. if (inLevel > 0)
  103. {
  104. int new_level = inLevel - 1;
  105. sCreateUnitSphereHelper(ioVertices, inV1, center1, center3, new_level);
  106. sCreateUnitSphereHelper(ioVertices, center1, center2, center3, new_level);
  107. sCreateUnitSphereHelper(ioVertices, center1, inV2, center2, new_level);
  108. sCreateUnitSphereHelper(ioVertices, center3, center2, inV3, new_level);
  109. }
  110. else
  111. {
  112. ioVertices.push_back(inV1);
  113. ioVertices.push_back(inV2);
  114. ioVertices.push_back(inV3);
  115. }
  116. }
  117. Mat44 mLocalToWorld;
  118. const Vec3 * mTriangleVertices;
  119. size_t mNumTriangleVertices;
  120. size_t mCurrentVertex = 0;
  121. const PhysicsMaterial * mMaterial;
  122. bool mIsInsideOut;
  123. };
  124. /// 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.
  125. class GetTrianglesContextMultiVertexList
  126. {
  127. public:
  128. /// Constructor, to be called in GetTrianglesStart
  129. GetTrianglesContextMultiVertexList(bool inIsInsideOut, const PhysicsMaterial *inMaterial) :
  130. mMaterial(inMaterial),
  131. mIsInsideOut(inIsInsideOut)
  132. {
  133. static_assert(sizeof(GetTrianglesContextMultiVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");
  134. JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextMultiVertexList)));
  135. }
  136. /// Add a mesh part and its transform
  137. void AddPart(Mat44Arg inLocalToWorld, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices)
  138. {
  139. JPH_ASSERT(inNumTriangleVertices % 3 == 0);
  140. mParts.push_back({ inLocalToWorld, inTriangleVertices, inNumTriangleVertices });
  141. }
  142. /// @see Shape::GetTrianglesNext
  143. int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)
  144. {
  145. JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);
  146. int total_num_vertices = 0;
  147. int max_vertices_requested = inMaxTrianglesRequested * 3;
  148. // Loop over parts
  149. for (; mCurrentPart < mParts.size(); ++mCurrentPart)
  150. {
  151. const Part &part = mParts[mCurrentPart];
  152. // Calculate how many vertices to take from this part
  153. int part_num_vertices = min(max_vertices_requested, int(part.mNumTriangleVertices - mCurrentVertex));
  154. if (part_num_vertices == 0)
  155. break;
  156. max_vertices_requested -= part_num_vertices;
  157. total_num_vertices += part_num_vertices;
  158. if (mIsInsideOut)
  159. {
  160. // Store triangles flipped
  161. for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)
  162. {
  163. (part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
  164. (part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
  165. (part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
  166. }
  167. }
  168. else
  169. {
  170. // Store triangles
  171. for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)
  172. {
  173. (part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
  174. (part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
  175. (part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
  176. }
  177. }
  178. // Update the current vertex to point to the next vertex to get
  179. mCurrentVertex += part_num_vertices;
  180. // Check if we completed this part
  181. if (mCurrentVertex < part.mNumTriangleVertices)
  182. break;
  183. // Reset current vertex for the next part
  184. mCurrentVertex = 0;
  185. }
  186. int total_num_triangles = total_num_vertices / 3;
  187. // Store materials
  188. if (outMaterials != nullptr)
  189. for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)
  190. *m = mMaterial;
  191. return total_num_triangles;
  192. }
  193. private:
  194. struct Part
  195. {
  196. Mat44 mLocalToWorld;
  197. const Vec3 * mTriangleVertices;
  198. size_t mNumTriangleVertices;
  199. };
  200. StaticArray<Part, 3> mParts;
  201. uint mCurrentPart = 0;
  202. size_t mCurrentVertex = 0;
  203. const PhysicsMaterial * mMaterial;
  204. bool mIsInsideOut;
  205. };
  206. JPH_NAMESPACE_END