From 900d19a41bc1886e7a809d99d6119b12235a4f0a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 20 Jul 2024 10:57:17 +0100 Subject: Initial commit of basic shadow depth map creation --- game/scenary/foliage.cpp | 3 +++ game/scenary/foliage.h | 2 ++ gfx/gl/shaders/shadowStencil.fs | 0 gfx/gl/shaders/shadowStencil.vs | 11 +++++++++ gfx/gl/shadowStenciller.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ gfx/gl/shadowStenciller.h | 21 +++++++++++++++++ 6 files changed, 88 insertions(+) create mode 100644 gfx/gl/shaders/shadowStencil.fs create mode 100644 gfx/gl/shaders/shadowStencil.vs create mode 100644 gfx/gl/shadowStenciller.cpp create mode 100644 gfx/gl/shadowStenciller.h diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 73d285f..870adb0 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -17,6 +17,9 @@ Foliage::postLoad() texture = getTexture(); bodyMesh->configureVAO(instanceVAO) .addAttribs(instances.bufferName(), 1); + ShadowStenciller ss; + ss.renderStencil(shadowStencil, *bodyMesh, {-4000, -4000, 0}, {4000, 4000, 8000}); + Texture::saveDepth(shadowStencil, std::format("/tmp/stencil-{}.tga", id).c_str()); } void diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 0a4261c..5367d44 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -2,6 +2,7 @@ #include "assetFactory/asset.h" #include "gfx/gl/instanceVertices.h" +#include "gfx/gl/shadowStenciller.h" #include "gfx/models/texture.h" #include "gfx/renderable.h" @@ -19,6 +20,7 @@ public: mutable InstanceVertices instances; void render(const SceneShader &) const override; void shadows(const ShadowMapper &) const override; + glTexture shadowStencil = ShadowStenciller::createStencilTexture(256, 256); protected: friend Persistence::SelectionPtrBase>; diff --git a/gfx/gl/shaders/shadowStencil.fs b/gfx/gl/shaders/shadowStencil.fs new file mode 100644 index 0000000..e69de29 diff --git a/gfx/gl/shaders/shadowStencil.vs b/gfx/gl/shaders/shadowStencil.vs new file mode 100644 index 0000000..4f4c250 --- /dev/null +++ b/gfx/gl/shaders/shadowStencil.vs @@ -0,0 +1,11 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +include(`meshIn.glsl') +uniform mat4 viewProjection; + +void +main() +{ + gl_Position = viewProjection * vec4(position, 1); +} diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp new file mode 100644 index 0000000..6d5fa40 --- /dev/null +++ b/gfx/gl/shadowStenciller.cpp @@ -0,0 +1,51 @@ +#include "shadowStenciller.h" +#include "config/types.h" +#include "gfx/gl/program.h" +#include "gfx/gl/shaders/vs-shadowStencil.h" +#include "gfx/models/mesh.h" +#include "glArrays.h" +#include "gl_traits.h" +#include "maths.h" +#include + +ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs} +{ + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +glTexture +ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) +{ + glTexture stencil; + glBindTexture(GL_TEXTURE_2D, stencil); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr); + + return stencil; +} + +void +ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh, const RelativePosition3D & mins, + const RelativePosition3D & maxs) const +{ + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, stencil, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + throw std::runtime_error("Stencil framebuffer not complete!"); + } + glUseProgram(shadowCaster); + glClear(GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, 256, 256); + glEnable(GL_DEPTH_TEST); + const auto extents = glm::ortho(mins.x, maxs.x, mins.z, maxs.z, mins.y, maxs.y); + const auto lightDir = glm::lookAt({}, north, up); + glUniform(viewProjectionLoc, extents * lightDir); + mesh.Draw(); +} diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h new file mode 100644 index 0000000..460fa68 --- /dev/null +++ b/gfx/gl/shadowStenciller.h @@ -0,0 +1,21 @@ +#pragma once + +#include "config/types.h" +#include "gfx/gl/program.h" +#include "gfx/models/mesh.h" +#include "glArrays.h" + +class ShadowStenciller { +public: + ShadowStenciller(); + + [[nodiscard]] + static glTexture createStencilTexture(GLsizei width, GLsizei height); + void renderStencil(const glTexture &, const MeshBase &, const RelativePosition3D & mins, + const RelativePosition3D & maxs) const; + +private: + glFrameBuffer fbo; + Program shadowCaster; + Program::UniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; +}; -- cgit v1.2.3 From 4102debac6fc9bcc58091ead007dbce47b42c712 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 20 Jul 2024 12:19:12 +0100 Subject: Calculate and store the extents of a mesh --- gfx/models/mesh.cpp | 5 ++++- gfx/models/mesh.h | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp index e7474ca..1b6ecda 100644 --- a/gfx/models/mesh.cpp +++ b/gfx/models/mesh.cpp @@ -1,6 +1,9 @@ #include "mesh.h" -MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode) : m_numIndices {m_numIndices}, mode {mode} { } +MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode, std::pair minmax) : + m_numIndices {m_numIndices}, mode {mode}, min {minmax.first}, max {minmax.second} +{ +} void MeshBase::Draw() const diff --git a/gfx/models/mesh.h b/gfx/models/mesh.h index 248cb8f..f6a1bd2 100644 --- a/gfx/models/mesh.h +++ b/gfx/models/mesh.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "gfx/gl/vertexArrayObject.h" #include #include @@ -13,19 +14,32 @@ public: void Draw() const; void DrawInstanced(GLuint vao, GLsizei count, GLuint base = 0) const; + auto + minExtent() const + { + return min; + } + + auto + maxExtent() const + { + return max; + } + protected: - MeshBase(GLsizei m_numIndices, GLenum mode); + MeshBase(GLsizei m_numIndices, GLenum mode, std::pair minmax); glVertexArray m_vertexArrayObject; glBuffers<2> m_vertexArrayBuffers; GLsizei m_numIndices; GLenum mode; + RelativePosition3D min, max; }; template class MeshT : public MeshBase, public ConstTypeDefs> { public: MeshT(const std::span vertices, const std::span indices, GLenum mode = GL_TRIANGLES) : - MeshBase {static_cast(indices.size()), mode} + MeshBase {static_cast(indices.size()), mode, extent(vertices)} { VertexArrayObject::data(vertices, m_vertexArrayBuffers[0], GL_ARRAY_BUFFER); VertexArrayObject::data(indices, m_vertexArrayBuffers[1], GL_ARRAY_BUFFER); @@ -37,6 +51,21 @@ public: { return vao.addAttribsFor(m_vertexArrayBuffers[0]).addIndices(m_vertexArrayBuffers[1]); } + + static auto + extent(const std::span vertices) + { + std::pair out {}; + for (glm::length_t D {}; D < 3; ++D) { + const auto mm + = std::minmax_element(vertices.begin(), vertices.end(), [D](const auto & va, const auto & vb) { + return va.pos[D] < vb.pos[D]; + }); + out.first[D] = mm.first->pos[D]; + out.second[D] = mm.second->pos[D]; + } + return out; + } }; using Mesh = MeshT; -- cgit v1.2.3 From 4ba67f34eac848e43bad2ccc4b5c09ac65dd7952 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 20 Jul 2024 12:55:15 +0100 Subject: Use mesh extents for shadow stencil extents --- game/scenary/foliage.cpp | 2 +- gfx/gl/shadowStenciller.cpp | 5 +++-- gfx/gl/shadowStenciller.h | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 870adb0..24caeb7 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -18,7 +18,7 @@ Foliage::postLoad() bodyMesh->configureVAO(instanceVAO) .addAttribs(instances.bufferName(), 1); ShadowStenciller ss; - ss.renderStencil(shadowStencil, *bodyMesh, {-4000, -4000, 0}, {4000, 4000, 8000}); + ss.renderStencil(shadowStencil, *bodyMesh); Texture::saveDepth(shadowStencil, std::format("/tmp/stencil-{}.tga", id).c_str()); } diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 6d5fa40..e20eda1 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -32,8 +32,7 @@ ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) } void -ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh, const RelativePosition3D & mins, - const RelativePosition3D & maxs) const +ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh) const { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, stencil, 0); @@ -44,6 +43,8 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, 256, 256); glEnable(GL_DEPTH_TEST); + const auto & mins = mesh.minExtent(); + const auto & maxs = mesh.maxExtent(); const auto extents = glm::ortho(mins.x, maxs.x, mins.z, maxs.z, mins.y, maxs.y); const auto lightDir = glm::lookAt({}, north, up); glUniform(viewProjectionLoc, extents * lightDir); diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 460fa68..5a22a7e 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -11,8 +11,7 @@ public: [[nodiscard]] static glTexture createStencilTexture(GLsizei width, GLsizei height); - void renderStencil(const glTexture &, const MeshBase &, const RelativePosition3D & mins, - const RelativePosition3D & maxs) const; + void renderStencil(const glTexture &, const MeshBase &) const; private: glFrameBuffer fbo; -- cgit v1.2.3 From f737aada2b7164683303beb3bb490c30a4949fb0 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 21 Jul 2024 02:33:24 +0100 Subject: Use texture alpha in shadow stencil --- game/scenary/foliage.cpp | 2 +- gfx/gl/shaders/shadowStencil.fs | 16 ++++++++++++++++ gfx/gl/shaders/shadowStencil.vs | 7 +++++++ gfx/gl/shadowStenciller.cpp | 8 ++++++-- gfx/gl/shadowStenciller.h | 4 ++-- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 24caeb7..ba1b37e 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -18,7 +18,7 @@ Foliage::postLoad() bodyMesh->configureVAO(instanceVAO) .addAttribs(instances.bufferName(), 1); ShadowStenciller ss; - ss.renderStencil(shadowStencil, *bodyMesh); + ss.renderStencil(shadowStencil, *bodyMesh, texture); Texture::saveDepth(shadowStencil, std::format("/tmp/stencil-{}.tga", id).c_str()); } diff --git a/gfx/gl/shaders/shadowStencil.fs b/gfx/gl/shaders/shadowStencil.fs index e69de29..f149c23 100644 --- a/gfx/gl/shaders/shadowStencil.fs +++ b/gfx/gl/shaders/shadowStencil.fs @@ -0,0 +1,16 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +layout(binding = 0) uniform sampler2D textureAlbedo; + +include(`materialInterface.glsl') +include(`materialCommon.glsl') + +void +main() +{ + if (getTextureColour(Material, TexCoords).a < 0.5) { + discard; + } + gl_FragDepth = gl_FragCoord.z; +} diff --git a/gfx/gl/shaders/shadowStencil.vs b/gfx/gl/shaders/shadowStencil.vs index 4f4c250..45a0867 100644 --- a/gfx/gl/shaders/shadowStencil.vs +++ b/gfx/gl/shaders/shadowStencil.vs @@ -1,11 +1,18 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable +layout(binding = 1) uniform usampler2DRect materialData; + include(`meshIn.glsl') +include(`materialInterface.glsl') +include(`getMaterialDetail.glsl') uniform mat4 viewProjection; void main() { + TexCoords = texCoord; + Material = getMaterialDetail(material); + gl_Position = viewProjection * vec4(position, 1); } diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index e20eda1..2ba519f 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -1,6 +1,7 @@ #include "shadowStenciller.h" #include "config/types.h" #include "gfx/gl/program.h" +#include "gfx/gl/shaders/fs-shadowStencil.h" #include "gfx/gl/shaders/vs-shadowStencil.h" #include "gfx/models/mesh.h" #include "glArrays.h" @@ -8,7 +9,7 @@ #include "maths.h" #include -ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs} +ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_fs} { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDrawBuffer(GL_NONE); @@ -32,13 +33,16 @@ ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) } void -ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh) const +ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh, const Texture::AnyPtr texture) const { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, stencil, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { throw std::runtime_error("Stencil framebuffer not complete!"); } + if (texture) { + texture->bind(); + } glUseProgram(shadowCaster); glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, 256, 256); diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 5a22a7e..bf6d204 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -1,8 +1,8 @@ #pragma once -#include "config/types.h" #include "gfx/gl/program.h" #include "gfx/models/mesh.h" +#include "gfx/models/texture.h" #include "glArrays.h" class ShadowStenciller { @@ -11,7 +11,7 @@ public: [[nodiscard]] static glTexture createStencilTexture(GLsizei width, GLsizei height); - void renderStencil(const glTexture &, const MeshBase &) const; + void renderStencil(const glTexture &, const MeshBase &, const Texture::AnyPtr texture) const; private: glFrameBuffer fbo; -- cgit v1.2.3 From 064864eac61e936af909470fcccc5c67ef6d3169 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 11 Aug 2024 19:32:23 +0100 Subject: Calculate centre and size of mesh, wrap it all in a Dimensions object --- gfx/gl/shadowStenciller.cpp | 4 ++-- gfx/models/mesh.cpp | 27 ++++++++++++++++++++++-- gfx/models/mesh.h | 51 +++++++++++++++++++++------------------------ 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 2ba519f..dc87d76 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -47,8 +47,8 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, 256, 256); glEnable(GL_DEPTH_TEST); - const auto & mins = mesh.minExtent(); - const auto & maxs = mesh.maxExtent(); + const auto & mins = mesh.getDimensions().minExtent; + const auto & maxs = mesh.getDimensions().maxExtent; const auto extents = glm::ortho(mins.x, maxs.x, mins.z, maxs.z, mins.y, maxs.y); const auto lightDir = glm::lookAt({}, north, up); glUniform(viewProjectionLoc, extents * lightDir); diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp index 1b6ecda..2eae160 100644 --- a/gfx/models/mesh.cpp +++ b/gfx/models/mesh.cpp @@ -1,10 +1,33 @@ #include "mesh.h" -MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode, std::pair minmax) : - m_numIndices {m_numIndices}, mode {mode}, min {minmax.first}, max {minmax.second} +MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode, const std::vector & positions) : + m_numIndices {m_numIndices}, mode {mode}, dimensions {positions} { } +MeshBase::Dimensions::Dimensions(const std::span positions) : + Dimensions {positions, {extents(positions, 0), extents(positions, 1), extents(positions, 2)}} +{ +} + +MeshBase::Dimensions::Dimensions( + const std::span positions, const std::array & extents1ds) : + minExtent(extents1ds[0].min, extents1ds[1].min, extents1ds[2].min), + maxExtent(extents1ds[0].max, extents1ds[1].max, extents1ds[2].max), centre {(minExtent + maxExtent) / 2.0F}, + size {std::ranges::max(positions | std::views::transform([this](const auto & v) { + return glm::distance(v, centre); + }))} +{ +} + +MeshBase::Dimensions::Extents1D +MeshBase::Dimensions::extents(const std::span positions, glm::length_t D) +{ + return std::ranges::minmax(positions | std::views::transform([D](const auto & v) { + return v[D]; + })); +} + void MeshBase::Draw() const { diff --git a/gfx/models/mesh.h b/gfx/models/mesh.h index f6a1bd2..8791aed 100644 --- a/gfx/models/mesh.h +++ b/gfx/models/mesh.h @@ -4,6 +4,7 @@ #include "gfx/gl/vertexArrayObject.h" #include #include +#include #include #include @@ -11,35 +12,46 @@ class Vertex; class MeshBase { public: + class Dimensions { + public: + using Extents1D = std::ranges::minmax_result; + explicit Dimensions(const std::span); + + RelativePosition3D minExtent, maxExtent; + RelativePosition3D centre; + RelativeDistance size; + + private: + Dimensions(const std::span, const std::array &); + static Extents1D extents(const std::span, glm::length_t D); + }; + void Draw() const; void DrawInstanced(GLuint vao, GLsizei count, GLuint base = 0) const; - auto - minExtent() const + [[nodiscard]] const Dimensions & + getDimensions() const { - return min; - } - - auto - maxExtent() const - { - return max; + return dimensions; } protected: - MeshBase(GLsizei m_numIndices, GLenum mode, std::pair minmax); + MeshBase(GLsizei m_numIndices, GLenum mode, const std::vector &); glVertexArray m_vertexArrayObject; glBuffers<2> m_vertexArrayBuffers; GLsizei m_numIndices; GLenum mode; - RelativePosition3D min, max; + Dimensions dimensions; }; template class MeshT : public MeshBase, public ConstTypeDefs> { public: MeshT(const std::span vertices, const std::span indices, GLenum mode = GL_TRIANGLES) : - MeshBase {static_cast(indices.size()), mode, extent(vertices)} + MeshBase {static_cast(indices.size()), mode, + materializeRange(vertices | std::views::transform([](const auto & v) { + return static_cast(v.pos); + }))} { VertexArrayObject::data(vertices, m_vertexArrayBuffers[0], GL_ARRAY_BUFFER); VertexArrayObject::data(indices, m_vertexArrayBuffers[1], GL_ARRAY_BUFFER); @@ -51,21 +63,6 @@ public: { return vao.addAttribsFor(m_vertexArrayBuffers[0]).addIndices(m_vertexArrayBuffers[1]); } - - static auto - extent(const std::span vertices) - { - std::pair out {}; - for (glm::length_t D {}; D < 3; ++D) { - const auto mm - = std::minmax_element(vertices.begin(), vertices.end(), [D](const auto & va, const auto & vb) { - return va.pos[D] < vb.pos[D]; - }); - out.first[D] = mm.first->pos[D]; - out.second[D] = mm.second->pos[D]; - } - return out; - } }; using Mesh = MeshT; -- cgit v1.2.3 From c9e55e44bf4e50e7737195886df2ea34ce799690 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 18 Aug 2024 12:54:05 +0100 Subject: Replace low poly plants with the double sided version Avoids culling half the trees --- res/shapespark-low-poly-plants-kit.fbx | Bin 20264540 -> 20407788 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/res/shapespark-low-poly-plants-kit.fbx b/res/shapespark-low-poly-plants-kit.fbx index fe87c0c..7457adb 100644 Binary files a/res/shapespark-low-poly-plants-kit.fbx and b/res/shapespark-low-poly-plants-kit.fbx differ -- cgit v1.2.3 From 87ebf7a7587e832d922635021a32c887823d92c7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 18 Aug 2024 13:11:46 +0100 Subject: Offset shaded position to reduce chance of self-shadowing --- gfx/gl/shaders/directionalLight.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/gl/shaders/directionalLight.fs b/gfx/gl/shaders/directionalLight.fs index 24457b8..86447ec 100644 --- a/gfx/gl/shaders/directionalLight.fs +++ b/gfx/gl/shaders/directionalLight.fs @@ -34,10 +34,10 @@ isShaded(vec4 Position) const float inside = insideShadowCube(PositionInLightSpace); if (inside > 0) { const float lightSpaceDepth = texture(shadowMap, vec3(PositionInLightSpace.xy, m)).r; - return step(lightSpaceDepth, PositionInLightSpace.z); + return step(PositionInLightSpace.z, lightSpaceDepth + 0.001); } } - return 0; + return 1; } void @@ -46,5 +46,5 @@ main() const vec4 Position = vec4(texture(gPosition, TexCoords).xyz - lightPoint, 1); const vec3 Normal = texture(gNormal, TexCoords).rgb; const float shaded = isShaded(Position); - FragColor = (1 - shaded) * max(dot(-lightDirection, Normal) * lightColour, 0); + FragColor = shaded * max(dot(-lightDirection, Normal) * lightColour, 0); } -- cgit v1.2.3 From 1bbbdfe0d9e9e7a4e42241a2eb596b46ac02c65b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 18 Aug 2024 16:05:05 +0100 Subject: Populate GameState::assets in appropriate tests --- test/test-assetFactory.cpp | 3 +++ test/testRenderOutput.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 1c2c417..0b5b278 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -97,6 +97,7 @@ BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) { auto mf = AssetFactory::loadXML(RESDIR "/brush47.xml"); BOOST_REQUIRE(mf); + gameState.assets = mf->assets; BOOST_REQUIRE_GE(mf->shapes.size(), 6); BOOST_CHECK(mf->shapes.at("plane")); BOOST_CHECK(mf->shapes.at("cylinder")); @@ -126,6 +127,7 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) { auto mf = AssetFactory::loadXML(RESDIR "/foliage.xml"); BOOST_REQUIRE(mf); + gameState.assets = mf->assets; auto tree_01_1 = mf->assets.at("Tree-01-1"); BOOST_REQUIRE(tree_01_1); auto tree_01_1_f = std::dynamic_pointer_cast(tree_01_1); @@ -144,6 +146,7 @@ BOOST_AUTO_TEST_CASE(lights, *boost::unit_test::timeout(5)) { auto mf = AssetFactory::loadXML(RESDIR "/lights.xml"); BOOST_REQUIRE(mf); + gameState.assets = mf->assets; auto rlight = mf->assets.at("r-light"); BOOST_REQUIRE(rlight); auto oldlamp = mf->assets.at("old-lamp"); diff --git a/test/testRenderOutput.h b/test/testRenderOutput.h index 056d029..79908b1 100644 --- a/test/testRenderOutput.h +++ b/test/testRenderOutput.h @@ -1,6 +1,7 @@ #pragma once #include "config/types.h" +#include "game/gamestate.h" #include "glArrays.h" #include #include @@ -17,6 +18,7 @@ public: glFrameBuffer output; glRenderBuffer depth; glTexture outImage; + GameState gameState; }; template class TestRenderOutputSize : public TestRenderOutput { -- cgit v1.2.3 From 0b8b0af99ed1ac00fc2ae78beb0fe6f9f24582fb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 18 Aug 2024 16:11:39 +0100 Subject: Add updateStencil to Renderable interface --- gfx/renderable.cpp | 5 +++++ gfx/renderable.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp index 0340189..3594968 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -9,3 +9,8 @@ void Renderable::shadows(const ShadowMapper &) const { } + +void +Renderable::updateStencil(const ShadowStenciller &) const +{ +} diff --git a/gfx/renderable.h b/gfx/renderable.h index e126fff..83522e3 100644 --- a/gfx/renderable.h +++ b/gfx/renderable.h @@ -4,6 +4,7 @@ class SceneShader; class ShadowMapper; +class ShadowStenciller; class Renderable { public: @@ -14,4 +15,6 @@ public: virtual void render(const SceneShader & shader) const = 0; virtual void lights(const SceneShader & shader) const; virtual void shadows(const ShadowMapper & shadowMapper) const; + + virtual void updateStencil(const ShadowStenciller & lightDir) const; }; -- cgit v1.2.3 From 172beac34e82c86f8c16b8a1be5fca9d7ccfc0d1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 18 Aug 2024 16:14:29 +0100 Subject: Update asset stencils from shadow mapper --- game/scenary/foliage.cpp | 13 +++++++++---- game/scenary/foliage.h | 1 + gfx/gl/shadowMapper.cpp | 9 +++++++++ gfx/gl/shadowStenciller.cpp | 15 +++++++-------- gfx/gl/shadowStenciller.h | 3 ++- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index ba1b37e..13d2f3b 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -3,7 +3,6 @@ #include "gfx/gl/shadowMapper.h" #include "gfx/gl/vertexArrayObject.h" #include "gfx/models/texture.h" -#include "location.h" bool Foliage::persist(Persistence::PersistenceStore & store) @@ -17,9 +16,15 @@ Foliage::postLoad() texture = getTexture(); bodyMesh->configureVAO(instanceVAO) .addAttribs(instances.bufferName(), 1); - ShadowStenciller ss; - ss.renderStencil(shadowStencil, *bodyMesh, texture); - Texture::saveDepth(shadowStencil, std::format("/tmp/stencil-{}.tga", id).c_str()); +} + +void +Foliage::updateStencil(const ShadowStenciller & ss) const +{ + if (instances.size() > 0) { + ss.renderStencil(shadowStencil, *bodyMesh, texture); + Texture::saveDepth(shadowStencil, std::format("/tmp/stencil-{}.tga", id).c_str()); + } } void diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 5367d44..fa6c63b 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -20,6 +20,7 @@ public: mutable InstanceVertices instances; void render(const SceneShader &) const override; void shadows(const ShadowMapper &) const override; + void updateStencil(const ShadowStenciller &) const override; glTexture shadowStencil = ShadowStenciller::createStencilTexture(256, 256); protected: diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index a846a3d..9b9e404 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -1,6 +1,7 @@ #include "shadowMapper.h" #include "camera.h" #include "collections.h" +#include "game/gamestate.h" #include "gfx/gl/shaders/fs-shadowDynamicPointInstWithTextures.h" #include "gfx/gl/shaders/gs-commonShadowPoint.h" #include "gfx/gl/shaders/gs-shadowDynamicPointInstWithTextures.h" @@ -8,6 +9,8 @@ #include "gfx/gl/shaders/vs-shadowDynamicPointInst.h" #include "gfx/gl/shaders/vs-shadowDynamicPointInstWithTextures.h" #include "gfx/gl/shaders/vs-shadowLandmass.h" +#include "gfx/gl/shadowStenciller.h" +#include "gfx/renderable.h" #include "gl_traits.h" #include "location.h" #include "maths.h" @@ -74,6 +77,12 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV ShadowMapper::Definitions ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const Camera & camera) const { + ShadowStenciller shadowStenciller {dir, up}; + for (const auto & [id, asset] : gameState->assets) { + if (const auto r = std::dynamic_pointer_cast(asset)) { + r->updateStencil(shadowStenciller); + } + } glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glClear(GL_DEPTH_BUFFER_BIT); glCullFace(GL_FRONT); diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index dc87d76..9f13808 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -1,15 +1,14 @@ #include "shadowStenciller.h" -#include "config/types.h" #include "gfx/gl/program.h" #include "gfx/gl/shaders/fs-shadowStencil.h" #include "gfx/gl/shaders/vs-shadowStencil.h" #include "gfx/models/mesh.h" #include "glArrays.h" #include "gl_traits.h" -#include "maths.h" #include -ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_fs} +ShadowStenciller::ShadowStenciller(const Direction3D & lightDir, const Direction3D & lightDirUp) : + shadowCaster {shadowStencil_vs, shadowStencil_fs}, lightDirMat {glm::lookAt(-lightDir, {}, lightDirUp)} { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDrawBuffer(GL_NONE); @@ -47,10 +46,10 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, 256, 256); glEnable(GL_DEPTH_TEST); - const auto & mins = mesh.getDimensions().minExtent; - const auto & maxs = mesh.getDimensions().maxExtent; - const auto extents = glm::ortho(mins.x, maxs.x, mins.z, maxs.z, mins.y, maxs.y); - const auto lightDir = glm::lookAt({}, north, up); - glUniform(viewProjectionLoc, extents * lightDir); + const auto & centre = mesh.getDimensions().centre; + const auto & size = mesh.getDimensions().size; + const auto extentsMat + = glm::translate(glm::ortho(-size, size, -size, size, -size, size), {-centre.x, -centre.z, -centre.y}); + glUniform(viewProjectionLoc, extentsMat * lightDirMat); mesh.Draw(); } diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index bf6d204..87dc044 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -7,7 +7,7 @@ class ShadowStenciller { public: - ShadowStenciller(); + ShadowStenciller(const Direction3D & lightDir, const Direction3D & lightDirUp); [[nodiscard]] static glTexture createStencilTexture(GLsizei width, GLsizei height); @@ -16,5 +16,6 @@ public: private: glFrameBuffer fbo; Program shadowCaster; + glm::mat4 lightDirMat; Program::UniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; }; -- cgit v1.2.3 From 08c9a8ea438f25ae8012d80d2c2c74c799f5543c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 19 Aug 2024 23:07:12 +0100 Subject: Shuffle some GL state setting Ensures the right things are set at the right times, it's more calls but its less prone to randomly getting screwed over. Also updates the comments about which phases do what. --- gfx/gl/sceneRenderer.cpp | 20 ++++++++++++++++---- gfx/gl/shadowMapper.cpp | 5 ++++- gfx/gl/shadowStenciller.cpp | 1 - 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index e0938f2..7aace49 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -62,7 +62,7 @@ SceneRenderer::render(const SceneProvider & scene) const shader.setViewProjection(camera.getPosition(), camera.getViewProjection()); glViewport(0, 0, size.x, size.y); - // Geometry pass + // Geometry/colour pass - writes albedo, normal and position textures glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); @@ -73,7 +73,13 @@ SceneRenderer::render(const SceneProvider & scene) const glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); scene.content(shader); - // Illumination pass + // Environment pass - + // * ambient - clears illumination texture - see setAmbientLight + // * directional - updates shadowMapper, reads normal and position, writes illumination - see setDirectionalLight + scene.environment(shader, *this); + + // Scene lights pass - + // * per light - reads normal and position, writes illumination glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); glBlendFunc(GL_ONE, GL_ONE); glActiveTexture(GL_TEXTURE0); @@ -82,11 +88,10 @@ SceneRenderer::render(const SceneProvider & scene) const glBindTexture(GL_TEXTURE_2D, gNormal); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMapper); - scene.environment(shader, *this); glDisable(GL_DEPTH_TEST); scene.lights(shader); - // Lighting pass + // Composition pass - reads albedo and illumination, writes output glBindFramebuffer(GL_FRAMEBUFFER, output); glViewport(0, 0, size.x, size.y); glCullFace(GL_BACK); @@ -114,6 +119,13 @@ SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direc if (colour.r > 0 || colour.g > 0 || colour.b > 0) { const auto lvp = shadowMapper.update(scene, direction, camera); glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); + glBlendFunc(GL_ONE, GL_ONE); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, gPosition); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, gNormal); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMapper); glViewport(0, 0, size.x, size.y); dirLight.use(); dirLight.setDirectionalLight(colour, direction, camera.getPosition(), lvp); diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 9b9e404..ff0634e 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -77,15 +77,18 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV ShadowMapper::Definitions ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const Camera & camera) const { + glCullFace(GL_FRONT); + glEnable(GL_DEPTH_TEST); + ShadowStenciller shadowStenciller {dir, up}; for (const auto & [id, asset] : gameState->assets) { if (const auto r = std::dynamic_pointer_cast(asset)) { r->updateStencil(shadowStenciller); } } + glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glClear(GL_DEPTH_BUFFER_BIT); - glCullFace(GL_FRONT); glViewport(0, 0, size.x, size.y); const auto lightViewDir = glm::lookAt({}, dir, up); diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 9f13808..fc3d77c 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -45,7 +45,6 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh glUseProgram(shadowCaster); glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, 256, 256); - glEnable(GL_DEPTH_TEST); const auto & centre = mesh.getDimensions().centre; const auto & size = mesh.getDimensions().size; const auto extentsMat -- cgit v1.2.3 From dd452f3e9238be954c3ecd325ed11e97a50ec1c3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 19 Aug 2024 23:26:32 +0100 Subject: Persist a single ShadowStenciller within ShadowMapper --- gfx/gl/shadowMapper.cpp | 2 +- gfx/gl/shadowMapper.h | 2 ++ gfx/gl/shadowStenciller.cpp | 9 +++++++-- gfx/gl/shadowStenciller.h | 6 ++++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index ff0634e..d9dd24f 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -80,7 +80,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glCullFace(GL_FRONT); glEnable(GL_DEPTH_TEST); - ShadowStenciller shadowStenciller {dir, up}; + shadowStenciller.setLightDirection(dir, up); for (const auto & [id, asset] : gameState->assets) { if (const auto r = std::dynamic_pointer_cast(asset)) { r->updateStencil(shadowStenciller); diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index 73dadd0..280a0cd 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -1,6 +1,7 @@ #pragma once #include "config/types.h" +#include "gfx/gl/shadowStenciller.h" #include "lib/glArrays.h" #include "program.h" #include @@ -61,4 +62,5 @@ private: glFrameBuffer depthMapFBO; glTexture depthMap; TextureAbsCoord size; + mutable ShadowStenciller shadowStenciller; }; diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index fc3d77c..ac63b4e 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -7,8 +7,7 @@ #include "gl_traits.h" #include -ShadowStenciller::ShadowStenciller(const Direction3D & lightDir, const Direction3D & lightDirUp) : - shadowCaster {shadowStencil_vs, shadowStencil_fs}, lightDirMat {glm::lookAt(-lightDir, {}, lightDirUp)} +ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_fs} { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDrawBuffer(GL_NONE); @@ -16,6 +15,12 @@ ShadowStenciller::ShadowStenciller(const Direction3D & lightDir, const Direction glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void +ShadowStenciller::setLightDirection(const Direction3D & lightDir, const Direction3D & lightDirUp) +{ + lightDirMat = glm::lookAt(-lightDir, {}, lightDirUp); +} + glTexture ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) { diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 87dc044..009285c 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -7,15 +7,17 @@ class ShadowStenciller { public: - ShadowStenciller(const Direction3D & lightDir, const Direction3D & lightDirUp); + ShadowStenciller(); [[nodiscard]] static glTexture createStencilTexture(GLsizei width, GLsizei height); + void setLightDirection(const Direction3D & lightDir, const Direction3D & lightDirUp); void renderStencil(const glTexture &, const MeshBase &, const Texture::AnyPtr texture) const; private: glFrameBuffer fbo; Program shadowCaster; - glm::mat4 lightDirMat; Program::UniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; + + glm::mat4 lightDirMat {}; }; -- cgit v1.2.3 From f03e11fb38701f278f3c0f465958932044227830 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 26 Aug 2024 13:34:06 +0100 Subject: test-render loads all assets into gameState --- test/test-render.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/test-render.cpp b/test/test-render.cpp index b9a809e..bb5a137 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -25,10 +26,8 @@ #include class TestScene : public SceneProvider { - const RailVehicleClassPtr brush47rvc = std::dynamic_pointer_cast( - AssetFactory::loadXML(RESDIR "/brush47.xml")->assets.at("brush-47")); - const std::shared_ptr tree021f - = std::dynamic_pointer_cast(AssetFactory::loadXML(RESDIR "/foliage.xml")->assets.at("Tree-02-1")); + RailVehicleClassPtr brush47rvc; + std::shared_ptr tree021f; std::shared_ptr train1, train2; std::shared_ptr plant1; RailLinks rail; @@ -40,6 +39,9 @@ class TestScene : public SceneProvider { public: TestScene() { + gameState->assets = AssetFactory::loadAll(RESDIR); + brush47rvc = std::dynamic_pointer_cast(gameState->assets.at("brush-47")); + tree021f = std::dynamic_pointer_cast(gameState->assets.at("Tree-02-1")); train1 = std::make_shared(brush47rvc); train1->location.setPosition({52000, 50000, 2000}); train1->bogies.front().setPosition(train1->bogies.front().position() + train1->location.position()); -- cgit v1.2.3 From c493369c5686fdd66175024444aca196cff54502 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 26 Aug 2024 13:38:55 +0100 Subject: Include sizes of shadow box extents as uniforms to shaders --- gfx/gl/shadowMapper.cpp | 16 +++++++++++----- gfx/gl/shadowMapper.h | 5 ++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index d9dd24f..55167e5 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -95,23 +95,28 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const const auto lightViewPoint = camera.getPosition(); const auto bandViewExtents = getBandViewExtents(camera, lightViewDir); Definitions out; + Sizes sizes; std::transform(bandViewExtents.begin(), std::prev(bandViewExtents.end()), std::next(bandViewExtents.begin()), std::back_inserter(out), - [bands = bandViewExtents.size() - 2, &lightViewDir](const auto & near, const auto & far) mutable { + [bands = bandViewExtents.size() - 2, &lightViewDir, &sizes](const auto & near, const auto & far) mutable { const auto extents_minmax = [extents = std::span {near.begin(), far.end()}](auto && comp) { const auto mm = std::minmax_element(extents.begin(), extents.end(), comp); return std::make_pair(comp.get(*mm.first), comp.get(*mm.second)); }; + const std::array extents + = {extents_minmax(CompareBy {0}), extents_minmax(CompareBy {1}), extents_minmax(CompareBy {2})}; const auto lightProjection = [](const auto & x, const auto & y, const auto & z) { return glm::ortho(x.first, x.second, y.first, y.second, -z.second, -z.first); - }(extents_minmax(CompareBy {0}), extents_minmax(CompareBy {1}), extents_minmax(CompareBy {2})); + }(extents[0], extents[1], extents[2]); + sizes.emplace_back(extents[0].second - extents[0].first, extents[1].second - extents[1].first, + extents[2].second - extents[2].first); return lightProjection * lightViewDir; }); for (const auto p : std::initializer_list { &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures}) { - p->setView(out, lightViewPoint); + p->setView(out, sizes, lightViewPoint); } scene.shadows(*this); @@ -128,12 +133,13 @@ ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs, const Shader & gs, } void -ShadowMapper::ShadowProgram::setView( - const std::span viewProjection, const GlobalPosition3D viewPoint) const +ShadowMapper::ShadowProgram::setView(const std::span viewProjection, + const std::span sizes, const GlobalPosition3D viewPoint) const { use(); glUniform(viewPointLoc, viewPoint); glUniform(viewProjectionLoc, viewProjection); + glUniform(sizesLoc, sizes); glUniform(viewProjectionsLoc, static_cast(viewProjection.size())); } diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index 280a0cd..19c3d23 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -19,6 +19,7 @@ public: static constexpr std::size_t SHADOW_BANDS {4}; using Definitions = std::vector; + using Sizes = std::vector; [[nodiscard]] Definitions update(const SceneProvider &, const Direction3D & direction, const Camera &) const; @@ -27,12 +28,14 @@ public: explicit ShadowProgram(const Shader & vs); explicit ShadowProgram(const Shader & vs, const Shader & gs, const Shader & fs); - void setView(const std::span, const GlobalPosition3D) const; + void setView(const std::span, const std::span, + const GlobalPosition3D) const; void use() const; private: RequiredUniformLocation viewProjectionLoc {*this, "viewProjection"}; RequiredUniformLocation viewProjectionsLoc {*this, "viewProjections"}; + UniformLocation sizesLoc {*this, "sizes"}; RequiredUniformLocation viewPointLoc {*this, "viewPoint"}; }; -- cgit v1.2.3 From 362c6952742eb01e32fdeb2ec26a2fe463e5001c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 26 Aug 2024 13:47:22 +0100 Subject: Add a foliage vertex array for just the location data --- game/scenary/foliage.cpp | 2 ++ game/scenary/foliage.h | 1 + 2 files changed, 3 insertions(+) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 13d2f3b..1c03217 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -16,6 +16,8 @@ Foliage::postLoad() texture = getTexture(); bodyMesh->configureVAO(instanceVAO) .addAttribs(instances.bufferName(), 1); + VertexArrayObject {instancePointVAO}.addAttribs( + instances.bufferName()); } void diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index fa6c63b..824a644 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -14,6 +14,7 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs { Mesh::Ptr bodyMesh; Texture::Ptr texture; glVertexArray instanceVAO; + glVertexArray instancePointVAO; public: using LocationVertex = std::pair; -- cgit v1.2.3 From 10e0fee323e6277ba73ee1fc148417882bc381c3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 26 Aug 2024 13:55:32 +0100 Subject: Add helper to test if a uniform was found --- gfx/gl/program.h | 6 ++++++ gfx/gl/sceneShader.cpp | 2 +- gfx/gl/shadowMapper.cpp | 4 +++- gfx/gl/shadowStenciller.h | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gfx/gl/program.h b/gfx/gl/program.h index c89a128..20be1aa 100644 --- a/gfx/gl/program.h +++ b/gfx/gl/program.h @@ -33,6 +33,12 @@ public: return location; } + explicit + operator bool() const + { + return location >= 0; + } + protected: GLint location; }; diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 4cbccb3..571538a 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -65,7 +65,7 @@ SceneShader::SceneProgram::setViewProjection(const GlobalPosition3D & viewPoint, void SceneShader::SceneProgram::setViewPort(const ViewPort & viewPort) const { - if (viewPortLoc >= 0) { + if (viewPortLoc) { glUseProgram(*this); glUniform(viewPortLoc, viewPort); } diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 55167e5..177bd22 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -139,7 +139,9 @@ ShadowMapper::ShadowProgram::setView(const std::span viewProj use(); glUniform(viewPointLoc, viewPoint); glUniform(viewProjectionLoc, viewProjection); - glUniform(sizesLoc, sizes); + if (sizesLoc) { + glUniform(sizesLoc, sizes); + } glUniform(viewProjectionsLoc, static_cast(viewProjection.size())); } diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 009285c..925f82a 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -17,7 +17,7 @@ public: private: glFrameBuffer fbo; Program shadowCaster; - Program::UniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; + Program::RequiredUniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; glm::mat4 lightDirMat {}; }; -- cgit v1.2.3 From ce6659f5581a7d1f6b0f7b42e29c831e93315be8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 26 Aug 2024 19:07:37 +0100 Subject: Set stencil texture min/mag filters --- gfx/gl/shadowStenciller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index ac63b4e..0c34da5 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -28,6 +28,8 @@ ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) glBindTexture(GL_TEXTURE_2D, stencil); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -- cgit v1.2.3 From ae9087aea7aa2b19bf78daa6593d14dfba98183d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 28 Aug 2024 03:48:19 +0100 Subject: Initial cut of shadow map creation with support for billboard shadows --- gfx/gl/shaders/shadowDynamicPointStencil.fs | 16 +++++++++++++++ gfx/gl/shaders/shadowDynamicPointStencil.gs | 32 +++++++++++++++++++++++++++++ gfx/gl/shaders/shadowDynamicPointStencil.vs | 17 +++++++++++++++ gfx/gl/shadowMapper.cpp | 18 +++++++++++++++- gfx/gl/shadowMapper.h | 11 ++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 gfx/gl/shaders/shadowDynamicPointStencil.fs create mode 100644 gfx/gl/shaders/shadowDynamicPointStencil.gs create mode 100644 gfx/gl/shaders/shadowDynamicPointStencil.vs diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.fs b/gfx/gl/shaders/shadowDynamicPointStencil.fs new file mode 100644 index 0000000..57b8aa3 --- /dev/null +++ b/gfx/gl/shaders/shadowDynamicPointStencil.fs @@ -0,0 +1,16 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +layout(binding = 0) uniform sampler2D stencilDepth; +flat in vec3 scale; +in vec2 texCoord; + +void +main() +{ + float stDepth = texture(stencilDepth, texCoord).r; + if (stDepth >= 1) { + discard; + } + gl_FragDepth = gl_FragCoord.z + (stDepth * scale.z); +} diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.gs b/gfx/gl/shaders/shadowDynamicPointStencil.gs new file mode 100644 index 0000000..6d707ae --- /dev/null +++ b/gfx/gl/shaders/shadowDynamicPointStencil.gs @@ -0,0 +1,32 @@ +#version 330 core +#extension GL_ARB_viewport_array : enable + +const vec2[] corners = vec2[4](vec2(-1, -1), vec2(-1, 1), vec2(1, -1), vec2(1, 1)); + +uniform mat4 viewProjection[4]; +uniform int viewProjections; +uniform vec3 sizes[4]; +uniform float size; + +in ivec3 vworldPos[]; + +flat out vec3 scale; +out vec2 texCoord; + +layout(points) in; +layout(triangle_strip, max_vertices = 16) out; + +void +main() +{ + for (gl_Layer = 0; gl_Layer < viewProjections; ++gl_Layer) { + scale = 2.0 * size / sizes[gl_Layer]; + vec4 pos = viewProjection[gl_Layer] * vec4(vworldPos[0], 1); + for (int c = 0; c < corners.length(); ++c) { + gl_Position = pos + vec4(scale.xy * corners[c], 0, 0); + texCoord = (corners[c] * 0.5) + 0.5; + EmitVertex(); + } + EndPrimitive(); + } +} diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.vs b/gfx/gl/shaders/shadowDynamicPointStencil.vs new file mode 100644 index 0000000..dadf9c2 --- /dev/null +++ b/gfx/gl/shaders/shadowDynamicPointStencil.vs @@ -0,0 +1,17 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +layout(location = 0) in mat3 model; +layout(location = 3) in ivec3 worldPos; +uniform ivec3 viewPoint; +uniform vec3 centre; + +out mat3 vmodel; +out ivec3 vworldPos; + +void +main() +{ + vmodel = model; + vworldPos = worldPos - viewPoint + ivec3(centre); +} diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 177bd22..ac161e2 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -3,11 +3,14 @@ #include "collections.h" #include "game/gamestate.h" #include "gfx/gl/shaders/fs-shadowDynamicPointInstWithTextures.h" +#include "gfx/gl/shaders/fs-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/gs-commonShadowPoint.h" #include "gfx/gl/shaders/gs-shadowDynamicPointInstWithTextures.h" +#include "gfx/gl/shaders/gs-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/vs-shadowDynamicPoint.h" #include "gfx/gl/shaders/vs-shadowDynamicPointInst.h" #include "gfx/gl/shaders/vs-shadowDynamicPointInstWithTextures.h" +#include "gfx/gl/shaders/vs-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/vs-shadowLandmass.h" #include "gfx/gl/shadowStenciller.h" #include "gfx/renderable.h" @@ -115,7 +118,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const return lightProjection * lightViewDir; }); for (const auto p : std::initializer_list { - &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures}) { + &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures, &stencilShadowProgram}) { p->setView(out, sizes, lightViewPoint); } scene.shadows(*this); @@ -166,3 +169,16 @@ ShadowMapper::DynamicPoint::setModel(const Location & location) const glUniform(modelLoc, location.getRotationTransform()); glUniform(modelPosLoc, location.pos); } + +ShadowMapper::StencilShadowProgram::StencilShadowProgram() : + ShadowProgram {shadowDynamicPointStencil_vs, shadowDynamicPointStencil_gs, shadowDynamicPointStencil_fs} +{ +} + +void +ShadowMapper::StencilShadowProgram::use(const RelativePosition3D & centre, const float size) const +{ + Program::use(); + glUniform(centreLoc, centre); + glUniform(sizeLoc, size); +} diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index 19c3d23..3aa224e 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -50,8 +50,19 @@ public: RequiredUniformLocation modelPosLoc {*this, "modelPos"}; }; + class StencilShadowProgram : public ShadowProgram { + public: + StencilShadowProgram(); + void use(const RelativePosition3D & centre, const float size) const; + + private: + RequiredUniformLocation centreLoc {*this, "centre"}; + RequiredUniformLocation sizeLoc {*this, "size"}; + }; + ShadowProgram landmess, dynamicPointInst, dynamicPointInstWithTextures; DynamicPoint dynamicPoint; + StencilShadowProgram stencilShadowProgram; // NOLINTNEXTLINE(hicpp-explicit-conversions) operator GLuint() const -- cgit v1.2.3 From 75905c01b13fd7a1d58494b8aaacb3b4b3cccdaa Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 28 Aug 2024 03:48:43 +0100 Subject: Use billboard shadows for foliage --- game/scenary/foliage.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 1c03217..af67ea6 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -45,10 +45,12 @@ void Foliage::shadows(const ShadowMapper & mapper) const { if (const auto count = instances.size()) { - mapper.dynamicPointInstWithTextures.use(); - if (texture) { - texture->bind(GL_TEXTURE3); - } - bodyMesh->DrawInstanced(instanceVAO, static_cast(count)); + const auto dimensions = bodyMesh->getDimensions(); + mapper.stencilShadowProgram.use(dimensions.centre, dimensions.size); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, shadowStencil); + glBindVertexArray(instancePointVAO); + glDrawArrays(GL_POINTS, 0, static_cast(count)); + glBindVertexArray(0); } } -- cgit v1.2.3 From 7299b08977acafe7eeba620f229a7169256f23cf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 1 Sep 2024 18:42:27 +0100 Subject: Extend depth of shadow box 10m to allow for depth offsets and clamp stencil to it --- gfx/gl/shaders/shadowDynamicPointStencil.gs | 1 + gfx/gl/shadowMapper.cpp | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.gs b/gfx/gl/shaders/shadowDynamicPointStencil.gs index 6d707ae..2873691 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.gs +++ b/gfx/gl/shaders/shadowDynamicPointStencil.gs @@ -24,6 +24,7 @@ main() vec4 pos = viewProjection[gl_Layer] * vec4(vworldPos[0], 1); for (int c = 0; c < corners.length(); ++c) { gl_Position = pos + vec4(scale.xy * corners[c], 0, 0); + gl_Position.z = max(gl_Position.z, -1); texCoord = (corners[c] * 0.5) + 0.5; EmitVertex(); } diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index ac161e2..b08538d 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -102,12 +102,13 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const std::transform(bandViewExtents.begin(), std::prev(bandViewExtents.end()), std::next(bandViewExtents.begin()), std::back_inserter(out), [bands = bandViewExtents.size() - 2, &lightViewDir, &sizes](const auto & near, const auto & far) mutable { - const auto extents_minmax = [extents = std::span {near.begin(), far.end()}](auto && comp) { - const auto mm = std::minmax_element(extents.begin(), extents.end(), comp); - return std::make_pair(comp.get(*mm.first), comp.get(*mm.second)); - }; - const std::array extents - = {extents_minmax(CompareBy {0}), extents_minmax(CompareBy {1}), extents_minmax(CompareBy {2})}; + const auto extents_minmax + = [extents = std::span {near.begin(), far.end()}](auto && comp, RelativeDistance extra) { + const auto mm = std::minmax_element(extents.begin(), extents.end(), comp); + return std::make_pair(comp.get(*mm.first) - extra, comp.get(*mm.second) + extra); + }; + const std::array extents = {extents_minmax(CompareBy {0}, 0), extents_minmax(CompareBy {1}, 0), + extents_minmax(CompareBy {2}, 10'000)}; const auto lightProjection = [](const auto & x, const auto & y, const auto & z) { return glm::ortho(x.first, x.second, y.first, y.second, -z.second, -z.first); -- cgit v1.2.3 From 683771aa8f13cab1760a69a47fcbebdf14a5343f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 2 Sep 2024 20:46:32 +0100 Subject: Add TextureDimensions type --- config/types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config/types.h b/config/types.h index 081530d..c501f41 100644 --- a/config/types.h +++ b/config/types.h @@ -42,6 +42,7 @@ using Normal3D = Normal<3>; using Rotation2D = Rotation<2>; using Rotation3D = Rotation<3>; using TextureRelCoord = glm::vec<2, float>; +using TextureDimensions = glm::vec<3, GLsizei>; using TextureRelRegion = glm::vec<4, float>; using TextureAbsCoord = glm::vec<2, GLsizei>; using TextureAbsRegion = glm::vec<4, GLsizei>; -- cgit v1.2.3 From 995961c162b4e79c690f722c61c01165ef497e9f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 2 Sep 2024 20:49:04 +0100 Subject: Update Texture::getSize and ::size to account for the third texture dimension --- gfx/models/texture.cpp | 9 +++++---- gfx/models/texture.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index 51223aa..a508421 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -59,12 +59,13 @@ Texture::bind(GLenum unit) const glBindTexture(type, m_texture); } -TextureAbsCoord +TextureDimensions Texture::getSize(const glTexture & texture) { - TextureAbsCoord size; + TextureDimensions size {}; glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_WIDTH, &size.x); glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_HEIGHT, &size.y); + glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_DEPTH, &size.z); return size; } @@ -73,7 +74,7 @@ Texture::save( const glTexture & texture, GLenum format, GLenum type, uint8_t channels, const char * path, uint8_t tgaFormat) { const auto size = getSize(texture); - const size_t dataSize = (static_cast(size.x * size.y * channels)); + const size_t dataSize = (static_cast(size.x * size.y * size.z * channels)); const size_t fileSize = dataSize + sizeof(TGAHead); filesystem::fh out {path, O_RDWR | O_CREAT, 0660}; @@ -81,7 +82,7 @@ Texture::save( auto tga = out.mmap(fileSize, 0, PROT_WRITE, MAP_SHARED); *tga.get() = { .format = tgaFormat, - .size = size, + .size = {size.x, size.y * size.z}, .pixelDepth = static_cast(8 * channels), }; glPixelStorei(GL_PACK_ALIGNMENT, 1); diff --git a/gfx/models/texture.h b/gfx/models/texture.h index 8cb8128..3329511 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -41,7 +41,7 @@ public: protected: static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat); - static TextureAbsCoord getSize(const glTexture &); + static TextureDimensions getSize(const glTexture &); glTexture m_texture; GLenum type; -- cgit v1.2.3 From 052b2b49d9bfdaaa7f7c5603fa7c47b881df93c2 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 2 Sep 2024 21:00:41 +0100 Subject: Update stencil texture to 2d array --- game/scenary/foliage.cpp | 2 +- gfx/gl/shaders/shadowDynamicPointStencil.fs | 4 ++-- gfx/gl/shaders/shadowDynamicPointStencil.gs | 4 ++-- gfx/gl/shadowStenciller.cpp | 13 +++++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index af67ea6..1e7424e 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -48,7 +48,7 @@ Foliage::shadows(const ShadowMapper & mapper) const const auto dimensions = bodyMesh->getDimensions(); mapper.stencilShadowProgram.use(dimensions.centre, dimensions.size); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shadowStencil); + glBindTexture(GL_TEXTURE_2D_ARRAY, shadowStencil); glBindVertexArray(instancePointVAO); glDrawArrays(GL_POINTS, 0, static_cast(count)); glBindVertexArray(0); diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.fs b/gfx/gl/shaders/shadowDynamicPointStencil.fs index 57b8aa3..e612691 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.fs +++ b/gfx/gl/shaders/shadowDynamicPointStencil.fs @@ -1,9 +1,9 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable -layout(binding = 0) uniform sampler2D stencilDepth; +layout(binding = 0) uniform sampler2DArray stencilDepth; flat in vec3 scale; -in vec2 texCoord; +in vec3 texCoord; void main() diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.gs b/gfx/gl/shaders/shadowDynamicPointStencil.gs index 2873691..b91937d 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.gs +++ b/gfx/gl/shaders/shadowDynamicPointStencil.gs @@ -11,7 +11,7 @@ uniform float size; in ivec3 vworldPos[]; flat out vec3 scale; -out vec2 texCoord; +out vec3 texCoord; layout(points) in; layout(triangle_strip, max_vertices = 16) out; @@ -25,7 +25,7 @@ main() for (int c = 0; c < corners.length(); ++c) { gl_Position = pos + vec4(scale.xy * corners[c], 0, 0); gl_Position.z = max(gl_Position.z, -1); - texCoord = (corners[c] * 0.5) + 0.5; + texCoord = vec3((corners[c] * 0.5) + 0.5, 0); EmitVertex(); } EndPrimitive(); diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 0c34da5..01248bd 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -25,15 +25,16 @@ glTexture ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) { glTexture stencil; - glBindTexture(GL_TEXTURE_2D, stencil); + glBindTexture(GL_TEXTURE_2D_ARRAY, stencil); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, width, height, 8, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, + nullptr); return stencil; } -- cgit v1.2.3 From f22f79330f9b8851cda76d1e11555877cbb72d80 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 3 Sep 2024 01:37:03 +0100 Subject: Populate all layers of the stencil texture Albeit with the same projection --- gfx/gl/shaders/shadowStencil.fs | 6 ++++-- gfx/gl/shaders/shadowStencil.gs | 28 ++++++++++++++++++++++++++++ gfx/gl/shaders/shadowStencil.vs | 10 ++++++---- gfx/gl/shadowStenciller.cpp | 3 ++- 4 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 gfx/gl/shaders/shadowStencil.gs diff --git a/gfx/gl/shaders/shadowStencil.fs b/gfx/gl/shaders/shadowStencil.fs index f149c23..1164cc9 100644 --- a/gfx/gl/shaders/shadowStencil.fs +++ b/gfx/gl/shaders/shadowStencil.fs @@ -3,13 +3,15 @@ layout(binding = 0) uniform sampler2D textureAlbedo; -include(`materialInterface.glsl') +include(`materialDetail.glsl') include(`materialCommon.glsl') +in vec2 gTexCoords; +flat in MaterialDetail gMaterial; void main() { - if (getTextureColour(Material, TexCoords).a < 0.5) { + if (getTextureColour(gMaterial, gTexCoords).a < 0.5) { discard; } gl_FragDepth = gl_FragCoord.z; diff --git a/gfx/gl/shaders/shadowStencil.gs b/gfx/gl/shaders/shadowStencil.gs new file mode 100644 index 0000000..eea4643 --- /dev/null +++ b/gfx/gl/shaders/shadowStencil.gs @@ -0,0 +1,28 @@ +#version 330 core +#extension GL_ARB_viewport_array : enable + +include(`materialDetail.glsl') + +layout(triangles) in; +layout(triangle_strip, max_vertices = 24) out; + +uniform mat4 viewProjection; +in vec3 FragPos[]; +in vec2 TexCoords[]; +flat in MaterialDetail Material[]; +out vec2 gTexCoords; +flat out MaterialDetail gMaterial; + +void +main() +{ + for (gl_Layer = 0; gl_Layer < 8; ++gl_Layer) { + for (int v = 0; v < FragPos.length(); ++v) { + gl_Position = viewProjection * vec4(FragPos[v], 1); + gTexCoords = TexCoords[v]; + gMaterial = Material[v]; + EmitVertex(); + } + EndPrimitive(); + } +} diff --git a/gfx/gl/shaders/shadowStencil.vs b/gfx/gl/shaders/shadowStencil.vs index 45a0867..a15c4fb 100644 --- a/gfx/gl/shaders/shadowStencil.vs +++ b/gfx/gl/shaders/shadowStencil.vs @@ -4,15 +4,17 @@ layout(binding = 1) uniform usampler2DRect materialData; include(`meshIn.glsl') -include(`materialInterface.glsl') +include(`materialDetail.glsl') include(`getMaterialDetail.glsl') -uniform mat4 viewProjection; + +out vec3 FragPos; +out vec2 TexCoords; +flat out MaterialDetail Material; void main() { TexCoords = texCoord; Material = getMaterialDetail(material); - - gl_Position = viewProjection * vec4(position, 1); + FragPos = position; } diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 01248bd..1063b71 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -1,13 +1,14 @@ #include "shadowStenciller.h" #include "gfx/gl/program.h" #include "gfx/gl/shaders/fs-shadowStencil.h" +#include "gfx/gl/shaders/gs-shadowStencil.h" #include "gfx/gl/shaders/vs-shadowStencil.h" #include "gfx/models/mesh.h" #include "glArrays.h" #include "gl_traits.h" #include -ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_fs} +ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs} { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDrawBuffer(GL_NONE); -- cgit v1.2.3 From 5ec74c35fb1f2524add7fd03ace78667f93edb2e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 7 Sep 2024 12:35:03 +0100 Subject: Populate all layers of shadow stencil with view from all around --- gfx/gl/shaders/shadowStencil.gs | 6 +++--- gfx/gl/shadowStenciller.cpp | 18 ++++++++++++++++-- gfx/gl/shadowStenciller.h | 1 + 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/gfx/gl/shaders/shadowStencil.gs b/gfx/gl/shaders/shadowStencil.gs index eea4643..2c3f9bd 100644 --- a/gfx/gl/shaders/shadowStencil.gs +++ b/gfx/gl/shaders/shadowStencil.gs @@ -6,7 +6,7 @@ include(`materialDetail.glsl') layout(triangles) in; layout(triangle_strip, max_vertices = 24) out; -uniform mat4 viewProjection; +uniform mat4 viewProjection[8]; in vec3 FragPos[]; in vec2 TexCoords[]; flat in MaterialDetail Material[]; @@ -16,9 +16,9 @@ flat out MaterialDetail gMaterial; void main() { - for (gl_Layer = 0; gl_Layer < 8; ++gl_Layer) { + for (gl_Layer = 0; gl_Layer < viewProjection.length(); ++gl_Layer) { for (int v = 0; v < FragPos.length(); ++v) { - gl_Position = viewProjection * vec4(FragPos[v], 1); + gl_Position = viewProjection[gl_Layer] * vec4(FragPos[v], 1); gTexCoords = TexCoords[v]; gMaterial = Material[v]; EmitVertex(); diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 1063b71..da2b3a0 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -6,9 +6,18 @@ #include "gfx/models/mesh.h" #include "glArrays.h" #include "gl_traits.h" +#include "maths.h" #include -ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs} +namespace { + static constexpr std::array anglesEigthPi {-3, -2, -1, 0, 1, 2, 3, 4}; + static const auto angles = anglesEigthPi * [](auto ep) { + return rotate_yaw(ep * quarter_pi); + }; +} + +ShadowStenciller::ShadowStenciller() : + shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs}, viewProjections {} { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDrawBuffer(GL_NONE); @@ -20,6 +29,9 @@ void ShadowStenciller::setLightDirection(const Direction3D & lightDir, const Direction3D & lightDirUp) { lightDirMat = glm::lookAt(-lightDir, {}, lightDirUp); + viewProjections = angles * [this](const auto & a) { + return lightDirMat * a; + }; } glTexture @@ -58,6 +70,8 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh const auto & size = mesh.getDimensions().size; const auto extentsMat = glm::translate(glm::ortho(-size, size, -size, size, -size, size), {-centre.x, -centre.z, -centre.y}); - glUniform(viewProjectionLoc, extentsMat * lightDirMat); + glUniform(viewProjectionLoc, std::span {viewProjections * [&](const auto & vp) { + return extentsMat * vp; + }}); mesh.Draw(); } diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 925f82a..2edb955 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -20,4 +20,5 @@ private: Program::RequiredUniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; glm::mat4 lightDirMat {}; + std::array viewProjections; }; -- cgit v1.2.3 From 38a839533e76d3e9570591a6aeec7c5c500270cf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 5 Oct 2024 12:15:28 +0100 Subject: Add rotate_yp taking two separate parameters --- lib/maths.cpp | 8 +++++++- lib/maths.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/maths.cpp b/lib/maths.cpp index 51e27fe..ea245f0 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -77,7 +77,13 @@ rotate_ypr(Rotation3D a) glm::mat4 rotate_yp(Rotation2D a) { - return rotate_yaw(a.y) * rotate_pitch(a.x); + return rotate_yp(a.y, a.x); +} + +glm::mat4 +rotate_yp(Angle yaw, Angle pitch) +{ + return rotate_yaw(yaw) * rotate_pitch(pitch); } float diff --git a/lib/maths.h b/lib/maths.h index 3127d3c..32f2884 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -97,6 +97,7 @@ glm::mat4 rotate_roll(float); glm::mat4 rotate_yaw(float); glm::mat4 rotate_pitch(float); glm::mat4 rotate_yp(Rotation2D); +glm::mat4 rotate_yp(Angle yaw, Angle pitch); glm::mat4 rotate_ypr(Rotation3D); float vector_yaw(const Direction2D & diff); -- cgit v1.2.3 From a9a2a4c8b5aad22d055c670c72eb41fc22b0d812 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 5 Oct 2024 12:17:55 +0100 Subject: Add LightDirection class --- gfx/lightDirection.cpp | 8 ++++++++ gfx/lightDirection.h | 32 ++++++++++++++++++++++++++++++++ test/test-environment.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 gfx/lightDirection.cpp create mode 100644 gfx/lightDirection.h diff --git a/gfx/lightDirection.cpp b/gfx/lightDirection.cpp new file mode 100644 index 0000000..6d7d1ea --- /dev/null +++ b/gfx/lightDirection.cpp @@ -0,0 +1,8 @@ +#include "lightDirection.h" +#include "maths.h" + +LightDirection::LightDirection(const Direction2D sunPos) : + pos {sunPos}, vec {glm::mat3 {rotate_yp(pi + sunPos.x, -sunPos.y)} * north}, + vert {-glm::clamp(-1.F, 0.F, vec.z - 0.1F)} +{ +} diff --git a/gfx/lightDirection.h b/gfx/lightDirection.h new file mode 100644 index 0000000..f1e1cc4 --- /dev/null +++ b/gfx/lightDirection.h @@ -0,0 +1,32 @@ +#pragma once + +#include "config/types.h" + +class LightDirection { +public: + // NOLINTNEXTLINE(hicpp-explicit-conversions) deliberately a helper + LightDirection(Direction2D sunPos); + + [[nodiscard]] Direction2D + position() const noexcept + { + return pos; + } + + [[nodiscard]] Direction3D + vector() const noexcept + { + return vec; + } + + [[nodiscard]] float + vertical() const noexcept + { + return vert; + } + +private: + Direction2D pos; + Direction3D vec; + float vert; +}; diff --git a/test/test-environment.cpp b/test/test-environment.cpp index b6e0e4f..76144a4 100644 --- a/test/test-environment.cpp +++ b/test/test-environment.cpp @@ -1,4 +1,5 @@ #define BOOST_TEST_MODULE environment +#include "testHelpers.h" #include #include #include @@ -7,9 +8,11 @@ #include #include #include +#include #include using sunPosTestData = std::tuple; +using sunDirTestData = std::tuple; constexpr Direction2D Doncaster = {-1.1, 53.5}; constexpr Direction2D NewYork = {74.0, 40.7}; constexpr Direction2D Syndey = {-151.2, -33.9}; @@ -19,6 +22,7 @@ BOOST_DATA_TEST_CASE(sun_position, boost::unit_test::data::make({ {EqGM, "2024-01-02T00:00:00"_time_t, {181.52F, -66.86F}}, {EqGM, "2024-01-02T06:00:00"_time_t, {113.12F, -0.85F}}, + {EqGM, "2024-01-02T06:30:00"_time_t, {113.12F, 6.05F}}, {EqGM, "2024-01-02T12:00:00"_time_t, {177.82F, 66.97F}}, {EqGM, "2024-01-02T18:00:00"_time_t, {246.99F, 0.90F}}, {EqGM, "2024-01-03T00:00:00"_time_t, {181.52F, -67.04F}}, @@ -33,3 +37,26 @@ BOOST_DATA_TEST_CASE(sun_position, BOOST_CHECK_CLOSE(sunPos.x, expSunPos.x, 1.F); BOOST_CHECK_CLOSE(sunPos.y, expSunPos.y, 1.F); } + +BOOST_DATA_TEST_CASE(sun_direction, + boost::unit_test::data::make({ + {{0.F, 0.F}, south, 0.1F}, + {{90.F, 0.F}, west, 0.1F}, + {{-90.F, 0.F}, east, 0.1F}, + // From above + // EqGM midnight, sun below horizon, shining upwards + {{181.52F, -66.86F}, {-0.01F, 0.39F, 0.919F}, 0}, + // EqGM just before sunrise, mostly west, north a bit, up a bit + {{113.12F, -0.85F}, {-0.92F, 0.39F, 0.015F}, 0.085F}, + // EqGM just after sunrise, mostly west, north a bit, down a bit + {{113.12F, 6.05F}, {-0.92F, 0.39F, -0.015F}, 0.205F}, + // Doncaster noon, roughly from south to north, high in the sky, downward + {{176.34F, 59.64F}, {-0.03F, 0.5F, -0.86F}, 0.96F}, + }), + position, direction, vert) +{ + const LightDirection ld {position * degreesToRads}; + BOOST_CHECK_CLOSE_VEC(ld.vector(), direction); + BOOST_CHECK_CLOSE(glm::length(ld.vector()), 1.F, 1); + BOOST_CHECK_CLOSE(ld.vertical(), vert, 5); +} -- cgit v1.2.3 From 10998a8302b3d7651b4afc046311961eb2dea2c8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 6 Oct 2024 12:48:40 +0100 Subject: Use LightDirection for calculating/passing all light dir components --- game/environment.cpp | 11 +++++------ gfx/gl/sceneProvider.cpp | 2 +- gfx/gl/sceneRenderer.cpp | 8 ++++---- gfx/gl/sceneRenderer.h | 3 ++- gfx/gl/shadowMapper.cpp | 7 ++++--- gfx/gl/shadowMapper.h | 3 ++- gfx/gl/shadowStenciller.cpp | 15 ++++++++------- gfx/gl/shadowStenciller.h | 5 +++-- test/test-assetFactory.cpp | 2 +- test/test-geoData.cpp | 2 +- test/test-render.cpp | 6 +++--- 11 files changed, 34 insertions(+), 30 deletions(-) diff --git a/game/environment.cpp b/game/environment.cpp index 19aad84..5aa1f09 100644 --- a/game/environment.cpp +++ b/game/environment.cpp @@ -1,4 +1,5 @@ #include "environment.h" +#include "gfx/lightDirection.h" #include #include @@ -16,14 +17,12 @@ Environment::render(const SceneRenderer & renderer, const SceneProvider & scene) constexpr RGB baseAmbient {0.1F}, baseDirectional {0.0F}; constexpr RGB relativeAmbient {0.3F, 0.3F, 0.4F}, relativeDirectional {0.6F, 0.6F, 0.5F}; - const auto sunPos = getSunPos({}, worldTime); - const auto sunDir = (glm::mat3 {rotate_yp({sunPos.y + pi, sunPos.x})} * north); - const auto vertical = -std::min(0.F, sunDir.z - 0.1F); - const auto ambient = baseAmbient + relativeAmbient * vertical; - const auto directional = baseDirectional + relativeDirectional * vertical; + const LightDirection sunPos = getSunPos({}, worldTime); + const auto ambient = baseAmbient + relativeAmbient * sunPos.vertical(); + const auto directional = baseDirectional + relativeDirectional * sunPos.vertical(); renderer.setAmbientLight(ambient); - renderer.setDirectionalLight(directional, sunDir, scene); + renderer.setDirectionalLight(directional, sunPos, scene); } // Based on the C++ code published at https://www.psa.es/sdg/sunpos.htm diff --git a/gfx/gl/sceneProvider.cpp b/gfx/gl/sceneProvider.cpp index 2e8604c..4e271db 100644 --- a/gfx/gl/sceneProvider.cpp +++ b/gfx/gl/sceneProvider.cpp @@ -5,7 +5,7 @@ void SceneProvider::environment(const SceneShader &, const SceneRenderer & renderer) const { renderer.setAmbientLight({0.5F, 0.5F, 0.5F}); - renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {-1, 1, -1}, *this); + renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {{-quarter_pi, -quarter_pi}}, *this); } void diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 7aace49..b2a7d78 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -114,7 +114,8 @@ SceneRenderer::setAmbientLight(const RGB & colour) const } void -SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider & scene) const +SceneRenderer::setDirectionalLight( + const RGB & colour, const LightDirection & direction, const SceneProvider & scene) const { if (colour.r > 0 || colour.g > 0 || colour.b > 0) { const auto lvp = shadowMapper.update(scene, direction, camera); @@ -128,7 +129,7 @@ SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direc glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMapper); glViewport(0, 0, size.x, size.y); dirLight.use(); - dirLight.setDirectionalLight(colour, direction, camera.getPosition(), lvp); + dirLight.setDirectionalLight(colour, direction.vector(), camera.getPosition(), lvp); renderQuad(); } } @@ -154,8 +155,7 @@ SceneRenderer::DirectionalLightProgram::setDirectionalLight( return toTextureSpaceMat * m; }; glUniform(colourLoc, c); - const auto nd = glm::normalize(d); - glUniform(directionLoc, nd); + glUniform(directionLoc, d); glUniform(lightPointLoc, p); glUniform(lightViewProjectionCountLoc, static_cast(lvp.size())); glUniform(lightViewProjectionLoc, std::span {lvp * toTextureSpace}); diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index 4195bcf..93470f5 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -1,6 +1,7 @@ #pragma once #include "camera.h" +#include "gfx/lightDirection.h" #include "glArrays.h" #include "program.h" #include "sceneProvider.h" @@ -14,7 +15,7 @@ public: void render(const SceneProvider &) const; void setAmbientLight(const RGB & colour) const; - void setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider &) const; + void setDirectionalLight(const RGB & colour, const LightDirection & direction, const SceneProvider &) const; Camera camera; diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index b08538d..4f7eac1 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -13,6 +13,7 @@ #include "gfx/gl/shaders/vs-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/vs-shadowLandmass.h" #include "gfx/gl/shadowStenciller.h" +#include "gfx/lightDirection.h" #include "gfx/renderable.h" #include "gl_traits.h" #include "location.h" @@ -78,12 +79,12 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV } ShadowMapper::Definitions -ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const Camera & camera) const +ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, const Camera & camera) const { glCullFace(GL_FRONT); glEnable(GL_DEPTH_TEST); - shadowStenciller.setLightDirection(dir, up); + shadowStenciller.setLightDirection(dir); for (const auto & [id, asset] : gameState->assets) { if (const auto r = std::dynamic_pointer_cast(asset)) { r->updateStencil(shadowStenciller); @@ -94,7 +95,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, size.x, size.y); - const auto lightViewDir = glm::lookAt({}, dir, up); + const auto lightViewDir = glm::lookAt({}, dir.vector(), up); const auto lightViewPoint = camera.getPosition(); const auto bandViewExtents = getBandViewExtents(camera, lightViewDir); Definitions out; diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index 3aa224e..951e29c 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -11,6 +11,7 @@ class SceneProvider; class Camera; +class LightDirection; class ShadowMapper { public: @@ -21,7 +22,7 @@ public: using Definitions = std::vector; using Sizes = std::vector; - [[nodiscard]] Definitions update(const SceneProvider &, const Direction3D & direction, const Camera &) const; + [[nodiscard]] Definitions update(const SceneProvider &, const LightDirection & direction, const Camera &) const; class ShadowProgram : public Program { public: diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index da2b3a0..ae4012a 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -3,6 +3,7 @@ #include "gfx/gl/shaders/fs-shadowStencil.h" #include "gfx/gl/shaders/gs-shadowStencil.h" #include "gfx/gl/shaders/vs-shadowStencil.h" +#include "gfx/lightDirection.h" #include "gfx/models/mesh.h" #include "glArrays.h" #include "gl_traits.h" @@ -26,10 +27,9 @@ ShadowStenciller::ShadowStenciller() : } void -ShadowStenciller::setLightDirection(const Direction3D & lightDir, const Direction3D & lightDirUp) +ShadowStenciller::setLightDirection(const LightDirection & lightDir) { - lightDirMat = glm::lookAt(-lightDir, {}, lightDirUp); - viewProjections = angles * [this](const auto & a) { + viewProjections = angles * [lightDirMat = rotate_pitch(lightDir.position().y)](const auto & a) { return lightDirMat * a; }; } @@ -68,10 +68,11 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh glViewport(0, 0, 256, 256); const auto & centre = mesh.getDimensions().centre; const auto & size = mesh.getDimensions().size; - const auto extentsMat - = glm::translate(glm::ortho(-size, size, -size, size, -size, size), {-centre.x, -centre.z, -centre.y}); - glUniform(viewProjectionLoc, std::span {viewProjections * [&](const auto & vp) { - return extentsMat * vp; + glUniform(viewProjectionLoc, + std::span {viewProjections * + [extentsMat = glm::translate(glm::ortho(-size, size, -size, size, -size, size), -centre)]( + const auto & vp) { + return vp * extentsMat; }}); mesh.Draw(); } diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 2edb955..03efced 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -5,13 +5,15 @@ #include "gfx/models/texture.h" #include "glArrays.h" +class LightDirection; + class ShadowStenciller { public: ShadowStenciller(); [[nodiscard]] static glTexture createStencilTexture(GLsizei width, GLsizei height); - void setLightDirection(const Direction3D & lightDir, const Direction3D & lightDirUp); + void setLightDirection(const LightDirection & lightDir); void renderStencil(const glTexture &, const MeshBase &, const Texture::AnyPtr texture) const; private: @@ -19,6 +21,5 @@ private: Program shadowCaster; Program::RequiredUniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; - glm::mat4 lightDirMat {}; std::array viewProjections; }; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 0b5b278..6036721 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -54,7 +54,7 @@ public: environment(const SceneShader &, const SceneRenderer & sceneRenderer) const override { sceneRenderer.setAmbientLight({.4, .4, .4}); - sceneRenderer.setDirectionalLight({.6, .6, .6}, east + south + south + down, *this); + sceneRenderer.setDirectionalLight({.6, .6, .6}, {{0.9, 0.5}}, *this); } void diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 11d634d..4a7b98d 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -253,7 +253,7 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson("geoData/deform/ environment(const SceneShader &, const SceneRenderer & sr) const override { sr.setAmbientLight({0.1, 0.1, 0.1}); - sr.setDirectionalLight({1, 1, 1}, south + down, *this); + sr.setDirectionalLight({1, 1, 1}, {{quarter_pi, -3 * half_pi}}, *this); } void diff --git a/test/test-render.cpp b/test/test-render.cpp index 0a92689..775eb5c 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -1,4 +1,3 @@ -#include "game/environment.h" #define BOOST_TEST_MODULE test_render #include "testHelpers.h" @@ -8,6 +7,7 @@ #include #include +#include #include #include #include @@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(terrain) environment(const SceneShader &, const SceneRenderer & sr) const override { sr.setAmbientLight({0.1, 0.1, 0.1}); - sr.setDirectionalLight({1, 1, 1}, south + down, *this); + sr.setDirectionalLight({1, 1, 1}, {{0, quarter_pi}}, *this); } void @@ -213,7 +213,7 @@ BOOST_AUTO_TEST_CASE(railnet) environment(const SceneShader &, const SceneRenderer & sr) const override { sr.setAmbientLight({0.1, 0.1, 0.1}); - sr.setDirectionalLight({1, 1, 1}, south + down, *this); + sr.setDirectionalLight({1, 1, 1}, {{0, quarter_pi}}, *this); } void -- cgit v1.2.3 From c9bf24c7d1c10e2ff7349fa2d9010895860977a9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 10 Oct 2024 00:48:06 +0100 Subject: Fix stencil shadow depth offset --- gfx/gl/shaders/shadowDynamicPointStencil.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.fs b/gfx/gl/shaders/shadowDynamicPointStencil.fs index e612691..fe91b07 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.fs +++ b/gfx/gl/shaders/shadowDynamicPointStencil.fs @@ -12,5 +12,5 @@ main() if (stDepth >= 1) { discard; } - gl_FragDepth = gl_FragCoord.z + (stDepth * scale.z); + gl_FragDepth = gl_FragCoord.z + ((stDepth - 0.5) * scale.z); } -- cgit v1.2.3 From 439630ae86b01b714574335d4dd2e583f724dba3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 10 Oct 2024 00:59:41 +0100 Subject: Include foliage yaw rotation in vertex, pass through instead of whole model rotation matrix --- game/scenary/foliage.cpp | 5 +++-- game/scenary/foliage.h | 7 ++++++- game/scenary/plant.cpp | 3 ++- gfx/gl/shaders/shadowDynamicPointStencil.vs | 8 ++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 1e7424e..c90d5be 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -15,8 +15,9 @@ Foliage::postLoad() { texture = getTexture(); bodyMesh->configureVAO(instanceVAO) - .addAttribs(instances.bufferName(), 1); - VertexArrayObject {instancePointVAO}.addAttribs( + .addAttribs( + instances.bufferName(), 1); + VertexArrayObject {instancePointVAO}.addAttribs( instances.bufferName()); } diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 824a644..5da63f0 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -17,7 +17,12 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs { glVertexArray instancePointVAO; public: - using LocationVertex = std::pair; + struct LocationVertex { + glm::mat3 rotation; + float yaw; + GlobalPosition3D position; + }; + mutable InstanceVertices instances; void render(const SceneShader &) const override; void shadows(const ShadowMapper &) const override; diff --git a/game/scenary/plant.cpp b/game/scenary/plant.cpp index b39c28b..2006225 100644 --- a/game/scenary/plant.cpp +++ b/game/scenary/plant.cpp @@ -2,6 +2,7 @@ #include "location.h" Plant::Plant(std::shared_ptr type, const Location & position) : - type {std::move(type)}, location {this->type->instances.acquire(position.getRotationTransform(), position.pos)} + type {std::move(type)}, + location {this->type->instances.acquire(position.getRotationTransform(), position.rot.y, position.pos)} { } diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.vs b/gfx/gl/shaders/shadowDynamicPointStencil.vs index dadf9c2..0dd2d79 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.vs +++ b/gfx/gl/shaders/shadowDynamicPointStencil.vs @@ -1,17 +1,17 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable -layout(location = 0) in mat3 model; -layout(location = 3) in ivec3 worldPos; +layout(location = 0) in ivec3 worldPos; +layout(location = 1) in float modelYaw; uniform ivec3 viewPoint; uniform vec3 centre; -out mat3 vmodel; +out float vmodelYaw; out ivec3 vworldPos; void main() { - vmodel = model; + vmodelYaw = modelYaw; vworldPos = worldPos - viewPoint + ivec3(centre); } -- cgit v1.2.3 From 493af2b220d6ba7f883d35a6bb30cb5d07b4a4b5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 10 Oct 2024 01:01:24 +0100 Subject: Use foliage yaw rotation to select shadow stencil layer --- gfx/gl/shaders/shadowDynamicPointStencil.gs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.gs b/gfx/gl/shaders/shadowDynamicPointStencil.gs index b91937d..7e81d97 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.gs +++ b/gfx/gl/shaders/shadowDynamicPointStencil.gs @@ -2,12 +2,14 @@ #extension GL_ARB_viewport_array : enable const vec2[] corners = vec2[4](vec2(-1, -1), vec2(-1, 1), vec2(1, -1), vec2(1, 1)); +const float tau = 6.28318531; uniform mat4 viewProjection[4]; uniform int viewProjections; uniform vec3 sizes[4]; uniform float size; +in float vmodelYaw[]; in ivec3 vworldPos[]; flat out vec3 scale; @@ -19,13 +21,14 @@ layout(triangle_strip, max_vertices = 16) out; void main() { + int viewAngle = int(round(4.0 + (vmodelYaw[0] / tau))) % 8; for (gl_Layer = 0; gl_Layer < viewProjections; ++gl_Layer) { scale = 2.0 * size / sizes[gl_Layer]; vec4 pos = viewProjection[gl_Layer] * vec4(vworldPos[0], 1); for (int c = 0; c < corners.length(); ++c) { gl_Position = pos + vec4(scale.xy * corners[c], 0, 0); gl_Position.z = max(gl_Position.z, -1); - texCoord = vec3((corners[c] * 0.5) + 0.5, 0); + texCoord = vec3((corners[c] * 0.5) + 0.5, viewAngle); EmitVertex(); } EndPrimitive(); -- cgit v1.2.3 From 1d58b128db3a4b9eff55031993390f8488878587 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 10 Oct 2024 01:10:45 +0100 Subject: Generate stencils as views offset from light direction --- gfx/gl/shadowStenciller.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index ae4012a..30a67a7 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -10,13 +10,6 @@ #include "maths.h" #include -namespace { - static constexpr std::array anglesEigthPi {-3, -2, -1, 0, 1, 2, 3, 4}; - static const auto angles = anglesEigthPi * [](auto ep) { - return rotate_yaw(ep * quarter_pi); - }; -} - ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs}, viewProjections {} { @@ -29,8 +22,8 @@ ShadowStenciller::ShadowStenciller() : void ShadowStenciller::setLightDirection(const LightDirection & lightDir) { - viewProjections = angles * [lightDirMat = rotate_pitch(lightDir.position().y)](const auto & a) { - return lightDirMat * a; + viewProjections = std::array {0, 1, 2, 3, 4, 5, 6, 7} * [&lightDir](const auto & ep) { + return rotate_pitch(half_pi - lightDir.position().y) * rotate_yaw((ep * quarter_pi) - lightDir.position().x); }; } -- cgit v1.2.3 From a5903c351d9219524cf6440d299e57ac66e7ae35 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 10 Oct 2024 01:13:22 +0100 Subject: Don't dump stencil texture --- game/scenary/foliage.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index c90d5be..a0ec576 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -2,7 +2,6 @@ #include "gfx/gl/sceneShader.h" #include "gfx/gl/shadowMapper.h" #include "gfx/gl/vertexArrayObject.h" -#include "gfx/models/texture.h" bool Foliage::persist(Persistence::PersistenceStore & store) @@ -26,7 +25,6 @@ Foliage::updateStencil(const ShadowStenciller & ss) const { if (instances.size() > 0) { ss.renderStencil(shadowStencil, *bodyMesh, texture); - Texture::saveDepth(shadowStencil, std::format("/tmp/stencil-{}.tga", id).c_str()); } } -- cgit v1.2.3 From cfec8308a39ae4a2a1a1b1fe0df0a099470d9c78 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 02:58:16 +0100 Subject: Simple constexpr pow function --- lib/maths.cpp | 12 ++++++++++++ lib/maths.h | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/maths.cpp b/lib/maths.cpp index ea245f0..f527881 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -116,6 +116,18 @@ normalize(float ang) return ang; } +static_assert(pow(1, 0) == 1); +static_assert(pow(1, 1) == 1); +static_assert(pow(1, 2) == 1); +static_assert(pow(2, 0) == 1); +static_assert(pow(2, 1) == 2); +static_assert(pow(2, 2) == 4); +static_assert(pow(2, 3) == 8); +static_assert(pow(3, 0) == 1); +static_assert(pow(3, 1) == 3); +static_assert(pow(3, 2) == 9); +static_assert(pow(pi, 3) == 31.006278991699219F); + float operator"" _mph(const long double v) { diff --git a/lib/maths.h b/lib/maths.h index 32f2884..97b7ef5 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -261,6 +261,19 @@ midpoint(const std::pair & v) return std::midpoint(v.first, v.second); } +// std::pow is not constexpr +template + requires requires(T n) { n *= n; } +constexpr inline T +pow(const T base, std::integral auto exp) +{ + T res {1}; + while (exp--) { + res *= base; + } + return res; +} + // Conversions template inline constexpr auto -- cgit v1.2.3 From d99f1249e861c665710c5d8da0351e525c9f2116 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 03:41:51 +0100 Subject: Better shadowBands sizes Still a bit arbitrary, but calculated now to scale across the required range --- gfx/gl/shadowMapper.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 4f7eac1..1b95aa3 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -52,13 +52,15 @@ ShadowMapper::ShadowMapper(const TextureAbsCoord & s) : glBindFramebuffer(GL_FRAMEBUFFER, 0); } -constexpr std::array shadowBands { - 1000, - 250000, - 750000, - 2500000, - 10000000, -}; +constexpr auto shadowBands + = [](const float scaleFactor, std::integer_sequence) { + const auto base = 10'000'000 / pow(scaleFactor, sizeof...(ints) - 1); + return std::array {1, static_cast((base * pow(scaleFactor, ints)))...}; + }(6.6F, std::make_integer_sequence()); + +static_assert(shadowBands.front() == 1); +static_assert(shadowBands.back() == 10'000'000); +static_assert(shadowBands.size() == ShadowMapper::SHADOW_BANDS + 1); std::vector> ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightViewDir) -- cgit v1.2.3 From 79684d4ae9d4f05aaa091c8a5a66f58efd69c887 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 18:12:33 +0100 Subject: Texture::getSize helper can be public --- gfx/models/texture.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/models/texture.h b/gfx/models/texture.h index 3329511..d8c3b29 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -38,10 +38,10 @@ public: static void saveDepth(const glTexture &, const char * path); static void saveNormal(const glTexture &, const char * path); static void savePosition(const glTexture &, const char * path); + static TextureDimensions getSize(const glTexture &); protected: static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat); - static TextureDimensions getSize(const glTexture &); glTexture m_texture; GLenum type; -- cgit v1.2.3 From f1faf9e1f5f3cca954002c9fb3c654498957f149 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 18:13:27 +0100 Subject: Don't assume size of stencil texture --- gfx/gl/shadowStenciller.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 30a67a7..68b12ae 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -58,7 +58,8 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh } glUseProgram(shadowCaster); glClear(GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, 256, 256); + const auto stencilSize = Texture::getSize(stencil); + glViewport(0, 0, stencilSize.x, stencilSize.y); const auto & centre = mesh.getDimensions().centre; const auto & size = mesh.getDimensions().size; glUniform(viewProjectionLoc, -- cgit v1.2.3 From c94bfd67c7dc2aea719288b2f2457e7397a439e5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 18:14:20 +0100 Subject: Remove magic number for stencil view angles --- gfx/gl/shadowStenciller.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 68b12ae..55ad8e1 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -10,6 +10,8 @@ #include "maths.h" #include +template constexpr T STENCIL_ANGLES = 8; + ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs}, viewProjections {} { @@ -39,8 +41,8 @@ ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height) glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, width, height, 8, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, - nullptr); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, width, height, STENCIL_ANGLES, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr); return stencil; } -- cgit v1.2.3 From 9a43f9e749f9f51cb37dabd9c1d33f2ee9441b2f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 18:26:24 +0100 Subject: Re-express viewProjections calculations as a fold expression --- gfx/gl/shadowStenciller.cpp | 10 +++++----- gfx/gl/shadowStenciller.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 55ad8e1..89b61cc 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -10,8 +10,6 @@ #include "maths.h" #include -template constexpr T STENCIL_ANGLES = 8; - ShadowStenciller::ShadowStenciller() : shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs}, viewProjections {} { @@ -24,9 +22,11 @@ ShadowStenciller::ShadowStenciller() : void ShadowStenciller::setLightDirection(const LightDirection & lightDir) { - viewProjections = std::array {0, 1, 2, 3, 4, 5, 6, 7} * [&lightDir](const auto & ep) { - return rotate_pitch(half_pi - lightDir.position().y) * rotate_yaw((ep * quarter_pi) - lightDir.position().x); - }; + viewProjections = [&lightDir](std::integer_sequence) { + constexpr float STEP = two_pi / STENCIL_ANGLES; + return std::array { + rotate_pitch(half_pi - lightDir.position().y) * rotate_yaw((Ep * STEP) - lightDir.position().x)...}; + }(std::make_integer_sequence>()); } glTexture diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index 03efced..ac83eb1 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -9,6 +9,8 @@ class LightDirection; class ShadowStenciller { public: + template static constexpr T STENCIL_ANGLES = 8; + ShadowStenciller(); [[nodiscard]] @@ -21,5 +23,5 @@ private: Program shadowCaster; Program::RequiredUniformLocation viewProjectionLoc {shadowCaster, "viewProjection"}; - std::array viewProjections; + std::array> viewProjections; }; -- cgit v1.2.3 From 33a691f6ab681160b377102aa02e78ccdfaf1ec3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 17 Oct 2024 18:27:50 +0100 Subject: Misc readability fixes --- gfx/gl/shadowStenciller.cpp | 6 +++--- gfx/gl/shadowStenciller.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index 89b61cc..eab4797 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -67,8 +67,8 @@ ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh glUniform(viewProjectionLoc, std::span {viewProjections * [extentsMat = glm::translate(glm::ortho(-size, size, -size, size, -size, size), -centre)]( - const auto & vp) { - return vp * extentsMat; - }}); + const auto & viewProjection) { + return viewProjection * extentsMat; + }}); mesh.Draw(); } diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h index ac83eb1..f774ac7 100644 --- a/gfx/gl/shadowStenciller.h +++ b/gfx/gl/shadowStenciller.h @@ -16,7 +16,7 @@ public: [[nodiscard]] static glTexture createStencilTexture(GLsizei width, GLsizei height); void setLightDirection(const LightDirection & lightDir); - void renderStencil(const glTexture &, const MeshBase &, const Texture::AnyPtr texture) const; + void renderStencil(const glTexture &, const MeshBase &, Texture::AnyPtr texture) const; private: glFrameBuffer fbo; -- cgit v1.2.3 From 5b6a6f3b241fea6d19521ddbb705e27d5e4c0268 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 20 Oct 2024 16:24:14 +0100 Subject: Move lots of maths helpers to inline, constexpr, templates Always for working with different dimensions/types --- assetFactory/mutation.cpp | 5 +- game/network/link.cpp | 2 +- game/network/network.cpp | 2 +- game/network/rail.cpp | 4 +- gfx/gl/shadowStenciller.cpp | 4 +- lib/maths.cpp | 97 --------------- lib/maths.h | 287 +++++++++++++++++++++++++++++++------------- test/test-geoData.cpp | 2 +- test/test-maths.cpp | 10 +- 9 files changed, 218 insertions(+), 195 deletions(-) diff --git a/assetFactory/mutation.cpp b/assetFactory/mutation.cpp index 6695dff..2ab2a76 100644 --- a/assetFactory/mutation.cpp +++ b/assetFactory/mutation.cpp @@ -1,12 +1,11 @@ #include "mutation.h" -#include #include #include Mutation::Matrix Mutation::getMatrix() const { - return glm::translate(glm::identity(), position) * rotate_ypr(rotation) + return glm::translate(glm::identity(), position) * rotate_ypr<4>(rotation) * glm::scale(glm::identity(), scale); } @@ -19,7 +18,7 @@ Mutation::getDeformationMatrix() const Mutation::Matrix Mutation::getLocationMatrix() const { - return glm::translate(glm::identity(), position) * rotate_ypr(rotation); + return glm::translate(glm::identity(), position) * rotate_ypr<4>(rotation); } bool diff --git a/game/network/link.cpp b/game/network/link.cpp index 248fe7d..745896c 100644 --- a/game/network/link.cpp +++ b/game/network/link.cpp @@ -51,7 +51,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const + RelativePosition3D {0, 0, static_cast(es.first->pos.z - centreBase.z) + (static_cast(es.second->pos.z - es.first->pos.z) * frac)}}; - const auto pitch {vector_pitch({0, 0, static_cast(es.second->pos.z - es.first->pos.z) / length})}; + const auto pitch {vector_pitch(difference(es.second->pos, es.first->pos) / length)}; return Location {GlobalPosition3D(relPos + relClimb) + centreBase, {pitch, normalize(ang + dirOffset[start]), 0}}; } diff --git a/game/network/network.cpp b/game/network/network.cpp index 65b2a62..fa86cb5 100644 --- a/game/network/network.cpp +++ b/game/network/network.cpp @@ -95,7 +95,7 @@ Network::routeFromTo(const Link::End & end, const Node::Ptr & dest) const GenCurveDef Network::genCurveDef(const GlobalPosition3D & start, const GlobalPosition3D & end, float startDir) { - const auto diff {end - start}; + const auto diff = difference(end, start); const auto vy {vector_yaw(diff)}; const auto dir = pi + startDir; const auto flatStart {start.xy()}, flatEnd {end.xy()}; diff --git a/game/network/rail.cpp b/game/network/rail.cpp index fd07ace..c29217a 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -32,7 +32,7 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) } // Find start link/end - opposite entry dir to existing link; so pi +... const Angle dir = pi + findNodeDirection(node1ins.first); - if (dir == vector_yaw(end - start)) { + if (dir == vector_yaw(difference(end, start))) { return addLink(start, end); } const auto flatStart {start.xy()}, flatEnd {end.xy()}; @@ -62,7 +62,7 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) return addLink(midh, end, c2); } } - const auto diff {end - start}; + const auto diff = difference(end, start); const auto vy {vector_yaw(diff)}; const auto n2ed {(vy * 2) - dir - pi}; const auto centre {find_arc_centre(flatStart, dir, flatEnd, n2ed)}; diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp index eab4797..86b77e4 100644 --- a/gfx/gl/shadowStenciller.cpp +++ b/gfx/gl/shadowStenciller.cpp @@ -24,8 +24,8 @@ ShadowStenciller::setLightDirection(const LightDirection & lightDir) { viewProjections = [&lightDir](std::integer_sequence) { constexpr float STEP = two_pi / STENCIL_ANGLES; - return std::array { - rotate_pitch(half_pi - lightDir.position().y) * rotate_yaw((Ep * STEP) - lightDir.position().x)...}; + return std::array {rotate_pitch<4>(half_pi - lightDir.position().y) + * rotate_yaw<4>((Ep * STEP) - lightDir.position().x)...}; }(std::make_integer_sequence>()); } diff --git a/lib/maths.cpp b/lib/maths.cpp index f527881..3a9bf9b 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -19,103 +19,6 @@ flat_orientation(const Direction3D & diff) return (std::isnan(e[0][0])) ? oneeighty : e; } -// Helper to lookup into a matrix given an xy vector coordinate -template -inline auto & -operator^(M & m, glm::vec<2, I> xy) -{ - return m[xy.x][xy.y]; -} - -// Create a matrix for the angle, given the targets into the matrix -template -inline auto -rotation(typename M::value_type a, glm::vec<2, I> c1, glm::vec<2, I> s1, glm::vec<2, I> c2, glm::vec<2, I> ms2) -{ - M m(1); - sincosf(a, m ^ s1, m ^ c1); - m ^ c2 = m ^ c1; - m ^ ms2 = -(m ^ s1); - return m; -} - -// Create a flat (2D) transformation matrix -glm::mat2 -rotate_flat(float a) -{ - return rotation(a, {0, 0}, {0, 1}, {1, 1}, {1, 0}); -} - -// Create a yaw transformation matrix -glm::mat4 -rotate_yaw(float a) -{ - return rotation(a, {0, 0}, {1, 0}, {1, 1}, {0, 1}); -} - -// Create a roll transformation matrix -glm::mat4 -rotate_roll(float a) -{ - return rotation(a, {0, 0}, {2, 0}, {2, 2}, {0, 2}); -} - -// Create a pitch transformation matrix -glm::mat4 -rotate_pitch(float a) -{ - return rotation(a, {1, 1}, {1, 2}, {2, 2}, {2, 1}); -} - -// Create a combined yaw, pitch, roll transformation matrix -glm::mat4 -rotate_ypr(Rotation3D a) -{ - return rotate_yaw(a.y) * rotate_pitch(a.x) * rotate_roll(a.z); -} - -glm::mat4 -rotate_yp(Rotation2D a) -{ - return rotate_yp(a.y, a.x); -} - -glm::mat4 -rotate_yp(Angle yaw, Angle pitch) -{ - return rotate_yaw(yaw) * rotate_pitch(pitch); -} - -float -vector_yaw(const Direction2D & diff) -{ - return std::atan2(diff.x, diff.y); -} - -float -vector_pitch(const Direction3D & diff) -{ - return std::atan(diff.z); -} - -float -round_frac(const float & v, const float & frac) -{ - return std::round(v / frac) * frac; -} - -float -normalize(float ang) -{ - while (ang > pi) { - ang -= two_pi; - } - while (ang <= -pi) { - ang += two_pi; - } - return ang; -} - static_assert(pow(1, 0) == 1); static_assert(pow(1, 1) == 1); static_assert(pow(1, 2) == 1); diff --git a/lib/maths.h b/lib/maths.h index 97b7ef5..94e357b 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -17,22 +17,22 @@ struct Arc : public std::pair { } Arc(const RelativePosition2D & dir0, const RelativePosition2D & dir1); - Arc(const Angle angb, const Angle anga); + Arc(Angle anga, Angle angb); auto - operator[](bool i) const + operator[](bool getSecond) const { - return i ? second : first; + return getSecond ? second : first; } - [[nodiscard]] constexpr inline float + [[nodiscard]] constexpr float length() const { return second - first; } }; -constexpr const RelativePosition3D up {0, 0, 1}; +constexpr const RelativePosition3D up {0, 0, 1}; // NOLINT(readability-identifier-length) constexpr const RelativePosition3D down {0, 0, -1}; constexpr const RelativePosition3D north {0, 1, 0}; constexpr const RelativePosition3D south {0, -1, 0}; @@ -40,7 +40,7 @@ constexpr const RelativePosition3D east {1, 0, 0}; constexpr const RelativePosition3D west {-1, 0, 0}; constexpr auto half_pi {glm::half_pi()}; constexpr auto quarter_pi {half_pi / 2}; -constexpr auto pi {glm::pi()}; +constexpr auto pi {glm::pi()}; // NOLINT(readability-identifier-length) constexpr auto two_pi {glm::two_pi()}; constexpr auto degreesToRads = pi / 180.F; @@ -48,153 +48,274 @@ constexpr auto earthMeanRadius = 6371.01F; // In km constexpr auto astronomicalUnit = 149597890.F; // In km template -constexpr inline GlobalPosition -operator+(const GlobalPosition & g, const RelativePosition & r) +constexpr GlobalPosition +operator+(const GlobalPosition & global, const RelativePosition & relative) { - return g + GlobalPosition(glm::round(r)); + return global + GlobalPosition(glm::round(relative)); } template -constexpr inline GlobalPosition -operator+(const GlobalPosition & g, const CalcPosition & r) +constexpr GlobalPosition +operator+(const GlobalPosition & global, const CalcPosition & relative) { - return g + GlobalPosition(r); + return global + GlobalPosition(relative); } template -constexpr inline GlobalPosition -operator-(const GlobalPosition & g, const RelativePosition & r) +constexpr GlobalPosition +operator-(const GlobalPosition & global, const RelativePosition & relative) { - return g - GlobalPosition(glm::round(r)); + return global - GlobalPosition(glm::round(relative)); } template -constexpr inline GlobalPosition -operator-(const GlobalPosition & g, const CalcPosition & r) +constexpr GlobalPosition +operator-(const GlobalPosition & global, const CalcPosition & relative) { - return g - GlobalPosition(r); + return global - GlobalPosition(relative); +} + +template +constexpr RelativePosition +difference(const glm::vec & globalA, const glm::vec & globalB) +{ + return globalA - globalB; } glm::mat4 flat_orientation(const Rotation3D & diff); -// C++ wrapper for C's sincosf, but with references, not pointers -inline auto -sincosf(float a, float & s, float & c) +namespace { + // Helpers + // C++ wrapper for C's sincosf, but with references, not pointers + constexpr auto + sincosf(float angle, float & sinOut, float & cosOut) + { + if consteval { + sinOut = ::sinf(angle); + cosOut = ::cosf(angle); + } + else { + ::sincosf(angle, &sinOut, &cosOut); + } + } + + template + constexpr auto + sincosf(const T angle) + { + Rotation2D sincosOut; + sincosf(angle, sincosOut.x, sincosOut.y); + return sincosOut; + } + + // Helper to lookup into a matrix given an xy vector coordinate + template + constexpr auto & + operator^(M & matrix, glm::vec<2, I> rowCol) + { + return matrix[rowCol.x][rowCol.y]; + } + + // Create a matrix for the angle, given the targets into the matrix + template + constexpr auto + rotation(typename M::value_type angle, glm::vec<2, I> cos1, glm::vec<2, I> sin1, glm::vec<2, I> cos2, + glm::vec<2, I> negSin1) + { + M out(1); + sincosf(angle, out ^ sin1, out ^ cos1); + out ^ cos2 = out ^ cos1; + out ^ negSin1 = -(out ^ sin1); + return out; + } +} + +// Create a flat transformation matrix +template + requires(D >= 2) +constexpr auto +rotate_flat(const T angle) { - return sincosf(a, &s, &c); + return rotation, glm::length_t>(angle, {0, 0}, {0, 1}, {1, 1}, {1, 0}); } -inline Rotation2D -sincosf(float a) +// Create a yaw transformation matrix +template + requires(D >= 2) +constexpr auto +rotate_yaw(const T angle) { - Rotation2D sc; - sincosf(a, sc.x, sc.y); - return sc; + return rotation, glm::length_t>(angle, {0, 0}, {1, 0}, {1, 1}, {0, 1}); } -glm::mat2 rotate_flat(float); -glm::mat4 rotate_roll(float); -glm::mat4 rotate_yaw(float); -glm::mat4 rotate_pitch(float); -glm::mat4 rotate_yp(Rotation2D); -glm::mat4 rotate_yp(Angle yaw, Angle pitch); -glm::mat4 rotate_ypr(Rotation3D); +// Create a roll transformation matrix +template + requires(D >= 3) +constexpr auto +rotate_roll(const T angle) +{ + return rotation, glm::length_t>(angle, {0, 0}, {2, 0}, {2, 2}, {0, 2}); +} -float vector_yaw(const Direction2D & diff); -float vector_pitch(const Direction3D & diff); +// Create a pitch transformation matrix +template + requires(D >= 3) +constexpr auto +rotate_pitch(const T angle) +{ + return rotation, glm::length_t>(angle, {1, 1}, {1, 2}, {2, 2}, {2, 1}); +} + +// Create a combined yaw, pitch, roll transformation matrix +template + requires(D >= 3) +constexpr auto +rotate_ypr(const glm::vec<3, T, Q> & angles) +{ + return rotate_yaw(angles.y) * rotate_pitch(angles.x) * rotate_roll(angles.z); +} + +template + requires(D >= 3) +constexpr auto +rotate_yp(const T yaw, const T pitch) +{ + return rotate_yaw(yaw) * rotate_pitch(pitch); +} + +template + requires(D >= 3) +constexpr auto +rotate_yp(const glm::vec<2, T, Q> & angles) +{ + return rotate_yp(angles.y, angles.x); +} + +template + requires(D >= 2) +constexpr auto +vector_yaw(const glm::vec & diff) +{ + return std::atan2(diff.x, diff.y); +} + +template + requires(D >= 3) +constexpr auto +vector_pitch(const glm::vec & diff) +{ + return std::atan(diff.z); +} template -glm::vec<2, T, Q> -vector_normal(const glm::vec<2, T, Q> & v) +constexpr glm::vec<2, T, Q> +vector_normal(const glm::vec<2, T, Q> & vector) { - return {-v.y, v.x}; + return {-vector.y, vector.x}; }; -float round_frac(const float & v, const float & frac); +template +constexpr auto +round_frac(const T value, const T frac) +{ + return std::round(value / frac) * frac; +} template -inline constexpr auto -sq(T v) + requires requires(T value) { value * value; } +constexpr auto +sq(T value) { - return v * v; + return value * value; } template -inline constexpr glm::vec<3, int64_t, Q> -crossProduct(const glm::vec<3, int64_t, Q> a, const glm::vec<3, int64_t, Q> b) +constexpr glm::vec<3, int64_t, Q> +crossProduct(const glm::vec<3, int64_t, Q> & valueA, const glm::vec<3, int64_t, Q> & valueB) { return { - (a.y * b.z) - (a.z * b.y), - (a.z * b.x) - (a.x * b.z), - (a.x * b.y) - (a.y * b.x), + (valueA.y * valueB.z) - (valueA.z * valueB.y), + (valueA.z * valueB.x) - (valueA.x * valueB.z), + (valueA.x * valueB.y) - (valueA.y * valueB.x), }; } template -inline constexpr glm::vec<3, T, Q> -crossProduct(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b) +constexpr glm::vec<3, T, Q> +crossProduct(const glm::vec<3, T, Q> & valueA, const glm::vec<3, T, Q> & valueB) { - return crossProduct(a, b); + return crossProduct(valueA, valueB); } template -inline constexpr glm::vec<3, T, Q> -crossProduct(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b) +constexpr glm::vec<3, T, Q> +crossProduct(const glm::vec<3, T, Q> & valueA, const glm::vec<3, T, Q> & valueB) { - return glm::cross(a, b); + return glm::cross(valueA, valueB); } template -inline constexpr auto -ratio(Ta a, Tb b) +constexpr auto +ratio(const Ta valueA, const Tb valueB) { - return (static_cast(a) / static_cast(b)); + return (static_cast(valueA) / static_cast(valueB)); } template -inline constexpr auto -ratio(glm::vec<2, T, Q> v) +constexpr auto +ratio(const glm::vec<2, T, Q> & value) { - return ratio(v.x, v.y); + return ratio(value.x, value.y); } -template -inline constexpr glm::vec -perspective_divide(glm::vec<4, T, Q> v) +template +constexpr auto +perspective_divide(const glm::vec<4, T, Q> & value) { - return v / v.w; + return value / value.w; } template -inline constexpr glm::vec -operator||(const glm::vec v1, const glm::vec v2) +constexpr glm::vec +operator||(const glm::vec valueA, const glm::vec valueB) { - return {v1, v2}; + return {valueA, valueB}; } template -inline constexpr glm::vec -operator||(const glm::vec v1, const T v2) +constexpr glm::vec +operator||(const glm::vec valueA, const T valueB) { - return {v1, v2}; + return {valueA, valueB}; } -template -inline constexpr glm::vec -perspectiveMultiply(const glm::vec & p, const glm::mat & mutation) +template +constexpr glm::vec +perspectiveMultiply(const glm::vec & base, const glm::mat & mutation) { - const auto p2 = mutation * (p || T(1)); - return p2 / p2.w; + const auto mutated = mutation * (base || T(1)); + return mutated / mutated.w; } -template -inline constexpr glm::vec -perspectiveApply(glm::vec & p, const glm::mat & mutation) +template +constexpr glm::vec +perspectiveApply(glm::vec & base, const glm::mat & mutation) { - return p = perspectiveMultiply(p, mutation); + return base = perspectiveMultiply(base, mutation); } -float normalize(float ang); +template +constexpr T +normalize(T ang) +{ + while (ang > glm::pi()) { + ang -= glm::two_pi(); + } + while (ang <= -glm::pi()) { + ang += glm::two_pi(); + } + return ang; +} template std::pair, bool> @@ -264,7 +385,7 @@ midpoint(const std::pair & v) // std::pow is not constexpr template requires requires(T n) { n *= n; } -constexpr inline T +constexpr T pow(const T base, std::integral auto exp) { T res {1}; @@ -276,14 +397,14 @@ pow(const T base, std::integral auto exp) // Conversions template -inline constexpr auto +constexpr auto mph_to_ms(T v) { return v / 2.237L; } template -inline constexpr auto +constexpr auto kph_to_ms(T v) { return v / 3.6L; diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 4a7b98d..35d6bae 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -168,7 +168,7 @@ BOOST_DATA_TEST_CASE(walkTerrainSetsFromFace, from, to, visits) { GeoData::PointFace pf {from}; - BOOST_CHECK_NO_THROW(fixedTerrtain.walk(pf, to, [](auto) {})); + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(pf, to, [](auto) { })); BOOST_CHECK_EQUAL(pf.face(&fixedTerrtain).idx(), visits.front()); } diff --git a/test/test-maths.cpp b/test/test-maths.cpp index ccfb113..f7f34b3 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -107,9 +107,9 @@ const auto angs = boost::unit_test::data::make({pi, half_pi, two_pi, quarter_pi, * boost::unit_test::data::make(0); const auto random_angs = boost::unit_test::data::random(-two_pi, two_pi) ^ boost::unit_test::data::xrange(1000); const auto rots = boost::unit_test::data::make>({ - {down, rotate_yaw, "yaw"}, - {east, rotate_pitch, "pitch"}, - {north, rotate_roll, "roll"}, + {down, rotate_yaw<4>, "yaw"}, + {east, rotate_pitch<4>, "pitch"}, + {north, rotate_roll<4>, "roll"}, }); BOOST_DATA_TEST_CASE(test_rotations, (angs + random_angs) * rots, angle, ai, axis, ilt_func, name) @@ -247,13 +247,13 @@ BOOST_DATA_TEST_CASE(curve1, BOOST_CHECK_EQUAL(l.radius, 1.F); { const auto p = l.positionAt(0, 0); - const auto angForReversed = normalize(vector_yaw(-e1) * 2 - angFor); + const auto angForReversed = normalize(vector_yaw(difference({}, e1)) * 2 - angFor); BOOST_CHECK_CLOSE_VECI(p.pos, e1); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angForReversed, 0)); } { const auto p = l.positionAt(0, 1); - const auto angBackReversed = normalize(vector_yaw(e1) * 2 - angBack); + const auto angBackReversed = normalize(vector_yaw(difference(e1, {})) * 2 - angBack); BOOST_CHECK_CLOSE_VECI(p.pos, GlobalPosition3D {}); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBackReversed, 0)); } -- cgit v1.2.3 From f84a4771f3efe642c0946ccd94a52ede27f1d997 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 20 Oct 2024 21:55:00 +0100 Subject: Randomise for many trees, positions, rotations --- application/main.cpp | 13 +++++++++++-- test/test-render.cpp | 33 +++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index d58cf6d..db42a63 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -24,6 +24,7 @@ #include #include // IWYU pragma: keep #include +#include #include #include #include @@ -79,10 +80,18 @@ public: &train->orders, l3->ends[1], l3->length, rl->findNodeAt({-1100000, -450000, 15000})); train->currentActivity = train->orders.current()->createActivity(); - auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); + std::random_device randomdev {}; + std::uniform_real_distribution rotationDistribution {0, two_pi}; + std::uniform_int_distribution positionOffsetDistribution {-1500, +1500}; + std::uniform_int_distribution treeDistribution {1, 3}; + std::uniform_int_distribution treeVariantDistribution {1, 4}; for (auto x = 311000000; x < 311830000; x += 5000) { for (auto y = 491100000; y < 491130000; y += 5000) { - world.create(foliage, Location {geoData->positionAt({{x, y}})}); + world.create(std::dynamic_pointer_cast(assets.at(std::format("Tree-{:#02}-{}", + treeDistribution(randomdev), treeVariantDistribution(randomdev)))), + Location {geoData->positionAt({{x + positionOffsetDistribution(randomdev), + y + positionOffsetDistribution(randomdev)}}), + {0, rotationDistribution(randomdev), 0}}); } } } diff --git a/test/test-render.cpp b/test/test-render.cpp index 775eb5c..3966f28 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -28,9 +28,7 @@ class TestScene : public SceneProvider { RailVehicleClassPtr brush47rvc; - std::shared_ptr tree021f; std::shared_ptr train1, train2; - std::shared_ptr plant1; RailLinks rail; std::shared_ptr gd = std::make_shared(GeoData::createFlat({0, 0}, {1000000, 1000000}, 1)); std::shared_ptr env = std::make_shared(); @@ -43,7 +41,11 @@ public: { gameState->assets = AssetFactory::loadAll(RESDIR); brush47rvc = std::dynamic_pointer_cast(gameState->assets.at("brush-47")); - tree021f = std::dynamic_pointer_cast(gameState->assets.at("Tree-02-1")); + std::random_device randomdev {}; + std::uniform_real_distribution rotationDistribution {0, two_pi}; + std::uniform_int_distribution positionOffsetDistribution {-1500, +1500}; + std::uniform_int_distribution treeDistribution {1, 3}; + std::uniform_int_distribution treeVariantDistribution {1, 4}; train1 = std::make_shared(brush47rvc); train1->location.setPosition({52000, 50000, 2000}); train1->bogies.front().setPosition(train1->bogies.front().position() + train1->location.position()); @@ -52,7 +54,16 @@ public: train2->location.setPosition({52000, 30000, 2000}); train2->bogies.front().setPosition(train2->bogies.front().position() + train2->location.position()); train2->bogies.back().setPosition(train2->bogies.back().position() + train2->location.position()); - plant1 = std::make_shared(tree021f, Location {{40000, 60000, 1}, {}}); + for (auto x = 40000; x < 100000; x += 5000) { + for (auto y = 65000; y < 125000; y += 5000) { + gameState->world.create( + std::dynamic_pointer_cast(gameState->assets.at(std::format( + "Tree-{:#02}-{}", treeDistribution(randomdev), treeVariantDistribution(randomdev)))), + Location {{x + positionOffsetDistribution(randomdev), y + positionOffsetDistribution(randomdev), + 1}, + {0, rotationDistribution(randomdev), 0}}); + } + } rail.addLinksBetween({42000, 50000, 1000}, {65000, 50000, 1000}); rail.addLinksBetween({65000, 50000, 1000}, {75000, 45000, 2000}); } @@ -62,9 +73,12 @@ public: { terrain.render(shader); water.render(shader); - brush47rvc->render(shader); - tree021f->render(shader); rail.render(shader); + std::ranges::for_each(gameState->assets, [&shader](const auto & asset) { + if (const auto renderable = std::dynamic_pointer_cast(asset.second)) { + renderable->render(shader); + } + }); } void @@ -82,8 +96,11 @@ public: shadows(const ShadowMapper & shadowMapper) const override { terrain.shadows(shadowMapper); - brush47rvc->shadows(shadowMapper); - tree021f->shadows(shadowMapper); + std::ranges::for_each(gameState->assets, [&shadowMapper](const auto & asset) { + if (const auto renderable = std::dynamic_pointer_cast(asset.second)) { + renderable->shadows(shadowMapper); + } + }); } }; -- cgit v1.2.3 From 56100b1c4cb02db7608763dddd77f8052a533dae Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 21 Oct 2024 18:30:16 +0100 Subject: Further template maths functions --- assetFactory/cylinder.cpp | 2 +- game/geoData.cpp | 2 +- game/network/link.cpp | 4 ++-- game/network/network.cpp | 8 +++---- game/network/rail.cpp | 8 +++---- gfx/followCameraController.cpp | 2 +- lib/maths.h | 53 ++++++++++++++++++++++++------------------ ui/manualCameraController.cpp | 2 +- 8 files changed, 45 insertions(+), 36 deletions(-) diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp index f41bfd4..432fb16 100644 --- a/assetFactory/cylinder.cpp +++ b/assetFactory/cylinder.cpp @@ -12,7 +12,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, Scale3D lodf) const // Generate 2D circumference points std::vector circumference(P); std::generate(circumference.begin(), circumference.end(), [a = 0.F, step]() mutable { - return sincosf(a += step) * .5F; + return sincos(a += step) * .5F; }); CreatedFaces surface; diff --git a/game/geoData.cpp b/game/geoData.cpp index 72aa056..d212651 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -559,7 +559,7 @@ GeoData::setHeights(const std::span triangleStrip, const const auto limit = std::ceil(arc.length() * 5.F / pi); const auto inc = arc.length() / limit; for (float step = 0; step <= limit; step += 1.F) { - addExtrusionFor(sincosf(arc.first + (step * inc))); + addExtrusionFor(sincos(arc.first + (step * inc))); } } else { diff --git a/game/network/link.cpp b/game/network/link.cpp index 745896c..79af92a 100644 --- a/game/network/link.cpp +++ b/game/network/link.cpp @@ -46,7 +46,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const const auto es {std::make_pair(ends[start].node.get(), ends[1 - start].node.get())}; const auto as {std::make_pair(arc[start], arc[1 - start])}; const auto ang {as.first + ((as.second - as.first) * frac)}; - const auto relPos {(sincosf(ang) || 0.F) * radius}; + const auto relPos {(sincos(ang) || 0.F) * radius}; const auto relClimb {vehiclePositionOffset() + RelativePosition3D {0, 0, static_cast(es.first->pos.z - centreBase.z) @@ -69,7 +69,7 @@ LinkCurve::intersectRay(const Ray & ray) const points.reserve(segCount); for (std::remove_const_t swing = {arc.first, centreBase.z - e0p.z}; segCount; swing += step, --segCount) { - points.emplace_back(centreBase + ((sincosf(swing.x) * radius) || swing.y)); + points.emplace_back(centreBase + ((sincos(swing.x) * radius) || swing.y)); } return ray.passesCloseToEdges(points, 1.F); } diff --git a/game/network/network.cpp b/game/network/network.cpp index fa86cb5..6ba3ed6 100644 --- a/game/network/network.cpp +++ b/game/network/network.cpp @@ -121,16 +121,16 @@ Network::genCurveDef(const GlobalPosition3D & start, const GlobalPosition3D & en }; if (const auto radii = find_arcs_radius(flatStart, startDir, flatEnd, endDir); radii.first < radii.second) { const auto radius {radii.first}; - const auto c1 = flatStart + (sincosf(startDir + half_pi) * radius); - const auto c2 = flatEnd + (sincosf(endDir + half_pi) * radius); + const auto c1 = flatStart + (sincos(startDir + half_pi) * radius); + const auto c2 = flatEnd + (sincos(endDir + half_pi) * radius); const auto mid = (c1 + c2) / 2; const auto midh = mid || midheight(mid); return {{start, midh, c1}, {end, midh, c2}}; } else { const auto radius {radii.second}; - const auto c1 = flatStart + (sincosf(startDir - half_pi) * radius); - const auto c2 = flatEnd + (sincosf(endDir - half_pi) * radius); + const auto c1 = flatStart + (sincos(startDir - half_pi) * radius); + const auto c2 = flatEnd + (sincos(endDir - half_pi) * radius); const auto mid = (c1 + c2) / 2; const auto midh = mid || midheight(mid); return {{midh, start, c1}, {midh, end, c2}}; diff --git a/game/network/rail.cpp b/game/network/rail.cpp index c29217a..6f04070 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -45,8 +45,8 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) const float dir2 = pi + findNodeDirection(node2ins.first); if (const auto radii = find_arcs_radius(flatStart, dir, flatEnd, dir2); radii.first < radii.second) { const auto radius {radii.first}; - const auto c1 = flatStart + (sincosf(dir + half_pi) * radius); - const auto c2 = flatEnd + (sincosf(dir2 + half_pi) * radius); + const auto c1 = flatStart + (sincos(dir + half_pi) * radius); + const auto c2 = flatEnd + (sincos(dir2 + half_pi) * radius); const auto mid = (c1 + c2) / 2; const auto midh = mid || midheight(mid); addLink(start, midh, c1); @@ -54,8 +54,8 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) } else { const auto radius {radii.second}; - const auto c1 = flatStart + (sincosf(dir - half_pi) * radius); - const auto c2 = flatEnd + (sincosf(dir2 - half_pi) * radius); + const auto c1 = flatStart + (sincos(dir - half_pi) * radius); + const auto c2 = flatEnd + (sincos(dir2 - half_pi) * radius); const auto mid = (c1 + c2) / 2; const auto midh = mid || midheight(mid); addLink(midh, start, c1); diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp index 52dfb35..cf6da34 100644 --- a/gfx/followCameraController.cpp +++ b/gfx/followCameraController.cpp @@ -24,7 +24,7 @@ FollowCameraController::updateCamera(Camera * camera) const break; case Mode::Ride: - camera->setView(pos + (up * 4.8F), -sincosf(rot.y) || 0.F); + camera->setView(pos + (up * 4.8F), -sincos(rot.y) || 0.F); break; case Mode::ISO: diff --git a/lib/maths.h b/lib/maths.h index 94e357b..90ddb69 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -87,43 +87,52 @@ glm::mat4 flat_orientation(const Rotation3D & diff); namespace { // Helpers // C++ wrapper for C's sincosf, but with references, not pointers - constexpr auto - sincosf(float angle, float & sinOut, float & cosOut) + template + constexpr void + sincos(T angle, T & sinOut, T & cosOut) { if consteval { - sinOut = ::sinf(angle); - cosOut = ::cosf(angle); + sinOut = std::sin(angle); + cosOut = std::cos(angle); } else { - ::sincosf(angle, &sinOut, &cosOut); + if constexpr (std::is_same_v) { + ::sincosf(angle, &sinOut, &cosOut); + } + else if constexpr (std::is_same_v) { + ::sincos(angle, &sinOut, &cosOut); + } + else if constexpr (std::is_same_v) { + ::sincosl(angle, &sinOut, &cosOut); + } } } - template + template constexpr auto - sincosf(const T angle) + sincos(const T angle) { - Rotation2D sincosOut; - sincosf(angle, sincosOut.x, sincosOut.y); + glm::vec<2, T, Q> sincosOut {}; + sincos(angle, sincosOut.x, sincosOut.y); return sincosOut; } // Helper to lookup into a matrix given an xy vector coordinate - template + template constexpr auto & - operator^(M & matrix, glm::vec<2, I> rowCol) + operator^(glm::mat & matrix, const glm::vec<2, I> rowCol) { return matrix[rowCol.x][rowCol.y]; } // Create a matrix for the angle, given the targets into the matrix - template + template constexpr auto - rotation(typename M::value_type angle, glm::vec<2, I> cos1, glm::vec<2, I> sin1, glm::vec<2, I> cos2, - glm::vec<2, I> negSin1) + rotation(const T angle, const glm::vec<2, I> cos1, const glm::vec<2, I> sin1, const glm::vec<2, I> cos2, + const glm::vec<2, I> negSin1) { - M out(1); - sincosf(angle, out ^ sin1, out ^ cos1); + glm::mat out(1); + sincos(angle, out ^ sin1, out ^ cos1); out ^ cos2 = out ^ cos1; out ^ negSin1 = -(out ^ sin1); return out; @@ -136,7 +145,7 @@ template, glm::length_t>(angle, {0, 0}, {0, 1}, {1, 1}, {1, 0}); + return rotation(angle, {0, 0}, {0, 1}, {1, 1}, {1, 0}); } // Create a yaw transformation matrix @@ -145,7 +154,7 @@ template, glm::length_t>(angle, {0, 0}, {1, 0}, {1, 1}, {0, 1}); + return rotation(angle, {0, 0}, {1, 0}, {1, 1}, {0, 1}); } // Create a roll transformation matrix @@ -154,7 +163,7 @@ template, glm::length_t>(angle, {0, 0}, {2, 0}, {2, 2}, {0, 2}); + return rotation(angle, {0, 0}, {2, 0}, {2, 2}, {0, 2}); } // Create a pitch transformation matrix @@ -163,7 +172,7 @@ template, glm::length_t>(angle, {1, 1}, {1, 2}, {2, 2}, {2, 1}); + return rotation(angle, {1, 1}, {1, 2}, {2, 2}, {2, 1}); } // Create a combined yaw, pitch, roll transformation matrix @@ -337,7 +346,7 @@ find_arc_centre(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, An if (start == end) { return {start, false}; } - return find_arc_centre(start, sincosf(entrys + half_pi), end, sincosf(entrye - half_pi)); + return find_arc_centre(start, sincos(entrys + half_pi), end, sincos(entrye - half_pi)); } template @@ -370,7 +379,7 @@ std::pair find_arcs_radius(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye) { const auto getrad = [&](auto leftOrRight) { - return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight)); + return find_arcs_radius(start, sincos(entrys + leftOrRight), end, sincos(entrye + leftOrRight)); }; return {getrad(-half_pi), getrad(half_pi)}; } diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp index 065e1d8..53905eb 100644 --- a/ui/manualCameraController.cpp +++ b/ui/manualCameraController.cpp @@ -79,6 +79,6 @@ ManualCameraController::render(const UIShader &, const Position &) const void ManualCameraController::updateCamera(Camera * camera) const { - const auto forward = glm::normalize(sincosf(direction) || -sin(pitch)); + const auto forward = glm::normalize(sincos(direction) || -sin(pitch)); camera->setView((focus || 0) - (forward * 3.F * std::pow(dist, 1.3F)), forward); } -- cgit v1.2.3