From 2454b5449bbda815eb15327476e376d0d3a39617 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 5 Mar 2025 22:16:56 +0000 Subject: Move camera out of gl folder, it's not OpenGL specific --- gfx/camera.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 gfx/camera.cpp (limited to 'gfx/camera.cpp') diff --git a/gfx/camera.cpp b/gfx/camera.cpp new file mode 100644 index 0000000..9e165fa --- /dev/null +++ b/gfx/camera.cpp @@ -0,0 +1,67 @@ +#include "camera.h" +#include +#include +#include +#include + +Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance zNear, GlobalDistance zFar) : + position {pos}, forward {::north}, up {::up}, near {zNear}, far {zFar}, view {}, + projection { + glm::perspective(fov, aspect, static_cast(zNear), static_cast(zFar))}, + viewProjection {}, inverseViewProjection {} +{ + updateView(); +} + +Ray +Camera::unProject(const ScreenRelCoord & mouse) const +{ + static constexpr const glm::vec4 SCREEN {0, 0, 1, 1}; + return { + .start = position, + .direction = glm::normalize(glm::unProject(mouse || 1.F, view, projection, SCREEN)), + }; +} + +void +Camera::updateView() +{ + view = glm::lookAt({}, forward, up); + viewProjection = projection * view; + inverseViewProjection = glm::inverse(viewProjection); + static constexpr auto PLANES = std::array {0, 1, 2} * std::array {1.F, -1.F}; + std::ranges::transform(PLANES, frustumPlanes.begin(), [vpt = glm::transpose(viewProjection)](const auto & idxs) { + const auto [idx, sgn] = idxs; + return vpt[3] + (vpt[idx] * sgn); + }); +} + +Direction3D +Camera::upFromForward(const Direction3D & forward) +{ + const auto right = crossProduct(forward, ::down); + return crossProduct(forward, right); +} + +std::array +Camera::extentsAtDist(const GlobalDistance dist) const +{ + const auto clampToSeaFloor = [this, dist](GlobalPosition3D target) -> GlobalPosition4D { + target += position; + if (target.z < -1500) { + const CalcPosition3D diff = target - position; + const CalcDistance limit = -1500 - position.z; + return {position + ((limit * diff) / diff.z), (limit * dist) / diff.z}; + } + return {target, dist}; + }; + const auto depth = -(2.F * (static_cast(dist - near)) * static_cast(far)) + / (static_cast(dist) * (static_cast(near - far))) + - 1.F; + static constexpr const std::array extents {-1.F, 1.F}; + static constexpr const auto cartesianExtents = extents * extents; + return cartesianExtents * [&depth, this, &clampToSeaFloor](const auto & extent) { + const glm::vec4 in {extent.first, extent.second, depth, 1.F}; + return clampToSeaFloor(perspective_divide(inverseViewProjection * in)); + }; +} -- cgit v1.2.3