From 98bfbc1048fca2e11683ce8947c18d65fc5f561d Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 8 Jan 2023 01:06:50 +0800 Subject: [PATCH 1/3] Added DrawWireCapsule for debug draw (doesn't support orientation changes yet) --- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 58 ++++++++++++++++++ .../MiddleEnd/Interface/SHDebugDrawSystem.h | 23 ++++++++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 + .../MiddleEnd/Interface/SHGraphicsSystem.h | 5 +- .../MiddleEnd/Meshes/SHPrimitiveGenerator.cpp | 59 +++++++++++++++++++ .../MiddleEnd/Meshes/SHPrimitiveGenerator.h | 41 +++++++++++++ SHADE_Engine/src/Tools/SHDebugDraw.cpp | 8 +++ SHADE_Engine/src/Tools/SHDebugDraw.h | 24 ++++++++ 8 files changed, 218 insertions(+), 2 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index b57249de..fdd21fd4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -207,6 +207,11 @@ namespace SHADE drawSphere(getMeshBatch(true, depthTested), matrix, color); } + void SHDebugDrawSystem::DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + drawWireCapsule(getLineBatch(depthTested), getMeshBatch(false, depthTested), position, rotation, height, radius, color); + } + /*-----------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ /*-----------------------------------------------------------------------------------*/ @@ -264,6 +269,12 @@ namespace SHADE markPersistentDrawsDirty(); } + void SHDebugDrawSystem::DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + drawWireCapsule(getPersistentLineBatch(depthTested), getPersistentMeshBatch(false, depthTested), position, rotation, height, radius, color); + markPersistentDrawsDirty(); + } + void SHDebugDrawSystem::ClearPersistentDraws() { for (auto& batch : persistentLineBatches) @@ -348,6 +359,53 @@ namespace SHADE ); } + void SHDebugDrawSystem::drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color) + { + // Get local axis vectors + const SHVec3 LOCAL_UP = SHVec3::Up; + const SHVec3 LOCAL_RIGHT = SHVec3::Right; + const SHVec3 LOCAL_FORWARD = SHVec3::Forward; + + // Rotate the circle + SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)); + + // Compute top and bottom of the cylinder + const SHVec3 HALF_UP = LOCAL_UP * (height * 0.5f - radius); + const SHVec3 TOP_POS = position + HALF_UP; + const SHVec3 BOT_POS = position - HALF_UP; + + // Render circles + const SHVec3 CIRCLE_SCALE = SHVec3(radius * 2.0f, radius * 2.0, radius * 2.0); + drawCircle(meshBatch, SHMatrix::Transform(TOP_POS, circleOrientation, CIRCLE_SCALE), color); + drawCircle(meshBatch, SHMatrix::Transform(BOT_POS, circleOrientation, CIRCLE_SCALE), color); + + // Render connecting lines + drawLine(lineBatch, TOP_POS + LOCAL_RIGHT * radius, BOT_POS + LOCAL_RIGHT * radius, color); + drawLine(lineBatch, TOP_POS - LOCAL_RIGHT * radius, BOT_POS - LOCAL_RIGHT * radius, color); + drawLine(lineBatch, TOP_POS + LOCAL_FORWARD * radius, BOT_POS + LOCAL_FORWARD * radius, color); + drawLine(lineBatch, TOP_POS - LOCAL_FORWARD * radius, BOT_POS - LOCAL_FORWARD * radius, color); + + // Render caps + const SHVec3 RADIUS_SCALE = SHVec3(radius * 2.0, radius * 2.0f, radius * 2.0); + const SHMatrix TOP_CAP_MAT = SHMatrix::Transform(TOP_POS, rotation, RADIUS_SCALE); + drawMesh + ( + gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap), + meshBatch, TOP_CAP_MAT, color + ); + const SHMatrix BOT_CAP_MAT = SHMatrix::Transform + ( + BOT_POS, + rotation * SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)), + RADIUS_SCALE + ); + drawMesh + ( + gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap), + meshBatch, BOT_CAP_MAT, color + ); + } + /*-----------------------------------------------------------------------------------*/ /* Helper Batch Functions - Lines */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h index 2978d68e..3997b6df 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h @@ -163,6 +163,17 @@ namespace SHADE /// Colour to draw with. /// Whether or not drawn object will be occluded. void DrawSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// + /// Draws the outline of a capsule. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ @@ -269,6 +280,17 @@ namespace SHADE /// Whether or not drawn object will be occluded. void DrawPersistentSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false); /// + /// Draws a persistent outline of a capsule. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// /// Clears any persistent drawn debug primitives. /// void ClearPersistentDraws(); @@ -386,6 +408,7 @@ namespace SHADE void drawCube(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); void drawSphere(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); void drawCircle(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); + void drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color); /*---------------------------------------------------------------------------------*/ /* Helper Batch Functions - Lines */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index b1256921..f3bcc8f7 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -419,6 +419,7 @@ namespace SHADE primitiveMeshes[static_cast(PrimitiveType::Sphere)] = SHPrimitiveGenerator::Sphere(meshLibrary); primitiveMeshes[static_cast(PrimitiveType::LineCube)] = SHPrimitiveGenerator::LineCube(meshLibrary); primitiveMeshes[static_cast(PrimitiveType::LineCircle)] = SHPrimitiveGenerator::LineCircle(meshLibrary); + primitiveMeshes[static_cast(PrimitiveType::LineCapsuleCap)] = SHPrimitiveGenerator::LineCapsuleCap(meshLibrary); BuildMeshBuffers(); // Create default materials @@ -819,6 +820,7 @@ namespace SHADE case PrimitiveType::Sphere: case PrimitiveType::LineCube: case PrimitiveType::LineCircle: + case PrimitiveType::LineCapsuleCap: return primitiveMeshes[static_cast(type)]; default: return {}; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 40148e05..707862f9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -72,9 +72,10 @@ namespace SHADE Cube, Sphere, LineCube, - LineCircle + LineCircle, + LineCapsuleCap }; - static constexpr int MAX_PRIMITIVE_TYPES = 4; + static constexpr int MAX_PRIMITIVE_TYPES = 5; enum class DebugDrawPipelineType { LineNoDepthTest, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp index 444a6630..d5a0073f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp @@ -29,6 +29,7 @@ namespace SHADE SHMeshData SHPrimitiveGenerator::sphereMesh; SHMeshData SHPrimitiveGenerator::lineCubeMesh; SHMeshData SHPrimitiveGenerator::lineCircleMesh; + SHMeshData SHPrimitiveGenerator::lineCapsuleCapMesh; /*-----------------------------------------------------------------------------------*/ /* Primitive Generation Functions */ @@ -392,6 +393,64 @@ namespace SHADE return addMeshDataTo(lineCircleMesh, gfxSystem); } + SHADE::SHMeshData SHPrimitiveGenerator::LineCapsuleCap() noexcept + { + SHMeshData mesh; + + // Have multiple semi-circles for the cap + static constexpr int SPLITS = 36; + static constexpr float ANGLE_INCREMENTS = (std::numbers::pi_v * 2.0f) / static_cast(SPLITS); + + /* X-Axis */ + // Generate points of the circle + for (int i = 0; i <= SPLITS / 2; ++i) + { + const float ANGLE = ANGLE_INCREMENTS * i; + mesh.VertexPositions.emplace_back(cos(ANGLE) * 0.5f, sin(ANGLE) * 0.5f, 0.0f); + } + + // Generate lines of the circle + for (int i = 1; i <= SPLITS / 2; ++i) + { + mesh.Indices.emplace_back(static_cast(i - 1)); + mesh.Indices.emplace_back(static_cast(i)); + } + + /* Z-Axis */ + // Generate points of the circle + for (int i = 0; i <= SPLITS / 2; ++i) + { + const float ANGLE = ANGLE_INCREMENTS * i; + mesh.VertexPositions.emplace_back(0.0f, sin(ANGLE) * 0.5f, cos(ANGLE) * 0.5f); + } + + // Generate lines of the circle + for (int i = 2 + SPLITS / 2; i <= SPLITS + 1; ++i) + { + mesh.Indices.emplace_back(static_cast(i - 1)); + mesh.Indices.emplace_back(static_cast(i)); + } + + mesh.VertexNormals.resize(mesh.VertexPositions.size()); + mesh.VertexTangents.resize(mesh.VertexPositions.size()); + mesh.VertexTexCoords.resize(mesh.VertexPositions.size()); + + return mesh; + } + Handle SHPrimitiveGenerator::LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept + { + if (lineCapsuleCapMesh.VertexPositions.empty()) + lineCapsuleCapMesh = LineCapsuleCap(); + + return addMeshDataTo(lineCapsuleCapMesh, meshLibrary); + } + Handle SHPrimitiveGenerator::LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept + { + if (lineCapsuleCapMesh.VertexPositions.empty()) + lineCapsuleCapMesh = LineCapsuleCap(); + + return addMeshDataTo(lineCapsuleCapMesh, gfxSystem); + } /*-----------------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h index 9bcd2f3c..e8c7c3fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h @@ -194,6 +194,46 @@ namespace SHADE */ /***********************************************************************************/ [[nodiscard]] static Handle LineCircle(SHGraphicsSystem& gfxSystem) noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a circle that is comprised only of lines with no diagonal lines and + store the data in a SHMeshData object. + + \return + SHMeshData object containing vertex data for the line circle. + */ + /***********************************************************************************/ + [[nodiscard]] static SHMeshData LineCapsuleCap() noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a line circle and constructs a SHMesh using the SHGraphicsSystem + provided. + + \param meshLibrary + Reference to the SHMeshLibrary to produce and store a line circle mesh in. + + \return + SHMesh object that points to the generated line circle mesh in the SHMeshLibrary. + */ + /***********************************************************************************/ + [[nodiscard]] static Handle LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a line circle and constructs a SHMesh using the SHGraphicsSystem + provided. + + \param gfxSystem + Reference to the SHGraphicsSystem to produce and store a line circle mesh in. + + \return + SHMesh object that points to the generated line circle mesh in the + SHGraphicsSystem. + */ + /***********************************************************************************/ + [[nodiscard]] static Handle LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -209,5 +249,6 @@ namespace SHADE static SHMeshData sphereMesh; static SHMeshData lineCubeMesh; static SHMeshData lineCircleMesh; + static SHMeshData lineCapsuleCapMesh; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.cpp b/SHADE_Engine/src/Tools/SHDebugDraw.cpp index 02eca592..ee040d8b 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.cpp +++ b/SHADE_Engine/src/Tools/SHDebugDraw.cpp @@ -128,6 +128,10 @@ namespace SHADE dbgDrawSys->DrawWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested); } + void SHDebugDraw::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + dbgDrawSys->DrawWireCapsule(position, rotation, height, radius, color, depthTested); + } /*-----------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ /*-----------------------------------------------------------------------------------*/ @@ -216,6 +220,10 @@ namespace SHADE dbgDrawSys->DrawPersistentWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested); } + void SHDebugDraw::Persistent::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + dbgDrawSys->DrawPersistentWireCapsule(position, rotation, height, radius, color, depthTested); + } void SHDebugDraw::Persistent::ClearDraws() { dbgDrawSys->ClearPersistentDraws(); diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.h b/SHADE_Engine/src/Tools/SHDebugDraw.h index c28b93e6..3d7bee2f 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.h +++ b/SHADE_Engine/src/Tools/SHDebugDraw.h @@ -194,6 +194,18 @@ namespace SHADE /// Colour to draw with. /// Whether or not drawn object will be occluded. static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false); + /// + /// Draws the outline of a capsule. + /// This will remain drawn until ClearDraws() is called. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Function Class "Folder" */ @@ -366,6 +378,18 @@ namespace SHADE /// Whether or not drawn object will be occluded. static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false); /// + /// Draws the outline of a capsule. + /// This will remain drawn until ClearDraws() is called. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// /// Clears any persistent drawn debug primitives. /// static void ClearDraws(); From f44e7b7a1c2a17d41a0047049428192565463e6a Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 8 Jan 2023 01:43:40 +0800 Subject: [PATCH 2/3] Debug draw capsule now works with different orientations --- .../Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index fdd21fd4..ae8c62b2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -362,12 +362,12 @@ namespace SHADE void SHDebugDrawSystem::drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color) { // Get local axis vectors - const SHVec3 LOCAL_UP = SHVec3::Up; - const SHVec3 LOCAL_RIGHT = SHVec3::Right; - const SHVec3 LOCAL_FORWARD = SHVec3::Forward; + const SHVec3 LOCAL_UP = SHVec3::Rotate(SHVec3::Up, rotation); + const SHVec3 LOCAL_RIGHT = SHVec3::Rotate(SHVec3::Right, rotation); + const SHVec3 LOCAL_FORWARD = SHVec3::Rotate(SHVec3::Forward, rotation); // Rotate the circle - SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)); + SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)) * rotation; // Compute top and bottom of the cylinder const SHVec3 HALF_UP = LOCAL_UP * (height * 0.5f - radius); @@ -396,7 +396,7 @@ namespace SHADE const SHMatrix BOT_CAP_MAT = SHMatrix::Transform ( BOT_POS, - rotation * SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)), + SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)) * rotation, RADIUS_SCALE ); drawMesh From 686e141efaad45351a836dd91e42a792b52055c2 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 8 Jan 2023 01:46:52 +0800 Subject: [PATCH 3/3] Fixed comment for SHPrimitiveGenerator::LineCapsuleCap --- .../Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h index e8c7c3fb..839d0ef6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h @@ -197,7 +197,7 @@ namespace SHADE /***********************************************************************************/ /*! \brief - Produces a circle that is comprised only of lines with no diagonal lines and + Produces a cap of a wireframe capsule that is comprised only of lines and store the data in a SHMeshData object. \return @@ -208,8 +208,8 @@ namespace SHADE /***********************************************************************************/ /*! \brief - Produces a line circle and constructs a SHMesh using the SHGraphicsSystem - provided. + Produces a cap of a wireframe capsule that is comprised only of lines and + constructs a SHMesh using the SHGraphicsSystem provided. \param meshLibrary Reference to the SHMeshLibrary to produce and store a line circle mesh in. @@ -222,8 +222,8 @@ namespace SHADE /***********************************************************************************/ /*! \brief - Produces a line circle and constructs a SHMesh using the SHGraphicsSystem - provided. + Produces a cap of a wireframe capsule that is comprised only of lines and + constructs a SHMesh using the SHGraphicsSystem provided. \param gfxSystem Reference to the SHGraphicsSystem to produce and store a line circle mesh in.