Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Renderer/DebugRenderer.h
9906 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#ifndef JPH_DEBUG_RENDERER
8
#error This file should only be included when JPH_DEBUG_RENDERER is defined
9
#endif // !JPH_DEBUG_RENDERER
10
11
#ifndef JPH_DEBUG_RENDERER_EXPORT
12
// By default export the debug renderer
13
#define JPH_DEBUG_RENDERER_EXPORT JPH_EXPORT
14
#endif // !JPH_DEBUG_RENDERER_EXPORT
15
16
#include <Jolt/Core/Color.h>
17
#include <Jolt/Core/Reference.h>
18
#include <Jolt/Core/HashCombine.h>
19
#include <Jolt/Core/UnorderedMap.h>
20
#include <Jolt/Core/NonCopyable.h>
21
#include <Jolt/Math/Float2.h>
22
#include <Jolt/Geometry/IndexedTriangle.h>
23
#include <Jolt/Geometry/AABox.h>
24
25
JPH_NAMESPACE_BEGIN
26
27
class OrientedBox;
28
29
/// Simple triangle renderer for debugging purposes.
30
///
31
/// Inherit from this class to provide your own implementation.
32
///
33
/// Implement the following virtual functions:
34
/// - DrawLine
35
/// - DrawTriangle
36
/// - DrawText3D
37
/// - CreateTriangleBatch
38
/// - DrawGeometry
39
///
40
/// Make sure you call Initialize() from the constructor of your implementation.
41
///
42
/// The CreateTriangleBatch is used to prepare a batch of triangles to be drawn by a single DrawGeometry call,
43
/// which means that Jolt can render a complex scene much more efficiently than when each triangle in that scene would have been drawn through DrawTriangle.
44
///
45
/// Note that an implementation that implements CreateTriangleBatch and DrawGeometry is provided by DebugRendererSimple which can be used to start quickly.
46
class JPH_DEBUG_RENDERER_EXPORT DebugRenderer : public NonCopyable
47
{
48
public:
49
JPH_OVERRIDE_NEW_DELETE
50
51
/// Constructor
52
DebugRenderer();
53
virtual ~DebugRenderer();
54
55
/// Call once after frame is complete. Releases unused dynamically generated geometry assets.
56
void NextFrame();
57
58
/// Draw line
59
virtual void DrawLine(RVec3Arg inFrom, RVec3Arg inTo, ColorArg inColor) = 0;
60
61
/// Draw wireframe box
62
void DrawWireBox(const AABox &inBox, ColorArg inColor);
63
void DrawWireBox(const OrientedBox &inBox, ColorArg inColor);
64
void DrawWireBox(RMat44Arg inMatrix, const AABox &inBox, ColorArg inColor);
65
66
/// Draw a marker on a position
67
void DrawMarker(RVec3Arg inPosition, ColorArg inColor, float inSize);
68
69
/// Draw an arrow
70
void DrawArrow(RVec3Arg inFrom, RVec3Arg inTo, ColorArg inColor, float inSize);
71
72
/// Draw coordinate system (3 arrows, x = red, y = green, z = blue)
73
void DrawCoordinateSystem(RMat44Arg inTransform, float inSize = 1.0f);
74
75
/// Draw a plane through inPoint with normal inNormal
76
void DrawPlane(RVec3Arg inPoint, Vec3Arg inNormal, ColorArg inColor, float inSize);
77
78
/// Draw wireframe triangle
79
void DrawWireTriangle(RVec3Arg inV1, RVec3Arg inV2, RVec3Arg inV3, ColorArg inColor);
80
81
/// Draw a wireframe polygon
82
template <class VERTEX_ARRAY>
83
void DrawWirePolygon(RMat44Arg 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); }
84
85
/// Draw wireframe sphere
86
void DrawWireSphere(RVec3Arg inCenter, float inRadius, ColorArg inColor, int inLevel = 3);
87
void DrawWireUnitSphere(RMat44Arg inMatrix, ColorArg inColor, int inLevel = 3);
88
89
/// Enum that determines if a shadow should be cast or not
90
enum class ECastShadow
91
{
92
On, ///< This shape should cast a shadow
93
Off ///< This shape should not cast a shadow
94
};
95
96
/// Determines how triangles are drawn
97
enum class EDrawMode
98
{
99
Solid, ///< Draw as a solid shape
100
Wireframe, ///< Draw as wireframe
101
};
102
103
/// Draw a single back face culled triangle
104
virtual void DrawTriangle(RVec3Arg inV1, RVec3Arg inV2, RVec3Arg inV3, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::Off) = 0;
105
106
/// Draw a box
107
void DrawBox(const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
108
void DrawBox(RMat44Arg inMatrix, const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
109
110
/// Draw a sphere
111
void DrawSphere(RVec3Arg inCenter, float inRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
112
void DrawUnitSphere(RMat44Arg inMatrix, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
113
114
/// Draw a capsule with one half sphere at (0, -inHalfHeightOfCylinder, 0) and the other half sphere at (0, inHalfHeightOfCylinder, 0) and radius inRadius.
115
/// The capsule will be transformed by inMatrix.
116
void DrawCapsule(RMat44Arg inMatrix, float inHalfHeightOfCylinder, float inRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
117
118
/// Draw a cylinder with top (0, inHalfHeight, 0) and bottom (0, -inHalfHeight, 0) and radius inRadius.
119
/// The cylinder will be transformed by inMatrix
120
void DrawCylinder(RMat44Arg inMatrix, float inHalfHeight, float inRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
121
122
/// Draw a bottomless cone.
123
/// @param inTop Top of cone, center of base is at inTop + inAxis.
124
/// @param inAxis Height and direction of cone
125
/// @param inPerpendicular Perpendicular vector to inAxis.
126
/// @param inHalfAngle Specifies the cone angle in radians (angle measured between inAxis and cone surface).
127
/// @param inLength The length of the cone.
128
/// @param inColor Color to use for drawing the cone.
129
/// @param inCastShadow determines if this geometry should cast a shadow or not.
130
/// @param inDrawMode determines if we draw the geometry solid or in wireframe.
131
void DrawOpenCone(RVec3Arg inTop, Vec3Arg inAxis, Vec3Arg inPerpendicular, float inHalfAngle, float inLength, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
132
133
/// Draws cone rotation limits as used by the SwingTwistConstraintPart.
134
/// @param inMatrix Matrix that transforms from constraint space to world space
135
/// @param inSwingYHalfAngle See SwingTwistConstraintPart
136
/// @param inSwingZHalfAngle See SwingTwistConstraintPart
137
/// @param inEdgeLength Size of the edge of the cone shape
138
/// @param inColor Color to use for drawing the cone.
139
/// @param inCastShadow determines if this geometry should cast a shadow or not.
140
/// @param inDrawMode determines if we draw the geometry solid or in wireframe.
141
void DrawSwingConeLimits(RMat44Arg inMatrix, float inSwingYHalfAngle, float inSwingZHalfAngle, float inEdgeLength, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
142
143
/// Draws rotation limits as used by the SwingTwistConstraintPart.
144
/// @param inMatrix Matrix that transforms from constraint space to world space
145
/// @param inMinSwingYAngle See SwingTwistConstraintPart
146
/// @param inMaxSwingYAngle See SwingTwistConstraintPart
147
/// @param inMinSwingZAngle See SwingTwistConstraintPart
148
/// @param inMaxSwingZAngle See SwingTwistConstraintPart
149
/// @param inEdgeLength Size of the edge of the cone shape
150
/// @param inColor Color to use for drawing the cone.
151
/// @param inCastShadow determines if this geometry should cast a shadow or not.
152
/// @param inDrawMode determines if we draw the geometry solid or in wireframe.
153
void DrawSwingPyramidLimits(RMat44Arg inMatrix, float inMinSwingYAngle, float inMaxSwingYAngle, float inMinSwingZAngle, float inMaxSwingZAngle, float inEdgeLength, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
154
155
/// Draw a pie (part of a circle).
156
/// @param inCenter The center of the circle.
157
/// @param inRadius Radius of the circle.
158
/// @param inNormal The plane normal in which the pie resides.
159
/// @param inAxis The axis that defines an angle of 0 radians.
160
/// @param inMinAngle The pie will be drawn between [inMinAngle, inMaxAngle] (in radians).
161
/// @param inMaxAngle The pie will be drawn between [inMinAngle, inMaxAngle] (in radians).
162
/// @param inColor Color to use for drawing the pie.
163
/// @param inCastShadow determines if this geometry should cast a shadow or not.
164
/// @param inDrawMode determines if we draw the geometry solid or in wireframe.
165
void DrawPie(RVec3Arg inCenter, float inRadius, Vec3Arg inNormal, Vec3Arg inAxis, float inMinAngle, float inMaxAngle, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
166
167
/// Draw a tapered cylinder
168
/// @param inMatrix Matrix that transforms the cylinder to world space.
169
/// @param inTop Top of cylinder (along Y axis)
170
/// @param inBottom Bottom of cylinder (along Y axis)
171
/// @param inTopRadius Radius at the top
172
/// @param inBottomRadius Radius at the bottom
173
/// @param inColor Color to use for drawing the pie.
174
/// @param inCastShadow determines if this geometry should cast a shadow or not.
175
/// @param inDrawMode determines if we draw the geometry solid or in wireframe.
176
void DrawTaperedCylinder(RMat44Arg inMatrix, float inTop, float inBottom, float inTopRadius, float inBottomRadius, ColorArg inColor, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid);
177
178
/// Singleton instance
179
static DebugRenderer * sInstance;
180
181
/// Vertex format used by the triangle renderer
182
class Vertex
183
{
184
public:
185
Float3 mPosition;
186
Float3 mNormal;
187
Float2 mUV;
188
Color mColor;
189
};
190
191
/// A single triangle
192
class JPH_DEBUG_RENDERER_EXPORT Triangle
193
{
194
public:
195
Triangle() = default;
196
Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor);
197
Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor, Vec3Arg inUVOrigin, Vec3Arg inUVDirection);
198
199
Vertex mV[3];
200
};
201
202
/// Handle for a batch of triangles
203
using Batch = Ref<RefTargetVirtual>;
204
205
/// A single level of detail
206
class LOD
207
{
208
public:
209
Batch mTriangleBatch;
210
float mDistance;
211
};
212
213
/// A geometry primitive containing triangle batches for various lods
214
class Geometry : public RefTarget<Geometry>
215
{
216
public:
217
JPH_OVERRIDE_NEW_DELETE
218
219
/// Constructor
220
Geometry(const AABox &inBounds) : mBounds(inBounds) { }
221
Geometry(const Batch &inBatch, const AABox &inBounds) : mBounds(inBounds) { mLODs.push_back({ inBatch, cLargeFloat }); }
222
223
/// Determine which LOD to render
224
/// @param inCameraPosition Current position of the camera
225
/// @param inWorldSpaceBounds World space bounds for this geometry (transform mBounds by model space matrix)
226
/// @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).
227
/// @return The selected LOD.
228
const LOD & GetLOD(Vec3Arg inCameraPosition, const AABox &inWorldSpaceBounds, float inLODScaleSq) const
229
{
230
float dist_sq = inWorldSpaceBounds.GetSqDistanceTo(inCameraPosition);
231
for (const LOD &lod : mLODs)
232
if (dist_sq <= inLODScaleSq * Square(lod.mDistance))
233
return lod;
234
235
return mLODs.back();
236
}
237
238
/// All level of details for this mesh
239
Array<LOD> mLODs;
240
241
/// Bounding box that encapsulates all LODs
242
AABox mBounds;
243
};
244
245
/// Handle for a lodded triangle batch
246
using GeometryRef = Ref<Geometry>;
247
248
/// Calculate bounding box for a batch of triangles
249
static AABox sCalculateBounds(const Vertex *inVertices, int inVertexCount);
250
251
/// Create a batch of triangles that can be drawn efficiently
252
virtual Batch CreateTriangleBatch(const Triangle *inTriangles, int inTriangleCount) = 0;
253
virtual Batch CreateTriangleBatch(const Vertex *inVertices, int inVertexCount, const uint32 *inIndices, int inIndexCount) = 0;
254
Batch CreateTriangleBatch(const Array<Triangle> &inTriangles) { return CreateTriangleBatch(inTriangles.empty()? nullptr : &inTriangles[0], int(inTriangles.size())); }
255
Batch CreateTriangleBatch(const Array<Vertex> &inVertices, const Array<uint32> &inIndices) { return CreateTriangleBatch(inVertices.empty()? nullptr : &inVertices[0], int(inVertices.size()), inIndices.empty()? nullptr : &inIndices[0], int(inIndices.size())); }
256
Batch CreateTriangleBatch(const VertexList &inVertices, const IndexedTriangleNoMaterialList &inTriangles);
257
258
/// Create a primitive for a convex shape using its support function
259
using SupportFunction = function<Vec3 (Vec3Arg inDirection)>;
260
Batch CreateTriangleBatchForConvex(SupportFunction inGetSupport, int inLevel, AABox *outBounds = nullptr);
261
GeometryRef CreateTriangleGeometryForConvex(SupportFunction inGetSupport);
262
263
/// Determines which polygons are culled
264
enum class ECullMode
265
{
266
CullBackFace, ///< Don't draw backfacing polygons
267
CullFrontFace, ///< Don't draw front facing polygons
268
Off ///< Don't do culling and draw both sides
269
};
270
271
/// Draw some geometry
272
/// @param inModelMatrix is the matrix that transforms the geometry to world space.
273
/// @param inWorldSpaceBounds is the bounding box of the geometry after transforming it into world space.
274
/// @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).
275
/// @param inModelColor is the color with which to multiply the vertex colors in inGeometry.
276
/// @param inGeometry The geometry to draw.
277
/// @param inCullMode determines which polygons are culled.
278
/// @param inCastShadow determines if this geometry should cast a shadow or not.
279
/// @param inDrawMode determines if we draw the geometry solid or in wireframe.
280
virtual void DrawGeometry(RMat44Arg inModelMatrix, const AABox &inWorldSpaceBounds, float inLODScaleSq, ColorArg inModelColor, const GeometryRef &inGeometry, ECullMode inCullMode = ECullMode::CullBackFace, ECastShadow inCastShadow = ECastShadow::On, EDrawMode inDrawMode = EDrawMode::Solid) = 0;
281
void DrawGeometry(RMat44Arg 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); }
282
283
/// Draw text
284
virtual void DrawText3D(RVec3Arg inPosition, const string_view &inString, ColorArg inColor = Color::sWhite, float inHeight = 0.5f) = 0;
285
286
protected:
287
/// Initialize the system, must be called from the constructor of the DebugRenderer implementation
288
void Initialize();
289
290
private:
291
/// Recursive helper function for DrawWireUnitSphere
292
void DrawWireUnitSphereRecursive(RMat44Arg inMatrix, ColorArg inColor, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, int inLevel);
293
294
/// Helper functions to create a box
295
void CreateQuad(Array<uint32> &ioIndices, Array<Vertex> &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, Vec3Arg inV4);
296
297
/// Helper functions to create a vertex and index buffer for a sphere
298
void Create8thSphereRecursive(Array<uint32> &ioIndices, Array<Vertex> &ioVertices, Vec3Arg inDir1, uint32 &ioIdx1, Vec3Arg inDir2, uint32 &ioIdx2, Vec3Arg inDir3, uint32 &ioIdx3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel);
299
void Create8thSphere(Array<uint32> &ioIndices, Array<Vertex> &ioVertices, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel);
300
301
/// Helper functions to create a vertex and index buffer for a cylinder
302
Batch CreateCylinder(float inTop, float inBottom, float inTopRadius, float inBottomRadius, int inLevel);
303
304
/// Helper function for DrawSwingConeLimits and DrawSwingPyramidLimits
305
Geometry * CreateSwingLimitGeometry(int inNumSegments, const Vec3 *inVertices);
306
307
// Predefined shapes
308
GeometryRef mBox;
309
GeometryRef mSphere;
310
GeometryRef mCapsuleTop;
311
GeometryRef mCapsuleMid;
312
GeometryRef mCapsuleBottom;
313
GeometryRef mOpenCone;
314
GeometryRef mCylinder;
315
316
struct SwingConeLimits
317
{
318
bool operator == (const SwingConeLimits &inRHS) const
319
{
320
return mSwingYHalfAngle == inRHS.mSwingYHalfAngle
321
&& mSwingZHalfAngle == inRHS.mSwingZHalfAngle;
322
}
323
324
float mSwingYHalfAngle;
325
float mSwingZHalfAngle;
326
};
327
328
JPH_MAKE_HASH_STRUCT(SwingConeLimits, SwingConeLimitsHasher, t.mSwingYHalfAngle, t.mSwingZHalfAngle)
329
330
using SwingConeBatches = UnorderedMap<SwingConeLimits, GeometryRef, SwingConeLimitsHasher>;
331
SwingConeBatches mSwingConeLimits;
332
SwingConeBatches mPrevSwingConeLimits;
333
334
struct SwingPyramidLimits
335
{
336
bool operator == (const SwingPyramidLimits &inRHS) const
337
{
338
return mMinSwingYAngle == inRHS.mMinSwingYAngle
339
&& mMaxSwingYAngle == inRHS.mMaxSwingYAngle
340
&& mMinSwingZAngle == inRHS.mMinSwingZAngle
341
&& mMaxSwingZAngle == inRHS.mMaxSwingZAngle;
342
}
343
344
float mMinSwingYAngle;
345
float mMaxSwingYAngle;
346
float mMinSwingZAngle;
347
float mMaxSwingZAngle;
348
};
349
350
JPH_MAKE_HASH_STRUCT(SwingPyramidLimits, SwingPyramidLimitsHasher, t.mMinSwingYAngle, t.mMaxSwingYAngle, t.mMinSwingZAngle, t.mMaxSwingZAngle)
351
352
using SwingPyramidBatches = UnorderedMap<SwingPyramidLimits, GeometryRef, SwingPyramidLimitsHasher>;
353
SwingPyramidBatches mSwingPyramidLimits;
354
SwingPyramidBatches mPrevSwingPyramidLimits;
355
356
using PieBatces = UnorderedMap<float, GeometryRef>;
357
PieBatces mPieLimits;
358
PieBatces mPrevPieLimits;
359
360
struct TaperedCylinder
361
{
362
bool operator == (const TaperedCylinder &inRHS) const
363
{
364
return mTop == inRHS.mTop
365
&& mBottom == inRHS.mBottom
366
&& mTopRadius == inRHS.mTopRadius
367
&& mBottomRadius == inRHS.mBottomRadius;
368
}
369
370
float mTop;
371
float mBottom;
372
float mTopRadius;
373
float mBottomRadius;
374
};
375
376
JPH_MAKE_HASH_STRUCT(TaperedCylinder, TaperedCylinderHasher, t.mTop, t.mBottom, t.mTopRadius, t.mBottomRadius)
377
378
using TaperedCylinderBatces = UnorderedMap<TaperedCylinder, GeometryRef, TaperedCylinderHasher>;
379
TaperedCylinderBatces mTaperedCylinders;
380
TaperedCylinderBatces mPrevTaperedCylinders;
381
};
382
383
JPH_NAMESPACE_END
384
385