DebugRenderer.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #ifndef JPH_DEBUG_RENDERER
  5. #error This file should only be included when JPH_DEBUG_RENDERER is defined
  6. #endif // !JPH_DEBUG_RENDERER
  7. #include <Core/Color.h>
  8. #include <Core/Reference.h>
  9. #include <Core/HashCombine.h>
  10. #include <Math/Float2.h>
  11. #include <Geometry/IndexedTriangle.h>
  12. #include <Geometry/AABox.h>
  13. #include <unordered_map>
  14. namespace JPH {
  15. class OrientedBox;
  16. /// Simple triangle renderer for debugging purposes.
  17. class DebugRenderer
  18. {
  19. public:
  20. /// Constructor
  21. DebugRenderer();
  22. virtual ~DebugRenderer();
  23. /// Draw line
  24. void DrawLine(Vec3Arg inFrom, Vec3Arg inTo, ColorArg inColor) { Float3 from, to; inFrom.StoreFloat3(&from); inTo.StoreFloat3(&to); DrawLine(from, to, inColor); }
  25. virtual void DrawLine(const Float3 &inFrom, const Float3 &inTo, ColorArg inColor) = 0;
  26. /// Draw wireframe box
  27. void DrawWireBox(const AABox &inBox, ColorArg inColor);
  28. void DrawWireBox(const OrientedBox &inBox, ColorArg inColor);
  29. void DrawWireBox(Mat44Arg inMatrix, const AABox &inBox, ColorArg inColor);
  30. /// Draw a marker on a position
  31. void DrawMarker(Vec3Arg inPosition, ColorArg inColor, float inSize);
  32. /// Draw an arrow
  33. void DrawArrow(Vec3Arg inFrom, Vec3Arg inTo, ColorArg inColor, float inSize);
  34. /// Draw coordinate system (3 arrows, x = red, y = green, z = blue)
  35. void DrawCoordinateSystem(Mat44Arg inTransform, float inSize = 1.0f);
  36. /// Draw wireframe triangle
  37. void DrawWireTriangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor);
  38. /// Draw a wireframe polygon
  39. template <class VERTEX_ARRAY>
  40. void DrawWirePolygon(const VERTEX_ARRAY &inVertices, ColorArg inColor, float inArrowSize = 0.0f) { for (typename VERTEX_ARRAY::size_type i = 0; i < inVertices.size(); ++i) DrawArrow(inVertices[i], inVertices[(i + 1) % inVertices.size()], inColor, inArrowSize); }
  41. template <class VERTEX_ARRAY>
  42. void DrawWirePolygon(Mat44Arg inTransform, const VERTEX_ARRAY &inVertices, ColorArg inColor, float inArrowSize = 0.0f) { for (typename VERTEX_ARRAY::size_type i = 0; i < inVertices.size(); ++i) DrawArrow(inTransform * inVertices[i], inTransform * inVertices[(i + 1) % inVertices.size()], inColor, inArrowSize); }
  43. /// Draw wireframe sphere
  44. void DrawWireSphere(Vec3Arg inCenter, float inRadius, ColorArg inColor, int inLevel = 3);
  45. void DrawWireUnitSphere(Mat44Arg inMatrix, ColorArg inColor, int inLevel = 3);
  46. /// Enum that determines if a shadow should be cast or not
  47. enum class ECastShadow
  48. {
  49. On, // This shape should cast a shadow
  50. Off // This shape should not cast a shadow
  51. };
  52. /// Determines how triangles are drawn
  53. enum class EDrawMode
  54. {
  55. Solid, ///< Draw as a solid shape
  56. Wireframe, ///< Draw as wireframe
  57. };
  58. /// Draw a single back face culled triangle without any shadows
  59. virtual void DrawTriangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor) = 0;
  60. /// Draw a box
  61. void DrawBox(const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  62. void DrawBox(Mat44Arg inMatrix, const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  63. /// Draw a sphere
  64. void DrawSphere(Vec3Arg inCenter, float inRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  65. void DrawUnitSphere(Mat44Arg inMatrix, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  66. /// Draw a capsule with one half sphere at (0, -inHalfHeightOfCylinder, 0) and the other half sphere at (0, inHalfHeightOfCylinder, 0) and radius inRadius.
  67. /// The capsule will be transformed by inMatrix.
  68. void DrawCapsule(Mat44Arg inMatrix, float inHalfHeightOfCylinder, float inRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  69. /// Draw a cylinder with top (0, inHalfHeight, 0) and bottom (0, -inHalfHeight, 0) and radius inRadius.
  70. /// The cylinder will be transformed by inMatrix
  71. void DrawCylinder(Mat44Arg inMatrix, float inHalfHeight, float inRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  72. /// Draw a bottomless cone.
  73. /// @param inTop Top of cone, center of base is at inTop + inAxis.
  74. /// @param inAxis Height and direction of cone
  75. /// @param inPerpendicular Perpendicular vector to inAxis.
  76. /// @param inHalfAngle Specifies the cone angle in radians (angle measured between inAxis and cone surface).
  77. /// @param inLength The length of the cone.
  78. /// @param inColor Color to use for drawing the cone.
  79. /// @param inCastShadow determins if this geometry should cast a shadow or not.
  80. /// @param inDrawMode determines if we draw the geometry solid or in wireframe.
  81. void DrawOpenCone(Vec3Arg inTop, Vec3Arg inAxis, Vec3Arg inPerpendicular, float inHalfAngle, float inLength, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  82. /// Draws rotation limits as used by the SwingTwistConstraintPart.
  83. /// @param inMatrix Matrix that transforms from constraint space to world space
  84. /// @param inSwingYHalfAngle See SwingTwistConstraintPart
  85. /// @param inSwingZHalfAngle See SwingTwistConstraintPart
  86. /// @param inEdgeLength Size of the edge of the cone shape
  87. /// @param inColor Color to use for drawing the cone.
  88. /// @param inCastShadow determins if this geometry should cast a shadow or not.
  89. /// @param inDrawMode determines if we draw the geometry solid or in wireframe.
  90. void DrawSwingLimits(Mat44Arg inMatrix, float inSwingYHalfAngle, float inSwingZHalfAngle, float inEdgeLength, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  91. /// Draw a pie (part of a circle).
  92. /// @param inCenter The center of the circle.
  93. /// @param inRadius Radius of the circle.
  94. /// @param inNormal The plane normal in which the pie resides.
  95. /// @param inAxis The axis that defines an angle of 0 radians.
  96. /// @param inMinAngle The pie will be drawn between [inMinAngle, inMaxAngle] (in radians).
  97. /// @param inMaxAngle The pie will be drawn between [inMinAngle, inMaxAngle] (in radians).
  98. /// @param inColor Color to use for drawing the pie.
  99. /// @param inCastShadow determins if this geometry should cast a shadow or not.
  100. /// @param inDrawMode determines if we draw the geometry solid or in wireframe.
  101. void DrawPie(Vec3Arg inCenter, float inRadius, Vec3Arg inNormal, Vec3Arg inAxis, float inMinAngle, float inMaxAngle, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
  102. /// Singleton instance
  103. static DebugRenderer * sInstance;
  104. /// Vertex format used by the triangle renderer
  105. class Vertex
  106. {
  107. public:
  108. Float3 mPosition;
  109. Float3 mNormal;
  110. Float2 mUV;
  111. Color mColor;
  112. };
  113. /// A single triangle
  114. class Triangle
  115. {
  116. public:
  117. Triangle() = default;
  118. Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor);
  119. Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor, Vec3Arg inUVOrigin, Vec3Arg inUVDirection);
  120. Vertex mV[3];
  121. };
  122. /// Handle for a batch of triangles
  123. using Batch = Ref<RefTargetVirtual>;
  124. /// A single level of detail
  125. class LOD
  126. {
  127. public:
  128. Batch mTriangleBatch;
  129. float mDistance;
  130. };
  131. /// A geometry primitive containing triangle batches for various lods
  132. class Geometry : public RefTarget<Geometry>
  133. {
  134. public:
  135. /// Constructor
  136. Geometry(const AABox &inBounds) : mBounds(inBounds) { }
  137. Geometry(const Batch &inBatch, const AABox &inBounds) : mBounds(inBounds) { mLODs.push_back({ inBatch, FLT_MAX }); }
  138. /// All level of details for this mesh
  139. vector<LOD> mLODs;
  140. /// Bounding box that encapsulates all LODs
  141. AABox mBounds;
  142. };
  143. /// Handle for a lodded triangle batch
  144. using GeometryRef = Ref<Geometry>;
  145. /// Calculate bounding box for a batch of triangles
  146. static AABox sCalculateBounds(const Vertex *inVertices, int inVertexCount);
  147. /// Create a batch of triangles that can be drawn efficiently
  148. virtual Batch CreateTriangleBatch(const Triangle *inTriangles, int inTriangleCount) = 0;
  149. virtual Batch CreateTriangleBatch(const Vertex *inVertices, int inVertexCount, const uint32 *inIndices, int inIndexCount) = 0;
  150. Batch CreateTriangleBatch(const vector<Triangle> &inTriangles) { return CreateTriangleBatch(inTriangles.empty()? nullptr : &inTriangles[0], (int)inTriangles.size()); }
  151. Batch CreateTriangleBatch(const vector<Vertex> &inVertices, const vector<uint32> &inIndices) { return CreateTriangleBatch(inVertices.empty()? nullptr : &inVertices[0], (int)inVertices.size(), inIndices.empty()? nullptr : &inIndices[0], (int)inIndices.size()); }
  152. Batch CreateTriangleBatch(const VertexList &inVertices, const IndexedTriangleNoMaterialList &inTriangles);
  153. /// Create a primitive for a convex shape using its support function
  154. using SupportFunction = function<Vec3 (Vec3Arg inDirection)>;
  155. Batch CreateTriangleBatchForConvex(SupportFunction inGetSupport, int inLevel, AABox *outBounds = nullptr);
  156. GeometryRef CreateTriangleGeometryForConvex(SupportFunction inGetSupport);
  157. /// Determines which polygons are culled
  158. enum class ECullMode
  159. {
  160. CullBackFace, ///< Don't draw backfacing polygons
  161. CullFrontFace, ///< Don't draw front facing polygons
  162. Off ///< Don't do culling and draw both sides
  163. };
  164. /// Draw some geometry
  165. /// @param inModelMatrix is the matrix that transforms the geometry to world space.
  166. /// @param inWorldSpaceBounds is the bounding box of the geometry after transforming it into world space.
  167. /// @param inLODScaleSq is the squared scale of the model matrix, it is multiplied with the LOD distances in inGeometry to calculate the real LOD distance (so a number > 1 will force a higher LOD).
  168. /// @param inModelColor is the color with which to multiply the vertex colors in inGeometry.
  169. /// @param inGeometry The geometry to draw.
  170. /// @param inCullMode determines which polygons are culled.
  171. /// @param inCastShadow determines if this geometry should cast a shadow or not.
  172. /// @param inDrawMode determines if we draw the geometry solid or in wireframe.
  173. virtual void DrawGeometry(Mat44Arg inModelMatrix, const AABox &inWorldSpaceBounds, float inLODScaleSq, ColorArg inModelColor, const GeometryRef &inGeometry, ECullMode inCullMode = ECullMode::CullBackFace, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid) = 0;
  174. void DrawGeometry(Mat44Arg inModelMatrix, ColorArg inModelColor, const GeometryRef &inGeometry, ECullMode inCullMode = ECullMode::CullBackFace, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid) { DrawGeometry(inModelMatrix, inGeometry->mBounds.Transformed(inModelMatrix), max(max(inModelMatrix.GetAxisX().LengthSq(), inModelMatrix.GetAxisY().LengthSq()), inModelMatrix.GetAxisZ().LengthSq()), inModelColor, inGeometry, inCullMode, inCastShadow, inDrawMode); }
  175. /// Draw text
  176. virtual void DrawText3D(Vec3Arg inPosition, const string &inString, ColorArg inColor = Color::sWhite, float inHeight = 0.5f) = 0;
  177. protected:
  178. /// Initialize the system, must be called from the constructor of the DebugRenderer implementation
  179. void Initialize();
  180. private:
  181. /// Recursive helper function for DrawWireUnitSphere
  182. void DrawWireUnitSphereRecursive(Mat44Arg inMatrix, ColorArg inColor, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, int inLevel);
  183. /// Helper functions to create a box
  184. void CreateQuad(vector<uint32> &ioIndices, vector<Vertex> &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, Vec3Arg inV4);
  185. /// Helper functions to create a vertex and index buffer for a sphere
  186. void Create8thSphereRecursive(vector<uint32> &ioIndices, vector<Vertex> &ioVertices, Vec3Arg inDir1, uint32 &ioIdx1, Vec3Arg inDir2, uint32 &ioIdx2, Vec3Arg inDir3, uint32 &ioIdx3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel);
  187. void Create8thSphere(vector<uint32> &ioIndices, vector<Vertex> &ioVertices, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel);
  188. // Predefined shapes
  189. GeometryRef mBox;
  190. GeometryRef mSphere;
  191. GeometryRef mCapsuleTop;
  192. GeometryRef mCapsuleMid;
  193. GeometryRef mCapsuleBottom;
  194. GeometryRef mOpenCone;
  195. GeometryRef mCylinder;
  196. struct SwingLimits
  197. {
  198. bool operator == (const SwingLimits &inRHS) const { return mSwingYHalfAngle == inRHS.mSwingYHalfAngle && mSwingZHalfAngle == inRHS.mSwingZHalfAngle; }
  199. float mSwingYHalfAngle;
  200. float mSwingZHalfAngle;
  201. };
  202. JPH_MAKE_HASH_STRUCT(SwingLimits, SwingLimitsHasher, t.mSwingYHalfAngle, t.mSwingZHalfAngle)
  203. using SwingBatches = unordered_map<SwingLimits, GeometryRef, SwingLimitsHasher>;
  204. SwingBatches mSwingLimits;
  205. using PieBatces = unordered_map<float, GeometryRef>;
  206. PieBatces mPieLimits;
  207. };
  208. } // JPH