DebugRendererImp.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Renderer/DebugRendererImp.h>
  6. #include <Renderer/Renderer.h>
  7. #include <Renderer/Font.h>
  8. #ifndef JPH_DEBUG_RENDERER
  9. // Hack to still compile DebugRenderer inside the test framework when Jolt is compiled without
  10. #define JPH_DEBUG_RENDERER
  11. #include <Jolt/Renderer/DebugRenderer.cpp>
  12. #undef JPH_DEBUG_RENDERER
  13. #endif // !JPH_DEBUG_RENDERER
  14. DebugRendererImp::DebugRendererImp(Renderer *inRenderer, const Font *inFont) :
  15. mRenderer(inRenderer),
  16. mFont(inFont)
  17. {
  18. // Create input layout for lines
  19. const PipelineState::EInputDescription line_vertex_desc[] =
  20. {
  21. PipelineState::EInputDescription::Position,
  22. PipelineState::EInputDescription::Color
  23. };
  24. // Lines
  25. Ref<VertexShader> vtx_line = mRenderer->CreateVertexShader("LineVertexShader");
  26. Ref<PixelShader> pix_line = mRenderer->CreatePixelShader("LinePixelShader");
  27. mLineState = mRenderer->CreatePipelineState(vtx_line, line_vertex_desc, std::size(line_vertex_desc), pix_line, PipelineState::EDrawPass::Normal, PipelineState::EFillMode::Solid, PipelineState::ETopology::Line, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  28. // Create input layout for triangles
  29. const PipelineState::EInputDescription triangles_vertex_desc[] =
  30. {
  31. PipelineState::EInputDescription::Position,
  32. PipelineState::EInputDescription::Normal,
  33. PipelineState::EInputDescription::TexCoord,
  34. PipelineState::EInputDescription::Color,
  35. PipelineState::EInputDescription::InstanceTransform,
  36. PipelineState::EInputDescription::InstanceInvTransform,
  37. PipelineState::EInputDescription::InstanceColor
  38. };
  39. // Triangles
  40. Ref<VertexShader> vtx_triangle = mRenderer->CreateVertexShader("TriangleVertexShader");
  41. Ref<PixelShader> pix_triangle = mRenderer->CreatePixelShader("TrianglePixelShader");
  42. mTriangleStateBF = mRenderer->CreatePipelineState(vtx_triangle, triangles_vertex_desc, std::size(triangles_vertex_desc), pix_triangle, PipelineState::EDrawPass::Normal, PipelineState::EFillMode::Solid, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  43. mTriangleStateFF = mRenderer->CreatePipelineState(vtx_triangle, triangles_vertex_desc, std::size(triangles_vertex_desc), pix_triangle, PipelineState::EDrawPass::Normal, PipelineState::EFillMode::Solid, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::FrontFace);
  44. mTriangleStateWire = mRenderer->CreatePipelineState(vtx_triangle, triangles_vertex_desc, std::size(triangles_vertex_desc), pix_triangle, PipelineState::EDrawPass::Normal, PipelineState::EFillMode::Wireframe, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  45. // Shadow pass
  46. Ref<VertexShader> vtx_shadow = mRenderer->CreateVertexShader("TriangleDepthVertexShader");
  47. Ref<PixelShader> pix_shadow = mRenderer->CreatePixelShader("TriangleDepthPixelShader");
  48. mShadowStateBF = mRenderer->CreatePipelineState(vtx_shadow, triangles_vertex_desc, std::size(triangles_vertex_desc), pix_shadow, PipelineState::EDrawPass::Shadow, PipelineState::EFillMode::Solid, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  49. mShadowStateFF = mRenderer->CreatePipelineState(vtx_shadow, triangles_vertex_desc, std::size(triangles_vertex_desc), pix_shadow, PipelineState::EDrawPass::Shadow, PipelineState::EFillMode::Solid, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::FrontFace);
  50. mShadowStateWire = mRenderer->CreatePipelineState(vtx_shadow, triangles_vertex_desc, std::size(triangles_vertex_desc), pix_shadow, PipelineState::EDrawPass::Shadow, PipelineState::EFillMode::Wireframe, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  51. // Create instances buffer
  52. for (uint n = 0; n < Renderer::cFrameCount; ++n)
  53. mInstancesBuffer[n] = mRenderer->CreateRenderInstances();
  54. // Create empty batch
  55. Vertex empty_vertex { Float3(0, 0, 0), Float3(1, 0, 0), Float2(0, 0), Color::sWhite };
  56. uint32 empty_indices[] = { 0, 0, 0 };
  57. mEmptyBatch = CreateTriangleBatch(&empty_vertex, 1, empty_indices, 3);
  58. // Initialize base class
  59. DebugRenderer::Initialize();
  60. }
  61. void DebugRendererImp::DrawLine(RVec3Arg inFrom, RVec3Arg inTo, ColorArg inColor)
  62. {
  63. RVec3 offset = mRenderer->GetBaseOffset();
  64. Line line;
  65. Vec3(inFrom - offset).StoreFloat3(&line.mFrom);
  66. line.mFromColor = inColor;
  67. Vec3(inTo - offset).StoreFloat3(&line.mTo);
  68. line.mToColor = inColor;
  69. lock_guard lock(mLinesLock);
  70. mLines.push_back(line);
  71. }
  72. DebugRenderer::Batch DebugRendererImp::CreateTriangleBatch(const Triangle *inTriangles, int inTriangleCount)
  73. {
  74. if (inTriangles == nullptr || inTriangleCount == 0)
  75. return mEmptyBatch;
  76. RenderPrimitive *primitive = mRenderer->CreateRenderPrimitive(PipelineState::ETopology::Triangle);
  77. primitive->CreateVertexBuffer(3 * inTriangleCount, sizeof(Vertex), inTriangles);
  78. return primitive;
  79. }
  80. DebugRenderer::Batch DebugRendererImp::CreateTriangleBatch(const Vertex *inVertices, int inVertexCount, const uint32 *inIndices, int inIndexCount)
  81. {
  82. if (inVertices == nullptr || inVertexCount == 0 || inIndices == nullptr || inIndexCount == 0)
  83. return mEmptyBatch;
  84. RenderPrimitive *primitive = mRenderer->CreateRenderPrimitive(PipelineState::ETopology::Triangle);
  85. primitive->CreateVertexBuffer(inVertexCount, sizeof(Vertex), inVertices);
  86. primitive->CreateIndexBuffer(inIndexCount, inIndices);
  87. return primitive;
  88. }
  89. void DebugRendererImp::DrawGeometry(RMat44Arg inModelMatrix, const AABox &inWorldSpaceBounds, float inLODScaleSq, ColorArg inModelColor, const GeometryRef &inGeometry, ECullMode inCullMode, ECastShadow inCastShadow, EDrawMode inDrawMode)
  90. {
  91. lock_guard lock(mPrimitivesLock);
  92. RVec3 offset = mRenderer->GetBaseOffset();
  93. Mat44 model_matrix = inModelMatrix.PostTranslated(-offset).ToMat44();
  94. AABox world_space_bounds = inWorldSpaceBounds;
  95. world_space_bounds.Translate(Vec3(-offset));
  96. // Our pixel shader uses alpha only to turn on/off shadows
  97. Color color = inCastShadow == ECastShadow::On? Color(inModelColor, 255) : Color(inModelColor, 0);
  98. if (inDrawMode == EDrawMode::Wireframe)
  99. {
  100. mWireframePrimitives[inGeometry].mInstances.push_back({ model_matrix, model_matrix.GetDirectionPreservingMatrix(), color, world_space_bounds, inLODScaleSq });
  101. ++mNumInstances;
  102. }
  103. else
  104. {
  105. if (inCullMode != ECullMode::CullFrontFace)
  106. {
  107. mPrimitives[inGeometry].mInstances.push_back({ model_matrix, model_matrix.GetDirectionPreservingMatrix(), color, world_space_bounds, inLODScaleSq });
  108. ++mNumInstances;
  109. }
  110. if (inCullMode != ECullMode::CullBackFace)
  111. {
  112. mPrimitivesBackFacing[inGeometry].mInstances.push_back({ model_matrix, model_matrix.GetDirectionPreservingMatrix(), color, world_space_bounds, inLODScaleSq });
  113. ++mNumInstances;
  114. }
  115. }
  116. }
  117. void DebugRendererImp::FinalizePrimitive()
  118. {
  119. JPH_PROFILE_FUNCTION();
  120. if (mLockedPrimitive != nullptr)
  121. {
  122. // Unlock the primitive
  123. mLockedPrimitive->UnlockVertexBuffer();
  124. // Set number of indices to draw
  125. mLockedPrimitive->SetNumVtxToDraw(int(mLockedVertices - mLockedVerticesStart));
  126. // Add to draw list
  127. mTempPrimitives[new Geometry(mLockedPrimitive.GetPtr(), mLockedPrimitiveBounds)].mInstances.push_back({ Mat44::sIdentity(), Mat44::sIdentity(), Color::sWhite, mLockedPrimitiveBounds, 1.0f });
  128. ++mNumInstances;
  129. // Clear pointers
  130. mLockedPrimitive = nullptr;
  131. mLockedVerticesStart = nullptr;
  132. mLockedVertices = nullptr;
  133. mLockedVerticesEnd = nullptr;
  134. mLockedPrimitiveBounds = AABox();
  135. }
  136. }
  137. void DebugRendererImp::EnsurePrimitiveSpace(int inVtxSize)
  138. {
  139. const int cVertexBufferSize = 10240;
  140. if (mLockedPrimitive == nullptr
  141. || mLockedVerticesEnd - mLockedVertices < inVtxSize)
  142. {
  143. FinalizePrimitive();
  144. // Create new
  145. mLockedPrimitive = mRenderer->CreateRenderPrimitive(PipelineState::ETopology::Triangle);
  146. mLockedPrimitive->CreateVertexBuffer(cVertexBufferSize, sizeof(Vertex));
  147. // Lock buffers
  148. mLockedVerticesStart = mLockedVertices = (Vertex *)mLockedPrimitive->LockVertexBuffer();
  149. mLockedVerticesEnd = mLockedVertices + cVertexBufferSize;
  150. }
  151. }
  152. void DebugRendererImp::DrawTriangle(RVec3Arg inV1, RVec3Arg inV2, RVec3Arg inV3, ColorArg inColor, ECastShadow inCastShadow)
  153. {
  154. RVec3 offset = mRenderer->GetBaseOffset();
  155. Vec3 v1(inV1 - offset);
  156. Vec3 v2(inV2 - offset);
  157. Vec3 v3(inV3 - offset);
  158. lock_guard lock(mPrimitivesLock);
  159. EnsurePrimitiveSpace(3);
  160. // Set alpha to zero if we don't want to cast shadows to notify the pixel shader
  161. Color color(inColor, inCastShadow == ECastShadow::Off? 0 : 0xff);
  162. // Construct triangle in separate buffer and then copy it to the target memory block (may be uncached memory)
  163. Triangle triangle(v1, v2, v3, color);
  164. *(Triangle *)mLockedVertices = triangle;
  165. mLockedVertices += 3;
  166. // Update bounding box
  167. mLockedPrimitiveBounds.Encapsulate(v1);
  168. mLockedPrimitiveBounds.Encapsulate(v2);
  169. mLockedPrimitiveBounds.Encapsulate(v3);
  170. }
  171. void DebugRendererImp::DrawInstances(const Geometry *inGeometry, const Array<int> &inStartIdx)
  172. {
  173. RenderInstances *instances_buffer = mInstancesBuffer[mRenderer->GetCurrentFrameIndex()];
  174. if (!inStartIdx.empty())
  175. {
  176. // Get LODs
  177. const Array<LOD> &geometry_lods = inGeometry->mLODs;
  178. // Write instances for all LODS
  179. int next_start_idx = inStartIdx.front();
  180. for (size_t lod = 0; lod < geometry_lods.size(); ++lod)
  181. {
  182. int start_idx = next_start_idx;
  183. next_start_idx = inStartIdx[lod + 1];
  184. int num_instances = next_start_idx - start_idx;
  185. instances_buffer->Draw(static_cast<RenderPrimitive *>(geometry_lods[lod].mTriangleBatch.GetPtr()), start_idx, num_instances);
  186. }
  187. }
  188. }
  189. void DebugRendererImp::DrawText3D(RVec3Arg inPosition, const string_view &inString, ColorArg inColor, float inHeight)
  190. {
  191. RVec3 offset = mRenderer->GetBaseOffset();
  192. Vec3 pos(inPosition - offset);
  193. lock_guard lock(mTextsLock);
  194. mTexts.emplace_back(pos, inString, inColor, inHeight);
  195. }
  196. void DebugRendererImp::DrawLines()
  197. {
  198. JPH_PROFILE_FUNCTION();
  199. lock_guard lock(mLinesLock);
  200. // Draw the lines
  201. if (!mLines.empty())
  202. {
  203. Ref<RenderPrimitive> primitive = mRenderer->CreateRenderPrimitive(PipelineState::ETopology::Line);
  204. primitive->CreateVertexBuffer((int)mLines.size() * 2, sizeof(Line) / 2);
  205. void *data = primitive->LockVertexBuffer();
  206. memcpy(data, &mLines[0], mLines.size() * sizeof(Line));
  207. primitive->UnlockVertexBuffer();
  208. mLineState->Activate();
  209. primitive->Draw();
  210. }
  211. }
  212. void DebugRendererImp::DrawShadowPass()
  213. {
  214. JPH_PROFILE_FUNCTION();
  215. lock_guard lock(mPrimitivesLock);
  216. // Finish the last primitive
  217. FinalizePrimitive();
  218. // Get the camera and light frustum for culling
  219. Vec3 camera_pos(mRenderer->GetCameraState().mPos - mRenderer->GetBaseOffset());
  220. const Frustum &camera_frustum = mRenderer->GetCameraFrustum();
  221. const Frustum &light_frustum = mRenderer->GetLightFrustum();
  222. // Resize instances buffer and copy all visible instance data into it
  223. if (mNumInstances > 0)
  224. {
  225. // Create instances buffer
  226. RenderInstances *instances_buffer = mInstancesBuffer[mRenderer->GetCurrentFrameIndex()];
  227. instances_buffer->CreateBuffer(2 * mNumInstances, sizeof(Instance));
  228. Instance *dst_instance = reinterpret_cast<Instance *>(instances_buffer->Lock());
  229. // Next write index
  230. int dst_index = 0;
  231. // This keeps track of which instances use which lod, first array: 0 = light pass, 1 = geometry pass
  232. Array<Array<int>> lod_indices[2];
  233. for (InstanceMap *primitive_map : { &mPrimitives, &mTempPrimitives, &mPrimitivesBackFacing, &mWireframePrimitives })
  234. for (InstanceMap::value_type &v : *primitive_map)
  235. {
  236. // Get LODs
  237. const Array<LOD> &geometry_lods = v.first->mLODs;
  238. size_t num_lods = geometry_lods.size();
  239. JPH_ASSERT(num_lods > 0);
  240. // Ensure that our lod index array is big enough (to avoid reallocating memory too often)
  241. if (lod_indices[0].size() < num_lods)
  242. lod_indices[0].resize(num_lods);
  243. if (lod_indices[1].size() < num_lods)
  244. lod_indices[1].resize(num_lods);
  245. // Iterate over all instances
  246. const Array<InstanceWithLODInfo> &instances = v.second.mInstances;
  247. for (size_t i = 0; i < instances.size(); ++i)
  248. {
  249. const InstanceWithLODInfo &src_instance = instances[i];
  250. // Check if it overlaps with the light or camera frustum
  251. bool light_overlaps = light_frustum.Overlaps(src_instance.mWorldSpaceBounds);
  252. bool camera_overlaps = camera_frustum.Overlaps(src_instance.mWorldSpaceBounds);
  253. if (light_overlaps || camera_overlaps)
  254. {
  255. // Figure out which LOD to use
  256. const LOD &lod = v.first->GetLOD(camera_pos, src_instance.mWorldSpaceBounds, src_instance.mLODScaleSq);
  257. size_t lod_index = &lod - geometry_lods.data();
  258. // Store which index goes in which LOD
  259. if (light_overlaps)
  260. lod_indices[0][lod_index].push_back((int)i);
  261. if (camera_overlaps)
  262. lod_indices[1][lod_index].push_back((int)i);
  263. }
  264. }
  265. // Loop over both passes: 0 = light, 1 = geometry
  266. Array<int> *start_idx[] = { &v.second.mLightStartIdx, &v.second.mGeometryStartIdx };
  267. for (int type = 0; type < 2; ++type)
  268. {
  269. // Reserve space for instance indices
  270. Array<int> &type_start_idx = *start_idx[type];
  271. type_start_idx.resize(num_lods + 1);
  272. // Write out geometry pass instances
  273. for (size_t lod = 0; lod < num_lods; ++lod)
  274. {
  275. // Write start index for this LOD
  276. type_start_idx[lod] = dst_index;
  277. // Copy instances
  278. Array<int> &this_lod_indices = lod_indices[type][lod];
  279. for (int i : this_lod_indices)
  280. {
  281. const Instance &src_instance = instances[i];
  282. dst_instance[dst_index++] = src_instance;
  283. }
  284. // Prepare for next iteration (will preserve memory)
  285. this_lod_indices.clear();
  286. }
  287. // Write out end of last LOD
  288. type_start_idx.back() = dst_index;
  289. }
  290. }
  291. instances_buffer->Unlock();
  292. }
  293. if (!mPrimitives.empty() || !mTempPrimitives.empty())
  294. {
  295. // Front face culling, we want to render the back side of the geometry for casting shadows
  296. mShadowStateFF->Activate();
  297. // Draw all primitives as seen from the light
  298. if (mNumInstances > 0)
  299. for (InstanceMap::value_type &v : mPrimitives)
  300. DrawInstances(v.first, v.second.mLightStartIdx);
  301. for (InstanceMap::value_type &v : mTempPrimitives)
  302. DrawInstances(v.first, v.second.mLightStartIdx);
  303. }
  304. if (!mPrimitivesBackFacing.empty())
  305. {
  306. // Back face culling, we want to render the front side of back facing geometry
  307. mShadowStateBF->Activate();
  308. // Draw all primitives as seen from the light
  309. for (InstanceMap::value_type &v : mPrimitivesBackFacing)
  310. DrawInstances(v.first, v.second.mLightStartIdx);
  311. }
  312. if (!mWireframePrimitives.empty())
  313. {
  314. // Switch to wireframe mode
  315. mShadowStateWire->Activate();
  316. // Draw all wireframe primitives as seen from the light
  317. for (InstanceMap::value_type &v : mWireframePrimitives)
  318. DrawInstances(v.first, v.second.mLightStartIdx);
  319. }
  320. }
  321. void DebugRendererImp::DrawTriangles()
  322. {
  323. // Bind the shadow map texture
  324. mRenderer->GetShadowMap()->Bind();
  325. if (!mPrimitives.empty() || !mTempPrimitives.empty())
  326. {
  327. // Bind the normal shader, back face culling
  328. mTriangleStateBF->Activate();
  329. // Draw all primitives
  330. if (mNumInstances > 0)
  331. for (InstanceMap::value_type &v : mPrimitives)
  332. DrawInstances(v.first, v.second.mGeometryStartIdx);
  333. for (InstanceMap::value_type &v : mTempPrimitives)
  334. DrawInstances(v.first, v.second.mGeometryStartIdx);
  335. }
  336. if (!mPrimitivesBackFacing.empty())
  337. {
  338. // Front face culling, the next batch needs to render inside out
  339. mTriangleStateFF->Activate();
  340. // Draw all back primitives
  341. for (InstanceMap::value_type &v : mPrimitivesBackFacing)
  342. DrawInstances(v.first, v.second.mGeometryStartIdx);
  343. }
  344. if (!mWireframePrimitives.empty())
  345. {
  346. // Wire frame mode
  347. mTriangleStateWire->Activate();
  348. // Draw all wireframe primitives
  349. for (InstanceMap::value_type &v : mWireframePrimitives)
  350. DrawInstances(v.first, v.second.mGeometryStartIdx);
  351. }
  352. }
  353. void DebugRendererImp::DrawTexts()
  354. {
  355. lock_guard lock(mTextsLock);
  356. JPH_PROFILE_FUNCTION();
  357. const CameraState &camera_state = mRenderer->GetCameraState();
  358. for (const Text &t : mTexts)
  359. {
  360. Vec3 forward = camera_state.mForward;
  361. Vec3 right = forward.Cross(camera_state.mUp).Normalized();
  362. Vec3 up = right.Cross(forward).Normalized();
  363. Mat44 transform(Vec4(right, 0), Vec4(up, 0), Vec4(forward, 0), Vec4(t.mPosition, 1));
  364. mFont->DrawText3D(transform * Mat44::sScale(t.mHeight), t.mText, t.mColor);
  365. }
  366. }
  367. void DebugRendererImp::Draw()
  368. {
  369. DrawLines();
  370. DrawTriangles();
  371. DrawTexts();
  372. }
  373. void DebugRendererImp::ClearLines()
  374. {
  375. lock_guard lock(mLinesLock);
  376. mLines.clear();
  377. }
  378. void DebugRendererImp::ClearMap(InstanceMap &ioInstances)
  379. {
  380. Array<GeometryRef> to_delete;
  381. for (InstanceMap::value_type &kv : ioInstances)
  382. {
  383. if (kv.second.mInstances.empty())
  384. to_delete.push_back(kv.first);
  385. else
  386. kv.second.mInstances.clear();
  387. }
  388. for (GeometryRef &b : to_delete)
  389. ioInstances.erase(b);
  390. }
  391. void DebugRendererImp::ClearTriangles()
  392. {
  393. lock_guard lock(mPrimitivesLock);
  394. // Close any primitive that's being built
  395. FinalizePrimitive();
  396. // Move primitives to draw back to the free list
  397. ClearMap(mWireframePrimitives);
  398. ClearMap(mPrimitives);
  399. mTempPrimitives.clear(); // These are created by FinalizePrimitive() and need to be cleared every frame
  400. ClearMap(mPrimitivesBackFacing);
  401. mNumInstances = 0;
  402. }
  403. void DebugRendererImp::ClearTexts()
  404. {
  405. lock_guard lock(mTextsLock);
  406. mTexts.clear();
  407. }
  408. void DebugRendererImp::Clear()
  409. {
  410. ClearLines();
  411. ClearTriangles();
  412. ClearTexts();
  413. NextFrame();
  414. }