From b514cd2e87ca90eb6a7552bad6702b44bbd35980 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Tue, 6 Oct 2020 17:10:59 -0700 Subject: [PATCH] Add some projection functions to math namespace. Break projection into their own header --- include/engine/camera.hpp | 16 +++--- include/engine/object.hpp | 12 +++-- include/math/mat.hpp | 8 --- include/math/mat.tpp | 34 ------------- include/math/math.hpp | 1 + include/math/projection.hpp | 45 +++++++++++++++++ include/math/projection.tpp | 98 +++++++++++++++++++++++++++++++++++++ src/engine/camera.cpp | 10 ++-- src/engine/object.cpp | 14 +++++- 9 files changed, 179 insertions(+), 59 deletions(-) create mode 100644 include/math/projection.hpp create mode 100644 include/math/projection.tpp diff --git a/include/engine/camera.hpp b/include/engine/camera.hpp index 4f26927..31301d3 100644 --- a/include/engine/camera.hpp +++ b/include/engine/camera.hpp @@ -33,8 +33,10 @@ namespace egn{ PROJ_UPDATE = 16, }; protected: - math::mat4 m_projection_matrix; //camera-to-sceen matrix - math::mat4 m_view_matrix; //world-to-camera matrix + //mutable because they're only really a cached value representation of the data + //in position, orientation, near, far, etc + mutable math::mat4 m_projection_matrix; //camera-to-sceen matrix + mutable math::mat4 m_view_matrix; //world-to-camera matrix GLfloat m_near = 1; //near clipping plane in camera space GLfloat m_far = 100; //far clipping plane in camera space @@ -52,8 +54,8 @@ namespace egn{ void set_orientation(const math::quaternion& distance)override; //getters - const math::mat4& get_projection_matrix(); - const math::mat4& get_view_matrix(); + const math::mat4& get_projection_matrix()const; + const math::mat4& get_view_matrix()const; GLfloat get_near_plane()const; GLfloat get_far_plane()const; @@ -62,8 +64,8 @@ namespace egn{ void set_far_plane(GLfloat f); protected: - void recalc_view_matrix(); - virtual void recalc_projection_matrix() = 0; + void recalc_view_matrix()const; + virtual void recalc_projection_matrix()const = 0; }; class ortho_camera : public camera_iface @@ -87,7 +89,7 @@ namespace egn{ void set_projection_height(GLfloat h); void set_projection_box(GLfloat w, GLfloat h); protected: - void recalc_projection_matrix()override; + void recalc_projection_matrix()const override; }; } diff --git a/include/engine/object.hpp b/include/engine/object.hpp index 16630f0..fb72cc1 100644 --- a/include/engine/object.hpp +++ b/include/engine/object.hpp @@ -37,8 +37,8 @@ namespace egn{ math::vec3 m_position; //track current positon in world space math::quaternion m_orientation; //track current model space rotation math::vec3 m_scale{1.0f, 1.0f, 1.0f}; //track model space scale - math::mat4 m_model_matrix; //compile all the above info into a matrix - int m_update_flag = NO_UPDATE; //whether or not to update the matrix upon access + mutable math::mat4 m_model_matrix; //compile all the above info into a matrix + mutable int m_update_flag = NO_UPDATE; //whether or not to update the matrix upon access public: object() = default; @@ -59,10 +59,14 @@ namespace egn{ virtual void set_position(const math::vec3& pos); virtual void set_orientation(const math::quaternion& orient); virtual void set_scale(const math::vec3& scale); - const math::mat4& get_model_matrix(); + + const math::mat4& get_model_matrix()const; + const math::vec3& get_position()const; + const math::vec3& get_scale()const; + const math::quaternion& get_orientation()const; protected: - void recalc_model_matrix(); + void recalc_model_matrix()const; }; } diff --git a/include/math/mat.hpp b/include/math/mat.hpp index 934b794..bebf029 100644 --- a/include/math/mat.hpp +++ b/include/math/mat.hpp @@ -176,14 +176,6 @@ namespace math{ template matrix rotation2d(T x, T y, T z); - template - matrix fov_projection(T fov, T asp, T near, T far); - template - matrix fov_asymetric_projection(T fovl, T fovr, T fovb, T fovt, T asp, T near, T far); - template - matrix ortho_projection(T w, T h, T n, T f); - template - matrix ortho_asymetric_projection(T l, T r, T b, T t, T n, T f); template constexpr matrix rotation3d(T angle_x, T angle_y, T angle_z); template diff --git a/include/math/mat.tpp b/include/math/mat.tpp index 40a4eaf..dea3dc5 100644 --- a/include/math/mat.tpp +++ b/include/math/mat.tpp @@ -208,40 +208,6 @@ namespace math{ return q.to_mat3(); } - template - matrix fov_projection(T fov, T asp, T near, T far){ - T r = near * std::tan(fov / T{2.0}); - return matrix((near / r) / asp, T{0}, T{0}, T{0}, - T{0}, (near / r), T{0}, T{0}, - T{0}, T{0}, (far + near) / (near - far), -T{1}, - T{0}, T{0}, (T{2} * near * far) / (near - far), T{0}); - } - template - matrix fov_asymetric_projection(T fovl, T fovr, T fovb, T fovt, T asp, T n, T f){ - T l = n * std::tan(fovl); - T r = n * std::tan(fovr); - T b = n * std::tan(fovb); - T t = n * std::tan(fovt); - - return matrix(((T{2} * n) / (r - l)) * asp, T{0}, T{0}, T{0}, - T{0}, (T{2} * n) / (t - b), T{0}, T{0}, - (r + l) / (r - l), (t + b) / (t - b), (f + n) / (n - f), -T{1}, - T{0}, T{0}, (T{2} * n * f) / (n - f), T{0}); - } - template - matrix ortho_projection(T w, T h, T n, T f){ - return matrix(T{2} / w, T{0}, T{0}, T{0}, - T{0}, T{2} / h, T{0}, T{0}, - T{0}, T{0}, T{2} / (n - f), T{0}, - T{0}, T{0}, (n + f) / (n - f), T{1}); - } - template - matrix ortho_asymetric_projection(T l, T r, T b, T t, T n, T f){ - return matrix(T{2} / (r - l), T{0}, T{0}, T{0}, - T{0}, T{2} / (t - b), T{0}, T{0}, - T{0}, T{0}, T{2} / (n - f), T{0}, - (r + l) / (l - r), (t + b) / (b - t), (n + f) / (n - f), T{1}); - } template constexpr matrix rotation3d(T angle_x, T angle_y, T angle_z){ quaternion q(angle_x, angle_y, angle_z); diff --git a/include/math/math.hpp b/include/math/math.hpp index e59d15c..8c35a0c 100644 --- a/include/math/math.hpp +++ b/include/math/math.hpp @@ -26,5 +26,6 @@ #include "vec.hpp" #include "mat.hpp" #include "quat.hpp" +#include "projection.hpp" #endif diff --git a/include/math/projection.hpp b/include/math/projection.hpp new file mode 100644 index 0000000..f54493c --- /dev/null +++ b/include/math/projection.hpp @@ -0,0 +1,45 @@ +/** + This file is a part of our_dick + Copyright (C) 2020 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef OUR_DICK_MATH_PROJECTION_HPP +#define OUR_DICK_MATH_PROJECTION_HPP + +#include "mat.hpp" +#include "vec.hpp" + +namespace math{ + + template + matrix fov_projection(T fov, T asp, T near, T far); + template + matrix fov_asymetric_projection(T fovl, T fovr, T fovb, T fovt, T asp, T near, T far); + template + matrix ortho_projection(T w, T h, T n, T f); + template + matrix ortho_asymetric_projection(T l, T r, T b, T t, T n, T f); + + template + vec3 project(const mat4& viewproj_mat, const vec3& world_coords, const vec4& viewport); + template + vec3 unproject(const mat4& viewproj_mat, const vec3& viewport_coords, const vec4& viewport); + +} + +#include "projection.tpp" + +#endif diff --git a/include/math/projection.tpp b/include/math/projection.tpp new file mode 100644 index 0000000..c365113 --- /dev/null +++ b/include/math/projection.tpp @@ -0,0 +1,98 @@ +/** + This file is a part of our_dick + Copyright (C) 2020 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef OUR_DICK_MATH_PROJECTION_TPP +#define OUR_DICK_MATH_PROJECTION_TPP + +#include "mat.hpp" +#include "vec.hpp" +#include //sin, cos, tan + +namespace math{ + + template + matrix fov_projection(T fov, T asp, T near, T far){ + T r = near * std::tan(fov / T{2.0}); + return matrix((near / r) / asp, T{0}, T{0}, T{0}, + T{0}, (near / r), T{0}, T{0}, + T{0}, T{0}, (far + near) / (near - far), -T{1}, + T{0}, T{0}, (T{2} * near * far) / (near - far), T{0}); + } + template + matrix fov_asymetric_projection(T fovl, T fovr, T fovb, T fovt, T asp, T n, T f){ + T l = n * std::tan(fovl); + T r = n * std::tan(fovr); + T b = n * std::tan(fovb); + T t = n * std::tan(fovt); + + return matrix(((T{2} * n) / (r - l)) * asp, T{0}, T{0}, T{0}, + T{0}, (T{2} * n) / (t - b), T{0}, T{0}, + (r + l) / (r - l), (t + b) / (t - b), (f + n) / (n - f), -T{1}, + T{0}, T{0}, (T{2} * n * f) / (n - f), T{0}); + } + template + matrix ortho_projection(T w, T h, T n, T f){ + return matrix(T{2} / w, T{0}, T{0}, T{0}, + T{0}, T{2} / h, T{0}, T{0}, + T{0}, T{0}, T{2} / (n - f), T{0}, + T{0}, T{0}, (n + f) / (n - f), T{1}); + } + template + matrix ortho_asymetric_projection(T l, T r, T b, T t, T n, T f){ + return matrix(T{2} / (r - l), T{0}, T{0}, T{0}, + T{0}, T{2} / (t - b), T{0}, T{0}, + T{0}, T{0}, T{2} / (n - f), T{0}, + (r + l) / (l - r), (t + b) / (b - t), (n + f) / (n - f), T{1}); + } + + template + vec3 project(const mat4& viewproj_mat, const vec3& w_coords, const vec4& viewport){ + //project world coordinates to ndc coordinates + vec4 world_coords{w_coords[0], w_coords[1], w_coords[2], T{1.0}}; + vec4 ndc_coords = viewproj_mat * world_coords; + + //perspective_division + ndc_coords /= ndc_coords[3]; + + //project ndc coordinates to viewport coordinates + return vec3{((ndc_coords[0] + T{1.0}) * viewport[2] * T{0.5}) + viewport[0], + ((ndc_coords[1] + T{1.0}) * viewport[3] * T{0.5}) + viewport[1], + ndc_coords[2] + }; + } + template + vec3 unproject(const mat4& viewproj_mat, const vec3& viewport_coords, const vec4& viewport){ + //project viewport coordinates to ndc coordinates + vec4 ndc_coords{((viewport_coords[0] - viewport[0]) * T{2.0} / viewport[2]) - T{1.0}, + ((viewport_coords[1] - viewport[1]) * T{2.0} / viewport[3]) - T{1.0}, + viewport_coords[2], + T{1.0}}; + + //project ndc coordinates to world coordinates + mat4 inv_viewproj_mat = viewproj_mat.inverse(); + vec4 world_coords = inv_viewproj_mat * ndc_coords; + + //perspective division + world_coords /= world_coords[3]; + + return {world_coords[0], world_coords[1], world_coords[2]}; + } + +} + +#endif diff --git a/src/engine/camera.cpp b/src/engine/camera.cpp index b62594f..15e5533 100644 --- a/src/engine/camera.cpp +++ b/src/engine/camera.cpp @@ -18,6 +18,7 @@ #include "engine/camera.hpp" #include "config.hpp" +#include "math/projection.hpp" namespace egn{ @@ -30,17 +31,18 @@ namespace egn{ m_update_flag |= VIEW_UPDATE; } void camera_iface::set_orientation(const math::quaternion& orient){ + debug_print("%f, %f, %f, %f\n", m_orientation.w(), m_orientation.x(), m_orientation.y(), m_orientation.z()); object::set_orientation(orient); m_update_flag |= VIEW_UPDATE; } - const math::mat4& camera_iface::get_projection_matrix(){ + const math::mat4& camera_iface::get_projection_matrix()const{ if(m_update_flag & PROJ_UPDATE){ recalc_projection_matrix(); m_update_flag ^= PROJ_UPDATE; } return m_projection_matrix; } - const math::mat4& camera_iface::get_view_matrix(){ + const math::mat4& camera_iface::get_view_matrix()const{ if(m_update_flag & VIEW_UPDATE){ recalc_view_matrix(); m_update_flag ^= VIEW_UPDATE; @@ -63,7 +65,7 @@ namespace egn{ m_far = f; } - void camera_iface::recalc_view_matrix(){ + void camera_iface::recalc_view_matrix()const{ debug_print_verbose("Rebuilding view matrix\n"); m_view_matrix = m_orientation.to_mat4(); m_view_matrix.get(3, 0) = -m_position[0]; @@ -97,7 +99,7 @@ namespace egn{ m_height = h; } - void ortho_camera::recalc_projection_matrix(){ + void ortho_camera::recalc_projection_matrix()const{ debug_print_verbose("Rebuilding orthographic projection matrix\n"); m_projection_matrix = math::ortho_projection(m_width, m_height, m_near, m_far); } diff --git a/src/engine/object.cpp b/src/engine/object.cpp index 7f33e7c..624a408 100644 --- a/src/engine/object.cpp +++ b/src/engine/object.cpp @@ -58,14 +58,24 @@ namespace egn{ m_update_flag |= SCALE_UPDATE; m_scale = scale; } - const math::mat4& object::get_model_matrix(){ + const math::mat4& object::get_model_matrix()const{ if(m_update_flag & (SCALE_UPDATE | ROTATION_UPDATE | TRANSLATION_UPDATE)){ recalc_model_matrix(); m_update_flag &= (~(SCALE_UPDATE | ROTATION_UPDATE | TRANSLATION_UPDATE)); } return m_model_matrix; } - void object::recalc_model_matrix(){ + const math::vec3& object::get_position()const{ + return m_position; + } + const math::vec3& object::get_scale()const{ + return m_scale; + } + const math::quaternion& object::get_orientation()const{ + return m_orientation; + } + + void object::recalc_model_matrix()const{ debug_print_verbose("Rebuilding model matrix\n"); m_model_matrix = m_orientation.to_mat4(); m_model_matrix.get(3, 0) = m_position[0];