summaryrefslogtreecommitdiff
path: root/gfx
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2024-09-23 20:12:48 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2024-09-23 20:12:48 +0100
commitdbbfd39eef3b4d063ab7cdeb8d139b1bc11ba72c (patch)
tree0a880b2d14ac152014649d32088b73f17bf77297 /gfx
parentMerge branch 'sunpos' (diff)
parentPopulate all layers of shadow stencil with view from all around (diff)
downloadilt-dbbfd39eef3b4d063ab7cdeb8d139b1bc11ba72c.tar.bz2
ilt-dbbfd39eef3b4d063ab7cdeb8d139b1bc11ba72c.tar.xz
ilt-dbbfd39eef3b4d063ab7cdeb8d139b1bc11ba72c.zip
Psycho-rebased branch billboard-shadows on top of main
Diffstat (limited to 'gfx')
-rw-r--r--gfx/gl/program.h6
-rw-r--r--gfx/gl/sceneRenderer.cpp20
-rw-r--r--gfx/gl/sceneShader.cpp2
-rw-r--r--gfx/gl/shaders/shadowDynamicPointStencil.fs16
-rw-r--r--gfx/gl/shaders/shadowDynamicPointStencil.gs33
-rw-r--r--gfx/gl/shaders/shadowDynamicPointStencil.vs17
-rw-r--r--gfx/gl/shaders/shadowStencil.fs18
-rw-r--r--gfx/gl/shaders/shadowStencil.gs28
-rw-r--r--gfx/gl/shaders/shadowStencil.vs20
-rw-r--r--gfx/gl/shadowMapper.cpp59
-rw-r--r--gfx/gl/shadowMapper.h18
-rw-r--r--gfx/gl/shadowStenciller.cpp77
-rw-r--r--gfx/gl/shadowStenciller.h24
-rw-r--r--gfx/models/mesh.cpp28
-rw-r--r--gfx/models/mesh.h30
-rw-r--r--gfx/models/texture.cpp9
-rw-r--r--gfx/models/texture.h2
-rw-r--r--gfx/renderable.cpp5
-rw-r--r--gfx/renderable.h3
19 files changed, 390 insertions, 25 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/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/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/shaders/shadowDynamicPointStencil.fs b/gfx/gl/shaders/shadowDynamicPointStencil.fs
new file mode 100644
index 0000000..e612691
--- /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 sampler2DArray stencilDepth;
+flat in vec3 scale;
+in vec3 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..b91937d
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointStencil.gs
@@ -0,0 +1,33 @@
+#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 vec3 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);
+ gl_Position.z = max(gl_Position.z, -1);
+ texCoord = vec3((corners[c] * 0.5) + 0.5, 0);
+ 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/shaders/shadowStencil.fs b/gfx/gl/shaders/shadowStencil.fs
new file mode 100644
index 0000000..1164cc9
--- /dev/null
+++ b/gfx/gl/shaders/shadowStencil.fs
@@ -0,0 +1,18 @@
+#version 330 core
+#extension GL_ARB_shading_language_420pack : enable
+
+layout(binding = 0) uniform sampler2D textureAlbedo;
+
+include(`materialDetail.glsl')
+include(`materialCommon.glsl')
+in vec2 gTexCoords;
+flat in MaterialDetail gMaterial;
+
+void
+main()
+{
+ 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..2c3f9bd
--- /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[8];
+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 < viewProjection.length(); ++gl_Layer) {
+ for (int v = 0; v < FragPos.length(); ++v) {
+ gl_Position = viewProjection[gl_Layer] * 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
new file mode 100644
index 0000000..a15c4fb
--- /dev/null
+++ b/gfx/gl/shaders/shadowStencil.vs
@@ -0,0 +1,20 @@
+#version 330 core
+#extension GL_ARB_shading_language_420pack : enable
+
+layout(binding = 1) uniform usampler2DRect materialData;
+
+include(`meshIn.glsl')
+include(`materialDetail.glsl')
+include(`getMaterialDetail.glsl')
+
+out vec3 FragPos;
+out vec2 TexCoords;
+flat out MaterialDetail Material;
+
+void
+main()
+{
+ TexCoords = texCoord;
+ Material = getMaterialDetail(material);
+ FragPos = position;
+}
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index a846a3d..b08538d 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -1,13 +1,19 @@
#include "shadowMapper.h"
#include "camera.h"
#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"
#include "gl_traits.h"
#include "location.h"
#include "maths.h"
@@ -74,32 +80,47 @@ 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.setLightDirection(dir, up);
+ for (const auto & [id, asset] : gameState->assets) {
+ if (const auto r = std::dynamic_pointer_cast<const Renderable>(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);
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 {
- 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));
- };
+ [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, 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);
- }(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<const ShadowProgram *> {
- &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures}) {
- p->setView(out, lightViewPoint);
+ &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures, &stencilShadowProgram}) {
+ p->setView(out, sizes, lightViewPoint);
}
scene.shadows(*this);
@@ -116,12 +137,15 @@ ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs, const Shader & gs,
}
void
-ShadowMapper::ShadowProgram::setView(
- const std::span<const glm::mat4> viewProjection, const GlobalPosition3D viewPoint) const
+ShadowMapper::ShadowProgram::setView(const std::span<const glm::mat4x4> viewProjection,
+ const std::span<const RelativePosition3D> sizes, const GlobalPosition3D viewPoint) const
{
use();
glUniform(viewPointLoc, viewPoint);
glUniform(viewProjectionLoc, viewProjection);
+ if (sizesLoc) {
+ glUniform(sizesLoc, sizes);
+ }
glUniform(viewProjectionsLoc, static_cast<GLint>(viewProjection.size()));
}
@@ -146,3 +170,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 73dadd0..3aa224e 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 <gfx/models/texture.h>
@@ -18,6 +19,7 @@ public:
static constexpr std::size_t SHADOW_BANDS {4};
using Definitions = std::vector<glm::mat4x4>;
+ using Sizes = std::vector<RelativePosition3D>;
[[nodiscard]] Definitions update(const SceneProvider &, const Direction3D & direction, const Camera &) const;
@@ -26,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 glm::mat4>, const GlobalPosition3D) const;
+ void setView(const std::span<const glm::mat4x4>, const std::span<const RelativePosition3D>,
+ const GlobalPosition3D) const;
void use() const;
private:
RequiredUniformLocation viewProjectionLoc {*this, "viewProjection"};
RequiredUniformLocation viewProjectionsLoc {*this, "viewProjections"};
+ UniformLocation sizesLoc {*this, "sizes"};
RequiredUniformLocation viewPointLoc {*this, "viewPoint"};
};
@@ -46,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
@@ -61,4 +76,5 @@ private:
glFrameBuffer depthMapFBO;
glTexture depthMap;
TextureAbsCoord size;
+ mutable ShadowStenciller shadowStenciller;
};
diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp
new file mode 100644
index 0000000..da2b3a0
--- /dev/null
+++ b/gfx/gl/shadowStenciller.cpp
@@ -0,0 +1,77 @@
+#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 "maths.h"
+#include <stdexcept>
+
+namespace {
+ static constexpr std::array<float, 8> 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);
+ glReadBuffer(GL_NONE);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void
+ShadowStenciller::setLightDirection(const Direction3D & lightDir, const Direction3D & lightDirUp)
+{
+ lightDirMat = glm::lookAt(-lightDir, {}, lightDirUp);
+ viewProjections = angles * [this](const auto & a) {
+ return lightDirMat * a;
+ };
+}
+
+glTexture
+ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height)
+{
+ glTexture stencil;
+ glBindTexture(GL_TEXTURE_2D_ARRAY, stencil);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ 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);
+
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, width, height, 8, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,
+ nullptr);
+
+ return stencil;
+}
+
+void
+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);
+ 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<const glm::mat4> {viewProjections * [&](const auto & vp) {
+ return extentsMat * vp;
+ }});
+ mesh.Draw();
+}
diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h
new file mode 100644
index 0000000..2edb955
--- /dev/null
+++ b/gfx/gl/shadowStenciller.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "gfx/gl/program.h"
+#include "gfx/models/mesh.h"
+#include "gfx/models/texture.h"
+#include "glArrays.h"
+
+class ShadowStenciller {
+public:
+ 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;
+ Program::RequiredUniformLocation viewProjectionLoc {shadowCaster, "viewProjection"};
+
+ glm::mat4 lightDirMat {};
+ std::array<glm::mat4, 8> viewProjections;
+};
diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp
index e7474ca..2eae160 100644
--- a/gfx/models/mesh.cpp
+++ b/gfx/models/mesh.cpp
@@ -1,6 +1,32 @@
#include "mesh.h"
-MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode) : m_numIndices {m_numIndices}, mode {mode} { }
+MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode, const std::vector<RelativePosition3D> & positions) :
+ m_numIndices {m_numIndices}, mode {mode}, dimensions {positions}
+{
+}
+
+MeshBase::Dimensions::Dimensions(const std::span<const RelativePosition3D> positions) :
+ Dimensions {positions, {extents(positions, 0), extents(positions, 1), extents(positions, 2)}}
+{
+}
+
+MeshBase::Dimensions::Dimensions(
+ const std::span<const RelativePosition3D> positions, const std::array<Extents1D, 3> & 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<const RelativePosition3D> 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 248cb8f..8791aed 100644
--- a/gfx/models/mesh.h
+++ b/gfx/models/mesh.h
@@ -1,8 +1,10 @@
#pragma once
+#include "config/types.h"
#include "gfx/gl/vertexArrayObject.h"
#include <glArrays.h>
#include <glad/gl.h>
+#include <ranges>
#include <span>
#include <stdTypeDefs.h>
@@ -10,22 +12,46 @@ class Vertex;
class MeshBase {
public:
+ class Dimensions {
+ public:
+ using Extents1D = std::ranges::minmax_result<RelativeDistance>;
+ explicit Dimensions(const std::span<const RelativePosition3D>);
+
+ RelativePosition3D minExtent, maxExtent;
+ RelativePosition3D centre;
+ RelativeDistance size;
+
+ private:
+ Dimensions(const std::span<const RelativePosition3D>, const std::array<Extents1D, 3> &);
+ static Extents1D extents(const std::span<const RelativePosition3D>, glm::length_t D);
+ };
+
void Draw() const;
void DrawInstanced(GLuint vao, GLsizei count, GLuint base = 0) const;
+ [[nodiscard]] const Dimensions &
+ getDimensions() const
+ {
+ return dimensions;
+ }
+
protected:
- MeshBase(GLsizei m_numIndices, GLenum mode);
+ MeshBase(GLsizei m_numIndices, GLenum mode, const std::vector<RelativePosition3D> &);
glVertexArray m_vertexArrayObject;
glBuffers<2> m_vertexArrayBuffers;
GLsizei m_numIndices;
GLenum mode;
+ Dimensions dimensions;
};
template<typename V> class MeshT : public MeshBase, public ConstTypeDefs<MeshT<V>> {
public:
MeshT(const std::span<const V> vertices, const std::span<const unsigned int> indices, GLenum mode = GL_TRIANGLES) :
- MeshBase {static_cast<GLsizei>(indices.size()), mode}
+ MeshBase {static_cast<GLsizei>(indices.size()), mode,
+ materializeRange(vertices | std::views::transform([](const auto & v) {
+ return static_cast<RelativePosition3D>(v.pos);
+ }))}
{
VertexArrayObject::data(vertices, m_vertexArrayBuffers[0], GL_ARRAY_BUFFER);
VertexArrayObject::data(indices, m_vertexArrayBuffers[1], GL_ARRAY_BUFFER);
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_t>(size.x * size.y * channels));
+ const size_t dataSize = (static_cast<size_t>(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<TGAHead>() = {
.format = tgaFormat,
- .size = size,
+ .size = {size.x, size.y * size.z},
.pixelDepth = static_cast<uint8_t>(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;
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;
};