From e11f4d99b03981a281b110946de0c2261c2efdd2 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 13 Jan 2026 19:47:44 +0200 Subject: [PATCH 1/5] [Feature]: Add Circle and Sphere to ShapeRenderer --- assets/shaders/shape_renderer.frag | 4 +- assets/shaders/shape_renderer.vert | 1 - assets/shaders/shape_renderer_sdf.frag | 28 +++++++ assets/shaders/shape_renderer_sdf.vert | 29 +++++++ .../entity/renderer/shape_renderer.hpp | 12 ++- src/gamecoe/core/game.cpp | 3 + .../entity/renderer/shape_renderer.cpp | 78 ++++++++++++++----- 7 files changed, 128 insertions(+), 27 deletions(-) create mode 100644 assets/shaders/shape_renderer_sdf.frag create mode 100644 assets/shaders/shape_renderer_sdf.vert diff --git a/assets/shaders/shape_renderer.frag b/assets/shaders/shape_renderer.frag index fbf3db5..99e6560 100644 --- a/assets/shaders/shape_renderer.frag +++ b/assets/shaders/shape_renderer.frag @@ -1,9 +1,9 @@ -uniform vec4 color; - #if __VERSION__ >= 330 out vec4 FragColor; #endif +uniform vec4 color; + void main() { #if __VERSION__ >= 330 diff --git a/assets/shaders/shape_renderer.vert b/assets/shaders/shape_renderer.vert index bbcf78f..86a1003 100644 --- a/assets/shaders/shape_renderer.vert +++ b/assets/shaders/shape_renderer.vert @@ -3,7 +3,6 @@ layout (location = 0) in vec3 aPos; #else attribute vec3 aPos; #endif -// texture, etc... in the future uniform mat4 model; #if GAMECOE_HAS_UBO diff --git a/assets/shaders/shape_renderer_sdf.frag b/assets/shaders/shape_renderer_sdf.frag new file mode 100644 index 0000000..f9cf91f --- /dev/null +++ b/assets/shaders/shape_renderer_sdf.frag @@ -0,0 +1,28 @@ +#if __VERSION__ >= 330 +in vec3 localPos; +#else +varying vec3 localPos; +#endif + +#if __VERSION__ >= 330 +out vec4 FragColor; +#endif + +uniform vec4 color; + +void main() +{ + const float RADIUS = 1.0; + const float SMOOTHNESS = 0.015; + + vec3 samplePos = localPos * 2.1; + float dist = length(samplePos); + + float alpha = 1.0 - smoothstep(RADIUS - SMOOTHNESS, RADIUS + SMOOTHNESS, dist); + +#if __VERSION__ >= 330 + FragColor = vec4(color.rgb, color.a * alpha); +#else + gl_FragColor = vec4(color.rgb, color.a * alpha); +#endif +} diff --git a/assets/shaders/shape_renderer_sdf.vert b/assets/shaders/shape_renderer_sdf.vert new file mode 100644 index 0000000..2a511bf --- /dev/null +++ b/assets/shaders/shape_renderer_sdf.vert @@ -0,0 +1,29 @@ +#if __VERSION__ >= 330 +layout (location = 0) in vec3 aPos; +#else +attribute vec3 aPos; +#endif + +#if __VERSION__ >= 330 +out vec3 localPos; +#else +varying vec3 localPos; +#endif + +uniform mat4 model; +#if GAMECOE_HAS_UBO +layout(std140) uniform CameraMatrices +{ + mat4 projection; + mat4 view; +}; +#else +uniform mat4 view; +uniform mat4 projection; +#endif + +void main() +{ + localPos = aPos; + gl_Position = projection * view * model * vec4(aPos, 1.0); +} diff --git a/include/gamecoe/entity/renderer/shape_renderer.hpp b/include/gamecoe/entity/renderer/shape_renderer.hpp index f5740bc..dbc6cb0 100644 --- a/include/gamecoe/entity/renderer/shape_renderer.hpp +++ b/include/gamecoe/entity/renderer/shape_renderer.hpp @@ -16,21 +16,23 @@ namespace gamecoe Triangle, Rectangle, Box, + Circle, + Sphere, // TODO: Support more primitive shapes }; class ShapeRenderer : public Renderer { static std::atomic s_counter; - static std::optional s_shader; -#if GAMECOE_HAS_UBO - static std::uint32_t s_cameraUniformBlockIndex; -#endif + static std::optional s_shapeShader; + static std::optional s_sdfShader; Shape m_shape; Color m_color; const VertexArray &m_vertexArray; + std::optional &shapeToShader(gamecoe::Shape shape) const; + ShapeRenderer(GameObject &owner, Shape shape, const Color &color, std::int8_t layer = 0); public: @@ -55,6 +57,8 @@ namespace gamecoe static std::unique_ptr triangle(GameObject &owner, const Color &color, std::int8_t layer = 0); static std::unique_ptr rectangle(GameObject &owner, const Color &color, std::int8_t layer = 0); static std::unique_ptr box(GameObject &owner, const Color &color, std::int8_t layer = 0); + static std::unique_ptr circle(GameObject &owner, const Color &color, std::int8_t layer = 0); + static std::unique_ptr sphere(GameObject &owner, const Color &color, std::int8_t layer = 0); }; } // namespace gamecoe \ No newline at end of file diff --git a/src/gamecoe/core/game.cpp b/src/gamecoe/core/game.cpp index 8b0da9b..0cb1e2f 100644 --- a/src/gamecoe/core/game.cpp +++ b/src/gamecoe/core/game.cpp @@ -59,6 +59,9 @@ namespace gamecoe #if GAMECOE_USE_OPENGL if(!gladLoadGL(glfwGetProcAddress)) detail::throwError("Game::Game(): Failed to initialize glad"); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif m_internalScene.emplace(*this, "gamecoe::Internal"); diff --git a/src/gamecoe/entity/renderer/shape_renderer.cpp b/src/gamecoe/entity/renderer/shape_renderer.cpp index faaa22f..580eafd 100644 --- a/src/gamecoe/entity/renderer/shape_renderer.cpp +++ b/src/gamecoe/entity/renderer/shape_renderer.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #if GAMECOE_USE_OPENGL @@ -22,13 +23,27 @@ namespace case gamecoe::Shape::Triangle: return gamecoe::VertexArray::triangle(); case gamecoe::Shape::Rectangle: + case gamecoe::Shape::Circle: return gamecoe::VertexArray::rectangle(); case gamecoe::Shape::Box: + case gamecoe::Shape::Sphere: + default: return gamecoe::VertexArray::box(); - + } + } + + std::pair shapeToShaderPaths(gamecoe::Shape shape) + { + switch (shape) + { + case gamecoe::Shape::Triangle: + case gamecoe::Shape::Rectangle: + case gamecoe::Shape::Box: + return { "gamecoe/shaders/shape_renderer.vert", "gamecoe/shaders/shape_renderer.frag" }; + case gamecoe::Shape::Circle: + case gamecoe::Shape::Sphere: default: - assert(false && "Need to add support for a new Shape"); - break; + return { "gamecoe/shaders/shape_renderer_sdf.vert", "gamecoe/shaders/shape_renderer_sdf.frag" }; } } } @@ -36,10 +51,23 @@ namespace namespace gamecoe { std::atomic ShapeRenderer::s_counter = 0; - std::optional ShapeRenderer::s_shader = std::nullopt; -#if GAMECOE_HAS_UBO - std::uint32_t ShapeRenderer::s_cameraUniformBlockIndex = 0; -#endif + std::optional ShapeRenderer::s_shapeShader = std::nullopt; + std::optional ShapeRenderer::s_sdfShader = std::nullopt; + + std::optional &ShapeRenderer::shapeToShader(gamecoe::Shape shape) const + { + switch (shape) + { + case Shape::Triangle: + case Shape::Rectangle: + case Shape::Box: + return s_shapeShader; + case Shape::Circle: + case Shape::Sphere: + default: + return s_sdfShader; + } + } ShapeRenderer::ShapeRenderer(GameObject &owner, Shape shape, const Color &color, std::int8_t layer) : Renderer(owner, layer), @@ -55,7 +83,8 @@ namespace gamecoe --s_counter; if (s_counter == 0) { - s_shader.reset(); + s_shapeShader.reset(); + s_sdfShader.reset(); VertexArray::destroyShapeVAs(); } } @@ -64,27 +93,26 @@ namespace gamecoe { if (!m_active) return; - if (!s_shader) + std::optional &shader = shapeToShader(m_shape); + if (!shader) { - s_shader.emplace( - resolvePath("gamecoe/shaders/shape_renderer.vert"), - resolvePath("gamecoe/shaders/shape_renderer.frag") - ); + auto shaderPaths = shapeToShaderPaths(m_shape); + shader.emplace(resolvePath(shaderPaths.first), resolvePath(shaderPaths.second)); #if GAMECOE_HAS_UBO - s_cameraUniformBlockIndex = glGetUniformBlockIndex(s_shader->id(), "CameraMatrices"); - glUniformBlockBinding(s_shader->id(), s_cameraUniformBlockIndex, constcoe::CAMERA_UBO_BINDING_POINT); + std::uint32_t cameraUniformBlockIndex = glGetUniformBlockIndex(shader->id(), "CameraMatrices"); + glUniformBlockBinding(shader->id(), cameraUniformBlockIndex, constcoe::CAMERA_UBO_BINDING_POINT); #endif } - s_shader->use(); + shader->use(); #if !GAMECOE_HAS_UBO auto &camera = owner().game().mainCamera(); - s_shader->set("view", camera.viewMatrix()); - s_shader->set("projection", camera.projectionMatrix()); + shader->set("view", camera.viewMatrix()); + shader->set("projection", camera.projectionMatrix()); #endif - s_shader->set("model", owner().transform().modelMatrix()); - s_shader->set("color", m_color.normalized()); + shader->set("model", owner().transform().modelMatrix()); + shader->set("color", m_color.normalized()); m_vertexArray.bind(); @@ -117,4 +145,14 @@ namespace gamecoe { return std::unique_ptr(new ShapeRenderer(owner, Shape::Box, color, layer)); } + + std::unique_ptr ShapeRenderer::circle(GameObject &owner, const Color &color, std::int8_t layer) + { + return std::unique_ptr(new ShapeRenderer(owner, Shape::Circle, color, layer)); + } + + std::unique_ptr ShapeRenderer::sphere(GameObject &owner, const Color &color, std::int8_t layer) + { + return std::unique_ptr(new ShapeRenderer(owner, Shape::Sphere, color, layer)); + } } // namespace gamecoe From f4b54a47234a0b0207f3abd7919275759d5d37e8 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 13 Jan 2026 20:08:55 +0200 Subject: [PATCH 2/5] Add glEnable(GL_DEPTH_TEST) for Sphere --- assets/shaders/shape_renderer_sdf.frag | 9 +++------ assets/shaders/shape_renderer_sdf.vert | 6 +----- src/gamecoe/core/game.cpp | 1 + 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/assets/shaders/shape_renderer_sdf.frag b/assets/shaders/shape_renderer_sdf.frag index f9cf91f..4b6d481 100644 --- a/assets/shaders/shape_renderer_sdf.frag +++ b/assets/shaders/shape_renderer_sdf.frag @@ -1,24 +1,21 @@ #if __VERSION__ >= 330 in vec3 localPos; +out vec4 FragColor; #else varying vec3 localPos; #endif -#if __VERSION__ >= 330 -out vec4 FragColor; -#endif - uniform vec4 color; void main() { const float RADIUS = 1.0; - const float SMOOTHNESS = 0.015; vec3 samplePos = localPos * 2.1; float dist = length(samplePos); - float alpha = 1.0 - smoothstep(RADIUS - SMOOTHNESS, RADIUS + SMOOTHNESS, dist); + float edgeWidth = fwidth(dist); + float alpha = 1.0 - smoothstep(RADIUS - edgeWidth, RADIUS + edgeWidth, dist); #if __VERSION__ >= 330 FragColor = vec4(color.rgb, color.a * alpha); diff --git a/assets/shaders/shape_renderer_sdf.vert b/assets/shaders/shape_renderer_sdf.vert index 2a511bf..3b03306 100644 --- a/assets/shaders/shape_renderer_sdf.vert +++ b/assets/shaders/shape_renderer_sdf.vert @@ -1,12 +1,8 @@ #if __VERSION__ >= 330 layout (location = 0) in vec3 aPos; -#else -attribute vec3 aPos; -#endif - -#if __VERSION__ >= 330 out vec3 localPos; #else +attribute vec3 aPos; varying vec3 localPos; #endif diff --git a/src/gamecoe/core/game.cpp b/src/gamecoe/core/game.cpp index 0cb1e2f..f7708c2 100644 --- a/src/gamecoe/core/game.cpp +++ b/src/gamecoe/core/game.cpp @@ -60,6 +60,7 @@ namespace gamecoe if(!gladLoadGL(glfwGetProcAddress)) detail::throwError("Game::Game(): Failed to initialize glad"); + glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif From 3a07b434f1885c4f15dd020f35d5034c49411b52 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 13 Jan 2026 20:17:02 +0200 Subject: [PATCH 3/5] Add MultiSample and different multiplier in frag shader --- assets/shaders/shape_renderer_sdf.frag | 4 +++- src/gamecoe/core/game.cpp | 1 + src/gamecoe/core/window.cpp | 1 + src/gamecoe/entity/renderer/shape_renderer.cpp | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/assets/shaders/shape_renderer_sdf.frag b/assets/shaders/shape_renderer_sdf.frag index 4b6d481..1ea7399 100644 --- a/assets/shaders/shape_renderer_sdf.frag +++ b/assets/shaders/shape_renderer_sdf.frag @@ -6,12 +6,14 @@ varying vec3 localPos; #endif uniform vec4 color; +uniform int shapeType; // 0 == Circle, 1 == Sphere void main() { const float RADIUS = 1.0; - vec3 samplePos = localPos * 2.1; + float multiplier = (shapeType == 0) ? 2.1 : 1.75; + vec3 samplePos = localPos * multiplier; float dist = length(samplePos); float edgeWidth = fwidth(dist); diff --git a/src/gamecoe/core/game.cpp b/src/gamecoe/core/game.cpp index f7708c2..74fb624 100644 --- a/src/gamecoe/core/game.cpp +++ b/src/gamecoe/core/game.cpp @@ -61,6 +61,7 @@ namespace gamecoe detail::throwError("Game::Game(): Failed to initialize glad"); glEnable(GL_DEPTH_TEST); + glEnable(GL_MULTISAMPLE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif diff --git a/src/gamecoe/core/window.cpp b/src/gamecoe/core/window.cpp index a04186f..8ca3b2e 100644 --- a/src/gamecoe/core/window.cpp +++ b/src/gamecoe/core/window.cpp @@ -38,6 +38,7 @@ namespace gamecoe glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif #endif + glfwWindowHint(GLFW_SAMPLES, 4); // which opengl version? work only on opengl? GLFWwindow *current = glfwGetCurrentContext(); GLFWwindow *window = glfwCreateWindow(m_width, m_height, m_title.c_str(), nullptr, current); diff --git a/src/gamecoe/entity/renderer/shape_renderer.cpp b/src/gamecoe/entity/renderer/shape_renderer.cpp index 580eafd..3e9d16f 100644 --- a/src/gamecoe/entity/renderer/shape_renderer.cpp +++ b/src/gamecoe/entity/renderer/shape_renderer.cpp @@ -113,6 +113,8 @@ namespace gamecoe #endif shader->set("model", owner().transform().modelMatrix()); shader->set("color", m_color.normalized()); + if (m_shape == Shape::Circle || m_shape == Shape::Sphere) + shader->set("shapeType", m_shape == Shape::Circle ? 0 : 1); m_vertexArray.bind(); From 790481ee149d46a0d6c44aafd577208171baf021 Mon Sep 17 00:00:00 2001 From: nircoe Date: Fri, 16 Jan 2026 13:21:54 +0200 Subject: [PATCH 4/5] Add sphere_renderer shaders --- ...renderer_sdf.frag => circle_renderer.frag} | 16 +++-- ...renderer_sdf.vert => circle_renderer.vert} | 2 + assets/shaders/shape_renderer.vert | 2 + assets/shaders/sphere_renderer.frag | 60 +++++++++++++++++++ assets/shaders/sphere_renderer.vert | 27 +++++++++ .../entity/renderer/shape_renderer.hpp | 3 +- src/gamecoe/entity/camera.cpp | 2 + .../entity/renderer/shape_renderer.cpp | 27 +++++---- 8 files changed, 121 insertions(+), 18 deletions(-) rename assets/shaders/{shape_renderer_sdf.frag => circle_renderer.frag} (68%) rename assets/shaders/{shape_renderer_sdf.vert => circle_renderer.vert} (88%) create mode 100644 assets/shaders/sphere_renderer.frag create mode 100644 assets/shaders/sphere_renderer.vert diff --git a/assets/shaders/shape_renderer_sdf.frag b/assets/shaders/circle_renderer.frag similarity index 68% rename from assets/shaders/shape_renderer_sdf.frag rename to assets/shaders/circle_renderer.frag index 1ea7399..baf7b86 100644 --- a/assets/shaders/shape_renderer_sdf.frag +++ b/assets/shaders/circle_renderer.frag @@ -6,19 +6,25 @@ varying vec3 localPos; #endif uniform vec4 color; -uniform int shapeType; // 0 == Circle, 1 == Sphere -void main() +float circleAlpha(vec3 lPos) { const float RADIUS = 1.0; + const float MULTIPLIER = 2.1; // Quad is -0.5 to 0.5, scale to radius 1.0 - float multiplier = (shapeType == 0) ? 2.1 : 1.75; - vec3 samplePos = localPos * multiplier; - float dist = length(samplePos); + vec3 samplePos = lPos * MULTIPLIER; + float dist = length(samplePos); float edgeWidth = fwidth(dist); float alpha = 1.0 - smoothstep(RADIUS - edgeWidth, RADIUS + edgeWidth, dist); + return alpha; +} + +void main() +{ + float alpha = circleAlpha(localPos); + #if __VERSION__ >= 330 FragColor = vec4(color.rgb, color.a * alpha); #else diff --git a/assets/shaders/shape_renderer_sdf.vert b/assets/shaders/circle_renderer.vert similarity index 88% rename from assets/shaders/shape_renderer_sdf.vert rename to assets/shaders/circle_renderer.vert index 3b03306..950331f 100644 --- a/assets/shaders/shape_renderer_sdf.vert +++ b/assets/shaders/circle_renderer.vert @@ -12,10 +12,12 @@ layout(std140) uniform CameraMatrices { mat4 projection; mat4 view; + vec3 cameraPosition; }; #else uniform mat4 view; uniform mat4 projection; +uniform vec3 cameraPosition; #endif void main() diff --git a/assets/shaders/shape_renderer.vert b/assets/shaders/shape_renderer.vert index 86a1003..23e6418 100644 --- a/assets/shaders/shape_renderer.vert +++ b/assets/shaders/shape_renderer.vert @@ -10,10 +10,12 @@ layout(std140) uniform CameraMatrices { mat4 projection; mat4 view; + vec3 cameraPosition; }; #else uniform mat4 view; uniform mat4 projection; +uniform vec3 cameraPosition; #endif void main() diff --git a/assets/shaders/sphere_renderer.frag b/assets/shaders/sphere_renderer.frag new file mode 100644 index 0000000..80f6822 --- /dev/null +++ b/assets/shaders/sphere_renderer.frag @@ -0,0 +1,60 @@ +#if __VERSION__ >= 330 +in vec3 localPos; +out vec4 FragColor; +#else +varying vec3 localPos; +#endif + +uniform vec4 color; +#if GAMECOE_HAS_UBO +layout(std140) uniform CameraMatrices +{ + mat4 projection; + mat4 view; + vec3 cameraPosition; +}; +#else +uniform mat4 view; +uniform mat4 projection; +uniform vec3 cameraPosition; +#endif + +float sphereAlpha(vec3 rayOrigin, vec3 lPos) +{ + // Sphere center at (0, 0, 0) + const float RADIUS = 1.0; + const float MULTIPLIER = 1.75; // Box is -0.5 to 0.5, scale to radius 1.0 + + vec3 samplePos = lPos * MULTIPLIER; + vec3 rayDirection = vec3(normalize(samplePos - rayOrigin)); + + float a = dot(rayDirection, rayDirection); + float b = 2.0 * dot(rayOrigin, rayDirection); + float c = dot(rayOrigin, rayOrigin) - (RADIUS * RADIUS); + + float discriminant = b * b - 4.0 * a * c; + + return (discriminant >= 0.0) ? 1.0 : 0.0; + /* + if (discriminant < 0.0) + { + return 0.0; + } + + float t1 = (-b + sqrt(discriminant)) / (2.0 * a); + float t2 = (-b - sqrt(discriminant)) / (2.0 * a); + float t = t2 > 0.0 ? t2 : t1; + vec3 intersection = rayOrigin + vec3(t * rayDirection); + */ +} + +void main() +{ + float alpha = sphereAlpha(cameraPosition, localPos); + +#if __VERSION__ >= 330 + FragColor = vec4(color.rgb, color.a * alpha); +#else + gl_FragColor = vec4(color.rgb, color.a * alpha); +#endif +} \ No newline at end of file diff --git a/assets/shaders/sphere_renderer.vert b/assets/shaders/sphere_renderer.vert new file mode 100644 index 0000000..950331f --- /dev/null +++ b/assets/shaders/sphere_renderer.vert @@ -0,0 +1,27 @@ +#if __VERSION__ >= 330 +layout (location = 0) in vec3 aPos; +out vec3 localPos; +#else +attribute vec3 aPos; +varying vec3 localPos; +#endif + +uniform mat4 model; +#if GAMECOE_HAS_UBO +layout(std140) uniform CameraMatrices +{ + mat4 projection; + mat4 view; + vec3 cameraPosition; +}; +#else +uniform mat4 view; +uniform mat4 projection; +uniform vec3 cameraPosition; +#endif + +void main() +{ + localPos = aPos; + gl_Position = projection * view * model * vec4(aPos, 1.0); +} diff --git a/include/gamecoe/entity/renderer/shape_renderer.hpp b/include/gamecoe/entity/renderer/shape_renderer.hpp index dbc6cb0..4d303f0 100644 --- a/include/gamecoe/entity/renderer/shape_renderer.hpp +++ b/include/gamecoe/entity/renderer/shape_renderer.hpp @@ -25,7 +25,8 @@ namespace gamecoe { static std::atomic s_counter; static std::optional s_shapeShader; - static std::optional s_sdfShader; + static std::optional s_circleShader; + static std::optional s_sphereShader; Shape m_shape; Color m_color; diff --git a/src/gamecoe/entity/camera.cpp b/src/gamecoe/entity/camera.cpp index 0b3ab06..de103e8 100644 --- a/src/gamecoe/entity/camera.cpp +++ b/src/gamecoe/entity/camera.cpp @@ -37,9 +37,11 @@ namespace gamecoe { glm::mat4 m_projection; glm::mat4 m_view; + glm::vec3 m_cameraPosition; } data; data.m_projection = projectionMatrix(); data.m_view = viewMatrix(); + data.m_cameraPosition = m_owner.transform().position(); m_uniformBuffer->uploadData(&data, sizeof(data)); #endif diff --git a/src/gamecoe/entity/renderer/shape_renderer.cpp b/src/gamecoe/entity/renderer/shape_renderer.cpp index 3e9d16f..bc8998d 100644 --- a/src/gamecoe/entity/renderer/shape_renderer.cpp +++ b/src/gamecoe/entity/renderer/shape_renderer.cpp @@ -36,14 +36,15 @@ namespace { switch (shape) { + case gamecoe::Shape::Circle: + return { "gamecoe/shaders/circle_renderer.vert", "gamecoe/shaders/circle_renderer.frag" }; + case gamecoe::Shape::Sphere: + return { "gamecoe/shaders/sphere_renderer.vert", "gamecoe/shaders/sphere_renderer.frag" }; case gamecoe::Shape::Triangle: case gamecoe::Shape::Rectangle: case gamecoe::Shape::Box: - return { "gamecoe/shaders/shape_renderer.vert", "gamecoe/shaders/shape_renderer.frag" }; - case gamecoe::Shape::Circle: - case gamecoe::Shape::Sphere: default: - return { "gamecoe/shaders/shape_renderer_sdf.vert", "gamecoe/shaders/shape_renderer_sdf.frag" }; + return { "gamecoe/shaders/shape_renderer.vert", "gamecoe/shaders/shape_renderer.frag" }; } } } @@ -52,20 +53,22 @@ namespace gamecoe { std::atomic ShapeRenderer::s_counter = 0; std::optional ShapeRenderer::s_shapeShader = std::nullopt; - std::optional ShapeRenderer::s_sdfShader = std::nullopt; + std::optional ShapeRenderer::s_circleShader = std::nullopt; + std::optional ShapeRenderer::s_sphereShader = std::nullopt; std::optional &ShapeRenderer::shapeToShader(gamecoe::Shape shape) const { switch (shape) { + case Shape::Circle: + return s_circleShader; + case Shape::Sphere: + return s_sphereShader; case Shape::Triangle: case Shape::Rectangle: case Shape::Box: - return s_shapeShader; - case Shape::Circle: - case Shape::Sphere: default: - return s_sdfShader; + return s_shapeShader; } } @@ -84,7 +87,8 @@ namespace gamecoe if (s_counter == 0) { s_shapeShader.reset(); - s_sdfShader.reset(); + s_circleShader.reset(); + s_sphereShader.reset(); VertexArray::destroyShapeVAs(); } } @@ -110,11 +114,10 @@ namespace gamecoe auto &camera = owner().game().mainCamera(); shader->set("view", camera.viewMatrix()); shader->set("projection", camera.projectionMatrix()); + shader->set("cameraPosition", camera.owner().transform().position()); #endif shader->set("model", owner().transform().modelMatrix()); shader->set("color", m_color.normalized()); - if (m_shape == Shape::Circle || m_shape == Shape::Sphere) - shader->set("shapeType", m_shape == Shape::Circle ? 0 : 1); m_vertexArray.bind(); From 241ebbf908a67675254d956d5f6d1141d4207008 Mon Sep 17 00:00:00 2001 From: nircoe Date: Fri, 16 Jan 2026 13:40:59 +0200 Subject: [PATCH 5/5] Modify sphere_renderer to intersection not alpha --- assets/shaders/sphere_renderer.frag | 47 ++++++++++++------- assets/shaders/sphere_renderer.vert | 9 ++-- .../entity/renderer/shape_renderer.cpp | 9 +++- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/assets/shaders/sphere_renderer.frag b/assets/shaders/sphere_renderer.frag index 80f6822..05bd522 100644 --- a/assets/shaders/sphere_renderer.frag +++ b/assets/shaders/sphere_renderer.frag @@ -1,10 +1,11 @@ #if __VERSION__ >= 330 -in vec3 localPos; +in vec3 worldPos; out vec4 FragColor; #else -varying vec3 localPos; +varying vec3 worldPos; #endif +uniform mat4 model; uniform vec4 color; #if GAMECOE_HAS_UBO layout(std140) uniform CameraMatrices @@ -18,43 +19,55 @@ uniform mat4 view; uniform mat4 projection; uniform vec3 cameraPosition; #endif +uniform vec3 sphereCenter; +uniform vec3 sphereScale; +uniform mat3 sphereRotation; -float sphereAlpha(vec3 rayOrigin, vec3 lPos) +vec3 sphereIntersection(vec3 rayOrigin, vec3 wPos) { - // Sphere center at (0, 0, 0) const float RADIUS = 1.0; - const float MULTIPLIER = 1.75; // Box is -0.5 to 0.5, scale to radius 1.0 + const float BOX_RADIUS = 0.5; - vec3 samplePos = lPos * MULTIPLIER; - vec3 rayDirection = vec3(normalize(samplePos - rayOrigin)); + mat3 sphereRotationT = transpose(sphereRotation); + + vec3 effectiveScale = sphereScale * BOX_RADIUS; + vec3 rayDirection = vec3(sphereRotationT * normalize(wPos - rayOrigin)) / effectiveScale; + vec3 sphereCenterToRayOrigin = (sphereRotationT * vec3(rayOrigin - sphereCenter)) / effectiveScale; float a = dot(rayDirection, rayDirection); - float b = 2.0 * dot(rayOrigin, rayDirection); - float c = dot(rayOrigin, rayOrigin) - (RADIUS * RADIUS); + float b = 2.0 * dot(sphereCenterToRayOrigin, rayDirection); + float c = dot(sphereCenterToRayOrigin, sphereCenterToRayOrigin) - (RADIUS * RADIUS); float discriminant = b * b - 4.0 * a * c; - return (discriminant >= 0.0) ? 1.0 : 0.0; - /* if (discriminant < 0.0) { - return 0.0; + return vec3(0.0); } float t1 = (-b + sqrt(discriminant)) / (2.0 * a); float t2 = (-b - sqrt(discriminant)) / (2.0 * a); float t = t2 > 0.0 ? t2 : t1; - vec3 intersection = rayOrigin + vec3(t * rayDirection); - */ + vec3 intersection = rayOrigin + (sphereRotation * (vec3(t * rayDirection) * effectiveScale)); + + return intersection; } void main() { - float alpha = sphereAlpha(cameraPosition, localPos); + vec3 spherePoint = sphereIntersection(cameraPosition, worldPos); + if (spherePoint == vec3(0.0)) + { + discard; + } + + vec4 shadingPos = projection * view * model * vec4(spherePoint, 1.0); + shadingPos /= shadingPos.w; + gl_FragDepth = shadingPos.z; // need version gating? #if __VERSION__ >= 330 - FragColor = vec4(color.rgb, color.a * alpha); + FragColor = color; #else - gl_FragColor = vec4(color.rgb, color.a * alpha); + gl_FragColor = color; #endif } \ No newline at end of file diff --git a/assets/shaders/sphere_renderer.vert b/assets/shaders/sphere_renderer.vert index 950331f..6f5da86 100644 --- a/assets/shaders/sphere_renderer.vert +++ b/assets/shaders/sphere_renderer.vert @@ -1,9 +1,9 @@ #if __VERSION__ >= 330 layout (location = 0) in vec3 aPos; -out vec3 localPos; +out vec3 worldPos; #else attribute vec3 aPos; -varying vec3 localPos; +varying vec3 worldPos; #endif uniform mat4 model; @@ -22,6 +22,7 @@ uniform vec3 cameraPosition; void main() { - localPos = aPos; - gl_Position = projection * view * model * vec4(aPos, 1.0); + vec4 wPos = model * vec4(aPos, 1.0); + worldPos = vec3(wPos); + gl_Position = projection * view * wPos; } diff --git a/src/gamecoe/entity/renderer/shape_renderer.cpp b/src/gamecoe/entity/renderer/shape_renderer.cpp index bc8998d..e80c906 100644 --- a/src/gamecoe/entity/renderer/shape_renderer.cpp +++ b/src/gamecoe/entity/renderer/shape_renderer.cpp @@ -116,8 +116,15 @@ namespace gamecoe shader->set("projection", camera.projectionMatrix()); shader->set("cameraPosition", camera.owner().transform().position()); #endif - shader->set("model", owner().transform().modelMatrix()); + auto &transform = owner().transform(); + shader->set("model", transform.modelMatrix()); shader->set("color", m_color.normalized()); + if(m_shape == Shape::Sphere) + { + shader->set("sphereCenter", transform.position()); + shader->set("sphereScale", transform.scale()); + shader->set("sphereRotation", glm::mat3(transform.rotationMatrix())); // how should I handle it mat3-mat4? maybe change to mat4 in the frag shader? + } m_vertexArray.bind();