diff options
| author | Dan Goodliffe <dan.goodliffe@octal.co.uk> | 2026-02-18 17:14:31 +0000 |
|---|---|---|
| committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2026-02-18 19:02:27 +0000 |
| commit | d8464a28c6066931dd638653e2a082e2640191dc (patch) | |
| tree | 18134e3ee51c9fd423b9395b90c3f19b6e54cfc3 | |
| parent | Add Renderable::preFrame for doing non-const frame prep work (diff) | |
| download | ilt-d8464a28c6066931dd638653e2a082e2640191dc.tar.bz2 ilt-d8464a28c6066931dd638653e2a082e2640191dc.tar.xz ilt-d8464a28c6066931dd638653e2a082e2640191dc.zip | |
Fix up the preFrame process to use both frustums
(camera and directional light frustums)
This has made the whole preFrame process far more fiddly and repetitive
than I'd like, but it does work. Maybe we can tidy it up later.
| -rw-r--r-- | application/resviewer.cpp | 17 | ||||
| -rw-r--r-- | game/environment.cpp | 8 | ||||
| -rw-r--r-- | game/environment.h | 1 | ||||
| -rw-r--r-- | gfx/gl/sceneRenderer.cpp | 6 | ||||
| -rw-r--r-- | gfx/gl/sceneRenderer.h | 1 | ||||
| -rw-r--r-- | gfx/gl/shadowMapper.cpp | 60 | ||||
| -rw-r--r-- | gfx/gl/shadowMapper.h | 7 | ||||
| -rw-r--r-- | gfx/renderable.cpp | 2 | ||||
| -rw-r--r-- | gfx/renderable.h | 2 | ||||
| -rw-r--r-- | test/test-assetFactory.cpp | 7 | ||||
| -rw-r--r-- | test/test-render.cpp | 8 | ||||
| -rw-r--r-- | ui/gameMainWindow.cpp | 5 |
12 files changed, 88 insertions, 36 deletions
diff --git a/application/resviewer.cpp b/application/resviewer.cpp index e0c36f6..0e34c05 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -44,8 +44,9 @@ private: void render() override { + const auto & [camFrust, lightFrust] = preFrame(gameState->environment->getSunPos()); SceneRenderer::render(*this); - controls(); + controls(camFrust, lightFrust); } void @@ -89,12 +90,12 @@ private: } void - controls() + controls(const Frustum & camFrust, const Frustum & lightFrust) { if (ImGui::Begin("Resource view")) { ImGui::SetWindowSize({}); fileSelection(); - assetSelection(); + assetSelection(camFrust, lightFrust); } ImGui::End(); @@ -130,7 +131,7 @@ private: } void - assetSelection() + assetSelection(const Frustum & camFrust, const Frustum & lightFrust) { if (!gameState->assets.empty()) { ImGui::BeginListBox("Asset"); @@ -141,7 +142,7 @@ private: selectedAssetId = asset.first; selectedAsset = renderable; location = asset.second->createAt(position); - renderable->preFrame(camera); + renderable->preFrame(camFrust, lightFrust); } } } @@ -175,6 +176,12 @@ private: } } + void + environment(const SceneShader &, const SceneRenderer & renderer) const override + { + gameState->environment->render(renderer, *this); + } + std::span<const std::filesystem::path> fileList; std::filesystem::file_time_type fileTime; const std::filesystem::path * selectedFile {}; diff --git a/game/environment.cpp b/game/environment.cpp index acb4f21..1ef6e22 100644 --- a/game/environment.cpp +++ b/game/environment.cpp @@ -11,13 +11,19 @@ Environment::tick(TickDuration) worldTime += 50; } +Direction2D +Environment::getSunPos() const +{ + return getSunPos({}, worldTime); +} + void Environment::render(const SceneRenderer & renderer, const SceneProvider & scene) const { 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 LightDirection sunPos = getSunPos({}, worldTime); + const LightDirection sunPos = getSunPos(); const auto ambient = baseAmbient + relativeAmbient * sunPos.ambient(); const auto directional = baseDirectional + relativeDirectional * sunPos.directional(); diff --git a/game/environment.h b/game/environment.h index a6f3036..6a2e1ad 100644 --- a/game/environment.h +++ b/game/environment.h @@ -11,6 +11,7 @@ public: Environment(); void tick(TickDuration elapsed) override; void render(const SceneRenderer &, const SceneProvider &) const; + Direction2D getSunPos() const; static Direction2D getSunPos(const Direction2D position, const time_t time); private: diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 5e8241f..d005dfa 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -77,6 +77,12 @@ SceneRenderer::resize(ScreenAbsCoord newSize) shader.setViewPort({0, 0, size.x, size.y}); } +std::pair<const Frustum &, const Frustum &> +SceneRenderer::preFrame(const LightDirection & lightDirection) +{ + return {camera, shadowMapper.preFrame(lightDirection, camera)}; +} + void SceneRenderer::render(const SceneProvider & scene) const { diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index 05921a1..2ec8057 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -18,6 +18,7 @@ public: void resize(ScreenAbsCoord size); void render(const SceneProvider &) const; + std::pair<const Frustum &, const Frustum &> preFrame(const LightDirection &); void setAmbientLight(const RGB & colour) const; void setDirectionalLight(const RGB & colour, const LightDirection & direction, const SceneProvider &) const; diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 7035162..a73caa0 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -31,7 +31,7 @@ ShadowMapper::ShadowMapper(const TextureAbsCoord & s) : landmess {shadowLandmass_vert}, dynamicPointInst {shadowDynamicPointInst_vert}, dynamicPointInstWithTextures {shadowDynamicPointInstWithTextures_vert, shadowDynamicPointInstWithTextures_geom, shadowDynamicPointInstWithTextures_frag}, - size {s} + size {s}, frustum {{}, {}, {}} { glDebugScope _ {depthMap}; glBindTexture(GL_TEXTURE_2D_ARRAY, depthMap); @@ -82,6 +82,37 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV return bandViewExtents; } +const Frustum & +ShadowMapper::preFrame(const LightDirection & dir, const Camera & camera) +{ + const auto lightViewDir = glm::lookAt({}, dir.vector(), up); + const auto lightViewPoint = camera.getPosition(); + const auto bandViewExtents = getBandViewExtents(camera, lightViewDir); + using ExtentsBoundingBox = AxisAlignedBoundingBox<RelativeDistance>; + definitions.clear(); + sizes.clear(); + std::ranges::transform(bandViewExtents | std::views::pairwise, std::back_inserter(definitions), + [&lightViewDir, this](const auto & band) mutable { + const auto & [near, far] = band; + auto extents = ExtentsBoundingBox::fromPoints(std::span {near.begin(), far.end()}); + extents.min.z -= 10'000.F; + extents.max.z += 10'000.F; + const auto lightProjection = glm::ortho( + extents.min.x, extents.max.x, extents.min.y, extents.max.y, -extents.max.z, -extents.min.z); + sizes.emplace_back(extents.max - extents.min); + return lightProjection * lightViewDir; + }); + + ExtentsBoundingBox extents {lightViewPoint, lightViewPoint}; + for (const auto & point : bandViewExtents.back()) { + extents += point; + } + const auto lightProjection + = glm::ortho(extents.min.x, extents.max.x, extents.min.y, extents.max.y, -extents.max.z, -extents.min.z); + frustum = {lightViewPoint, lightViewDir, lightProjection}; + return frustum; +} + ShadowMapper::Definitions ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, const Camera & camera) const { @@ -100,39 +131,16 @@ ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, co glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, size.x, size.y); - const auto lightViewDir = glm::lookAt({}, dir.vector(), up); const auto lightViewPoint = camera.getPosition(); - const auto bandViewExtents = getBandViewExtents(camera, lightViewDir); - Definitions out; - Sizes sizes; - using ExtentsBoundingBox = AxisAlignedBoundingBox<RelativeDistance>; - std::ranges::transform(bandViewExtents | std::views::pairwise, std::back_inserter(out), - [&lightViewDir, &sizes](const auto & band) mutable { - const auto & [near, far] = band; - auto extents = ExtentsBoundingBox::fromPoints(std::span {near.begin(), far.end()}); - extents.min.z -= 10'000.F; - extents.max.z += 10'000.F; - const auto lightProjection = glm::ortho( - extents.min.x, extents.max.x, extents.min.y, extents.max.y, -extents.max.z, -extents.min.z); - sizes.emplace_back(extents.max - extents.min); - return lightProjection * lightViewDir; - }); for (const auto p : std::initializer_list<const ShadowProgram *> { &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures, &stencilShadowProgram}) { - p->setView(out, sizes, lightViewPoint); - } - ExtentsBoundingBox extents {lightViewPoint, lightViewPoint}; - for (const auto & point : bandViewExtents.back()) { - extents += point; + p->setView(definitions, sizes, lightViewPoint); } - const auto lightProjection - = glm::ortho(extents.min.x, extents.max.x, extents.min.y, extents.max.y, -extents.max.z, -extents.min.z); - Frustum frustum {lightViewPoint, lightViewDir, lightProjection}; scene.shadows(*this, frustum); glCullFace(GL_BACK); - return out; + return definitions; } ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs) : Program {vs, commonShadowPoint_geom} { } diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index 951e29c..82374cb 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -1,6 +1,7 @@ #pragma once #include "config/types.h" +#include "gfx/frustum.h" #include "gfx/gl/shadowStenciller.h" #include "lib/glArrays.h" #include "program.h" @@ -22,6 +23,7 @@ public: using Definitions = std::vector<glm::mat4x4>; using Sizes = std::vector<RelativePosition3D>; + const Frustum & preFrame(const LightDirection & direction, const Camera &); [[nodiscard]] Definitions update(const SceneProvider &, const LightDirection & direction, const Camera &) const; class ShadowProgram : public Program { @@ -77,5 +79,10 @@ private: glFrameBuffer depthMapFBO; glTexture depthMap; TextureAbsCoord size; + + Definitions definitions; + Sizes sizes; + Frustum frustum; + mutable ShadowStenciller shadowStenciller; }; diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp index 7df5851..9fbc85b 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -1,7 +1,7 @@ #include "renderable.h" void -Renderable::preFrame(const Frustum &) +Renderable::preFrame(const Frustum &, const Frustum &) { } diff --git a/gfx/renderable.h b/gfx/renderable.h index d7f593a..ea72bb6 100644 --- a/gfx/renderable.h +++ b/gfx/renderable.h @@ -13,7 +13,7 @@ public: virtual ~Renderable() = default; DEFAULT_MOVE_COPY(Renderable); - virtual void preFrame(const Frustum &); + virtual void preFrame(const Frustum &, const Frustum &); virtual void render(const SceneShader & shader, const Frustum &) const = 0; virtual void lights(const SceneShader & shader) const; virtual void shadows(const ShadowMapper & shadowMapper, const Frustum &) const; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index ac7e04c..ff38369 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -72,6 +72,13 @@ namespace { render(float dist) { sceneRenderer.camera.setView({-dist, dist * 1.2F, dist * 1.2F}, south + east + down); + const auto & [camFrust, lightFrust] = sceneRenderer.preFrame({{0.9, 0.5}}); + for (const auto & [assetId, asset] : gameState.assets) { + if (const auto renderable = asset.getAs<Renderable>()) { + renderable->preFrame(camFrust, lightFrust); + } + } + gameState.world.apply<Renderable>(&Renderable::preFrame, camFrust, lightFrust); sceneRenderer.render(*this); } diff --git a/test/test-render.cpp b/test/test-render.cpp index 073239f..ac71276 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -162,6 +162,13 @@ BOOST_AUTO_TEST_CASE(Basic) TestSceneRenderer renderer {size, output}; renderer.camera.setView({-10000, -10000, 60000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); const TestScene scene; + const auto & [camFrust, lightFrust] = renderer.preFrame(gameState.environment->getSunPos()); + for (const auto & [assetId, asset] : gameState.assets) { + if (const auto renderable = asset.getAs<Renderable>()) { + renderable->preFrame(camFrust, lightFrust); + } + } + gameState.world.apply<Renderable>(&Renderable::preFrame, camFrust, lightFrust); renderer.render(scene); renderer.saveBuffers(ANALYSIS_DIRECTORY / "basic"); Texture::save(outImage, (ANALYSIS_DIRECTORY / "basic/final.tga").c_str()); @@ -203,6 +210,7 @@ BOOST_AUTO_TEST_CASE(TerrainSD19) } }; + renderer.preFrame(gameState.environment->getSunPos()); renderer.render(TestTerrain {}); Texture::save(outImage, (ANALYSIS_DIRECTORY / "terrain.tga").c_str()); } diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index eec5512..9f224a2 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -85,12 +85,13 @@ GameMainWindow::handleInput(const SDL_Event & event) void GameMainWindow::render() { + const auto & [camFrust, lightFrust] = SceneRenderer::preFrame(gameState->environment->getSunPos()); for (const auto & [assetId, asset] : gameState->assets) { if (const auto renderable = asset.getAs<Renderable>()) { - renderable->preFrame(camera); + renderable->preFrame(camFrust, lightFrust); } } - gameState->world.apply<const Renderable>(&Renderable::preFrame, camera); + gameState->world.apply<const Renderable>(&Renderable::preFrame, camFrust, lightFrust); SceneRenderer::render(*this); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
