diff options
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/aabb.h | 41 | ||||
-rw-r--r-- | gfx/camera.cpp | 2 | ||||
-rw-r--r-- | gfx/camera.h | 7 | ||||
-rw-r--r-- | gfx/frustum.cpp | 43 | ||||
-rw-r--r-- | gfx/frustum.h | 16 | ||||
-rw-r--r-- | gfx/gl/sceneProvider.cpp | 2 | ||||
-rw-r--r-- | gfx/gl/sceneProvider.h | 5 | ||||
-rw-r--r-- | gfx/gl/sceneRenderer.cpp | 2 | ||||
-rw-r--r-- | gfx/gl/shadowMapper.cpp | 40 | ||||
-rw-r--r-- | gfx/renderable.cpp | 2 | ||||
-rw-r--r-- | gfx/renderable.h | 5 |
11 files changed, 126 insertions, 39 deletions
diff --git a/gfx/aabb.h b/gfx/aabb.h new file mode 100644 index 0000000..ce15a0f --- /dev/null +++ b/gfx/aabb.h @@ -0,0 +1,41 @@ +#pragma once + +#include "maths.h" +#include <algorithm> +#include <tuple> + +template<Arithmetic T, glm::qualifier Q = glm::defaultp> class AxisAlignedBoundingBox { +public: + using V = glm::vec<3, T, Q>; + AxisAlignedBoundingBox() = default; + + AxisAlignedBoundingBox(const V & min, const V & max) : min {min}, max {max} { } + + AxisAlignedBoundingBox & + operator+=(const V & point) + { + min = glm::min(min, point); + max = glm::max(max, point); + return *this; + } + + AxisAlignedBoundingBox + operator-(const V & viewPoint) const + { + return {min - viewPoint, max - viewPoint}; + } + + [[nodiscard]] static AxisAlignedBoundingBox + fromPoints(auto && points) + { + using Limits = std::numeric_limits<T>; + static constexpr const auto INITIAL = std::make_pair(V {Limits::max()}, V {Limits::min()}); + return std::make_from_tuple<AxisAlignedBoundingBox<T, Q>>( + std::ranges::fold_left(points, INITIAL, [](const auto & prev, const auto & point) { + auto & [min, max] = prev; + return std::make_pair(glm::min(min, point), glm::max(max, point)); + })); + } + + V min {}, max {}; +}; diff --git a/gfx/camera.cpp b/gfx/camera.cpp index cc6a2dd..f01054a 100644 --- a/gfx/camera.cpp +++ b/gfx/camera.cpp @@ -12,7 +12,7 @@ Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance nea Camera::Camera(GlobalPosition3D pos, GlobalDistance near, GlobalDistance far, const glm::mat4 & view, const glm::mat4 & projection) : - Frustum {view, projection}, position {pos}, forward {::north}, up {::up}, near {near}, far {far} + Frustum {pos, view, projection}, forward {::north}, up {::up}, near {near}, far {far} { } diff --git a/gfx/camera.h b/gfx/camera.h index a52ec8b..d1bfc82 100644 --- a/gfx/camera.h +++ b/gfx/camera.h @@ -59,12 +59,6 @@ public: return forward; } - [[nodiscard]] auto - getPosition() const - { - return position; - } - [[nodiscard]] std::array<GlobalPosition4D, 4> extentsAtDist(GlobalDistance) const; [[nodiscard]] static Direction3D upFromForward(const Direction3D & forward); @@ -74,7 +68,6 @@ private: const glm::mat4 & projection); void updateView(); - GlobalPosition3D position; Direction3D forward; Direction3D up; GlobalDistance near, far; diff --git a/gfx/frustum.cpp b/gfx/frustum.cpp index 9e046f6..faa676d 100644 --- a/gfx/frustum.cpp +++ b/gfx/frustum.cpp @@ -3,10 +3,10 @@ #include <collections.h> #include <glm/ext/matrix_transform.hpp> -static constexpr auto PLANES = std::array {0, 1, 2} * std::array {1.F, -1.F}; +static constexpr auto PLANES = std::array {0, 1, 2} * std::array {-1.F, 1.F}; -Frustum::Frustum(const glm::mat4 & view, const glm::mat4 & projection) : - view {view}, projection {projection}, viewProjection {}, inverseViewProjection {}, planes {} +Frustum::Frustum(const GlobalPosition3D & pos, const glm::mat4 & view, const glm::mat4 & projection) : + position {pos}, view {view}, projection {projection}, viewProjection {}, inverseViewProjection {}, planes {} { updateCache(); } @@ -18,6 +18,43 @@ Frustum::updateView(const glm::mat4 & newView) updateCache(); } +bool +Frustum::contains(const BoundingBox & aabb) const +{ + return boundByPlanes(aabb, FACES); +} + +bool +Frustum::shadedBy(const BoundingBox & aabb) const +{ + return boundByPlanes(aabb, FACES - 1); +} + +bool +Frustum::boundByPlanes(const BoundingBox & aabb, size_t nplanes) const +{ + static constexpr auto EXTENT_CORNER_IDXS = [] { + using Extent = GlobalPosition3D BoundingBox::*; + constexpr auto EXTENTS = std::array {&BoundingBox::min, &BoundingBox::max}; + std::array<glm::vec<3, Extent>, 2ZU * 2ZU * 2ZU> out {}; + std::ranges::copy(std::views::cartesian_product(EXTENTS, EXTENTS, EXTENTS) + | std::views::transform( + std::make_from_tuple<glm::vec<3, Extent>, std::tuple<Extent, Extent, Extent>>), + out.begin()); + return out; + }(); + + const std::array<RelativePosition4D, 8> corners + = EXTENT_CORNER_IDXS * [relativeAabb = aabb - position](auto idxs) -> glm::vec4 { + return {(relativeAabb.*(idxs.x)).x, (relativeAabb.*(idxs.y)).y, (relativeAabb.*(idxs.z)).z, 1.F}; + }; + return std::ranges::none_of(std::span(planes).subspan(0, nplanes), [&corners](const auto & frustumPlane) { + return (std::ranges::all_of(corners, [&frustumPlane](const auto & corner) { + return glm::dot(frustumPlane, corner) < 0.F; + })); + }); +} + void Frustum::updateCache() { diff --git a/gfx/frustum.h b/gfx/frustum.h index 25dcc18..a2d90e9 100644 --- a/gfx/frustum.h +++ b/gfx/frustum.h @@ -1,11 +1,13 @@ #pragma once +#include "aabb.h" +#include "config/types.h" #include <array> #include <glm/mat4x4.hpp> class Frustum { public: - Frustum(const glm::mat4 & view, const glm::mat4 & projection); + Frustum(const GlobalPosition3D & pos, const glm::mat4 & view, const glm::mat4 & projection); [[nodiscard]] auto & getFrustumPlanes() const @@ -19,12 +21,24 @@ public: return viewProjection; } + [[nodiscard]] auto + getPosition() const + { + return position; + } + void updateView(const glm::mat4 & view); + using BoundingBox = AxisAlignedBoundingBox<GlobalDistance>; + [[nodiscard]] bool contains(const BoundingBox &) const; + [[nodiscard]] bool shadedBy(const BoundingBox &) const; + protected: static constexpr size_t FACES = 6; void updateCache(); + [[nodiscard]] bool boundByPlanes(const BoundingBox &, size_t nplanes) const; + GlobalPosition3D position; glm::mat4 view, projection; glm::mat4 viewProjection, inverseViewProjection; std::array<glm::vec4, FACES> planes; diff --git a/gfx/gl/sceneProvider.cpp b/gfx/gl/sceneProvider.cpp index 4e271db..e01532e 100644 --- a/gfx/gl/sceneProvider.cpp +++ b/gfx/gl/sceneProvider.cpp @@ -9,6 +9,6 @@ SceneProvider::environment(const SceneShader &, const SceneRenderer & renderer) } void -SceneProvider::shadows(const ShadowMapper &) const +SceneProvider::shadows(const ShadowMapper &, const Frustum &) const { } diff --git a/gfx/gl/sceneProvider.h b/gfx/gl/sceneProvider.h index f5e8e99..f6b7009 100644 --- a/gfx/gl/sceneProvider.h +++ b/gfx/gl/sceneProvider.h @@ -5,6 +5,7 @@ class SceneRenderer; class ShadowMapper; class SceneShader; +class Frustum; class SceneProvider { public: @@ -12,8 +13,8 @@ public: virtual ~SceneProvider() = default; DEFAULT_MOVE_COPY(SceneProvider); - virtual void content(const SceneShader &) const = 0; + virtual void content(const SceneShader &, const Frustum &) const = 0; virtual void environment(const SceneShader &, const SceneRenderer &) const; virtual void lights(const SceneShader &) const = 0; - virtual void shadows(const ShadowMapper &) const; + virtual void shadows(const ShadowMapper &, const Frustum &) const; }; diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index b2a7d78..188c4fd 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -71,7 +71,7 @@ SceneRenderer::render(const SceneProvider & scene) const glEnable(GL_DEPTH_TEST); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - scene.content(shader); + scene.content(shader, camera); // Environment pass - // * ambient - clears illumination texture - see setAmbientLight diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 908dbdb..6525f76 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -1,6 +1,7 @@ #include "shadowMapper.h" #include "collections.h" #include "game/gamestate.h" +#include "gfx/aabb.h" #include "gfx/gl/shaders/fs-shadowDynamicPointInstWithTextures.h" #include "gfx/gl/shaders/fs-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/gs-commonShadowPoint.h" @@ -19,7 +20,6 @@ #include "maths.h" #include "sceneProvider.h" #include "sceneShader.h" -#include "sorting.h" #include <gfx/camera.h> #include <glm/gtc/type_ptr.hpp> #include <glm/gtx/transform.hpp> @@ -56,7 +56,7 @@ constexpr auto shadowBands = []<GlobalDistance... ints>(const float scaleFactor, std::integer_sequence<GlobalDistance, ints...>) { const auto base = 10'000'000 / pow(scaleFactor, sizeof...(ints) - 1); return std::array {1, static_cast<GlobalDistance>((base * pow(scaleFactor, ints)))...}; - }(6.6F, std::make_integer_sequence<GlobalDistance, ShadowMapper::SHADOW_BANDS>()); + }(4.6F, std::make_integer_sequence<GlobalDistance, ShadowMapper::SHADOW_BANDS>()); static_assert(shadowBands.front() == 1); static_assert(shadowBands.back() == 10'000'000); @@ -102,30 +102,30 @@ ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, co 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, &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[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); + 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); } - scene.shadows(*this); + 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 frustum {lightViewPoint, lightViewDir, lightProjection}; + scene.shadows(*this, frustum); glCullFace(GL_BACK); diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp index 3594968..27f2459 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -6,7 +6,7 @@ Renderable::lights(const SceneShader &) const } void -Renderable::shadows(const ShadowMapper &) const +Renderable::shadows(const ShadowMapper &, const Frustum &) const { } diff --git a/gfx/renderable.h b/gfx/renderable.h index 83522e3..140c570 100644 --- a/gfx/renderable.h +++ b/gfx/renderable.h @@ -3,6 +3,7 @@ #include <special_members.h> class SceneShader; +class Frustum; class ShadowMapper; class ShadowStenciller; @@ -12,9 +13,9 @@ public: virtual ~Renderable() = default; DEFAULT_MOVE_COPY(Renderable); - virtual void render(const SceneShader & shader) const = 0; + virtual void render(const SceneShader & shader, const Frustum &) const = 0; virtual void lights(const SceneShader & shader) const; - virtual void shadows(const ShadowMapper & shadowMapper) const; + virtual void shadows(const ShadowMapper & shadowMapper, const Frustum &) const; virtual void updateStencil(const ShadowStenciller & lightDir) const; }; |