GetTrianglesContext.h 8.7 KB

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