huge improvement

This commit is contained in:
2024-12-01 03:51:40 +03:00
parent f8e7faa570
commit 46b4eb9151
17 changed files with 297 additions and 254 deletions

View File

@@ -5,6 +5,8 @@
#pragma once
#include "omath/Angles.hpp"
#include <algorithm>
namespace omath
{
@@ -14,14 +16,12 @@ namespace omath
Clamped = 1,
};
template<class Type, Type min = 0, Type max = 360, AngleFlags flags = AngleFlags::Normalized>
template<class Type, Type min = Type(0), Type max = Type(360), AngleFlags flags = AngleFlags::Normalized>
requires std::is_arithmetic_v<Type>
class Angle
{
Type m_angle;
public:
constexpr explicit Angle(const Type& degrees)
constexpr Angle(const Type& degrees)
{
if constexpr (flags == AngleFlags::Normalized)
m_angle = angles::WrapAngle(degrees, min, max);
@@ -34,17 +34,20 @@ namespace omath
std::unreachable();
}
}
public:
[[nodiscard]]
constexpr static Angle FromDegrees(const Type& degrees)
{
return {degrees};
}
constexpr Angle() : m_angle(0)
{
}
[[nodiscard]]
constexpr static Angle FromRadians(const Type& degrees)
{
return {angles::RadiansToDegrees(degrees)};
return {angles::RadiansToDegrees<Type>(degrees)};
}
[[nodiscard]]
@@ -54,23 +57,11 @@ namespace omath
}
[[nodiscard]]
constexpr Type& operator*()
constexpr Type AsDegrees() const
{
return m_angle;
}
[[nodiscard]]
constexpr const Type& Value() const
{
return **std::as_const(this);
}
[[nodiscard]]
constexpr Type& Value()
{
return **this;
}
[[nodiscard]]
constexpr Type AsRadians() const
{
@@ -86,7 +77,7 @@ namespace omath
[[nodiscard]]
Type Cos() const
{
return std::sin(AsRadians());
return std::cos(AsRadians());
}
[[nodiscard]]
@@ -108,13 +99,13 @@ namespace omath
}
[[nodiscard]]
constexpr Angle& operator+=(const Type& other)
constexpr Angle& operator+=(const Angle& other)
{
if constexpr (flags == AngleFlags::Normalized)
m_angle = angles::WrapAngle(m_angle + other, min, max);
m_angle = angles::WrapAngle(m_angle + other.m_angle, min, max);
else if constexpr (flags == AngleFlags::Clamped)
m_angle = std::clamp(m_angle + other, min, max);
m_angle = std::clamp(m_angle + other.m_angle, min, max);
else
{
static_assert(false);
@@ -125,19 +116,22 @@ namespace omath
}
[[nodiscard]]
constexpr Angle& operator-=(const Type& other)
constexpr std::partial_ordering operator<=>(const Angle& other) const = default;
[[nodiscard]]
constexpr Angle& operator-=(const Angle& other)
{
return operator+=(-other);
}
[[nodiscard]]
constexpr Angle& operator+(const Type& other)
constexpr Angle& operator+(const Angle& other)
{
if constexpr (flags == AngleFlags::Normalized)
return {angles::WrapAngle(m_angle + other, min, max)};
return {angles::WrapAngle(m_angle + other.m_angle, min, max)};
else if constexpr (flags == AngleFlags::Clamped)
return {std::clamp(m_angle + other, min, max)};
return {std::clamp(m_angle + other.m_angle, min, max)};
else
static_assert(false);
@@ -146,11 +140,9 @@ namespace omath
}
[[nodiscard]]
constexpr Angle& operator-(const Type& other)
constexpr Angle& operator-(const Angle& other)
{
return operator+(-other);
}
};
}

View File

@@ -11,14 +11,14 @@ namespace omath::angles
{
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr float RadiansToDegrees(const Type& radians)
[[nodiscard]] constexpr Type RadiansToDegrees(const Type& radians)
{
return radians * (Type(180) / std::numbers::pi_v<Type>);
}
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr float DegreesToRadians(const Type& degrees)
[[nodiscard]] constexpr Type DegreesToRadians(const Type& degrees)
{
return degrees * (std::numbers::pi_v<Type> / Type(180));
}

View File

@@ -5,10 +5,10 @@
#include <algorithm>
#include <array>
#include <sstream>
#include <utility>
#include "Vector3.hpp"
#include <stdexcept>
#include <utility>
#include "Angles.hpp"
#include "Vector3.hpp"
namespace omath
@@ -33,8 +33,11 @@ namespace omath
{
Clear();
}
constexpr Mat(const std::initializer_list<std::initializer_list<Type> >& rows)
constexpr static MatStoreType GetStoreOrdering()
{
return StoreType;
}
constexpr Mat(const std::initializer_list<std::initializer_list<Type>>& rows)
{
if (rows.size() != Rows)
throw std::invalid_argument("Initializer list rows size does not match template parameter Rows");
@@ -44,7 +47,7 @@ namespace omath
{
if (rowIt->size() != Columns)
throw std::invalid_argument(
"All rows must have the same number of columns as template parameter Columns");
"All rows must have the same number of columns as template parameter Columns");
auto colIt = rowIt->begin();
for (size_t j = 0; j < Columns; ++j, ++colIt)
@@ -133,8 +136,8 @@ namespace omath
// Operator overloading for multiplication with another Mat
template<size_t OtherColumns>
constexpr Mat<Rows, OtherColumns, Type, StoreType> operator*(
const Mat<Columns, OtherColumns, Type, StoreType>& other) const
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{
Mat<Rows, OtherColumns, Type, StoreType> result;
@@ -158,8 +161,8 @@ namespace omath
}
template<size_t OtherColumns>
constexpr Mat<Rows, OtherColumns, Type, StoreType> operator*=(
const Mat<Columns, OtherColumns, Type, StoreType>& other)
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*=(const Mat<Columns, OtherColumns, Type, StoreType>& other)
{
return *this = *this * other;
}
@@ -306,24 +309,22 @@ namespace omath
[[nodiscard]]
constexpr static Mat<4, 4> ToScreenMat(const Type& screenWidth, const Type& screenHeight) noexcept
{
return
{
{screenWidth / 2, 0, 0, 0},
{0, -screenHeight / 2, 0, 0},
{0, 0, 1, 0},
{screenWidth / 2, screenHeight / 2, 0, 1},
return {
{screenWidth / 2, 0, 0, 0},
{0, -screenHeight / 2, 0, 0},
{0, 0, 1, 0},
{screenWidth / 2, screenHeight / 2, 0, 1},
};
}
[[nodiscard]]
constexpr static Mat<4, 4> TranslationMat(const Vector3& diff) noexcept
{
return
{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{diff.x, diff.y, diff.z, 1},
return {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{diff.x, diff.y, diff.z, 1},
};
}
@@ -331,52 +332,55 @@ namespace omath
constexpr static Mat<4, 4> OrientationMat(const Vector3& forward, const Vector3& right,
const Vector3& up) noexcept
{
return
{
{right.x, up.x, forward.x, 0},
{right.y, up.y, forward.y, 0},
{right.z, up.z, forward.z, 0},
{0, 0, 0, 1},
return {
{right.x, up.x, forward.x, 0},
{right.y, up.y, forward.y, 0},
{right.z, up.z, forward.z, 0},
{0, 0, 0, 1},
};
}
[[nodiscard]]
constexpr static Mat<4, 4> ProjectionMat(const Type& fieldOfView, const Type& aspectRatio,
const Type& near, const Type& far, const Type& lensZoom) noexcept
constexpr static Mat<4, 4> ProjectionMat(const Type& fieldOfView, const Type& aspectRatio, const Type& near,
const Type& far, const Type& lensZoom) noexcept
{
const Type& fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2);
const Type& frustumHeight = far - near;
return
{
{-1 / (aspectRatio * fovHalfTan) * lensZoom, 0, 0, 0},
{0, -1 / fovHalfTan * lensZoom, 0, 0},
{0, 0, -far / frustumHeight, -1},
{0, 0, near * far / frustumHeight, 0}
};
}
[[nodiscard]]
constexpr static Mat<4, 1> MatRowFromVector(const Vector3& vector) noexcept
{
return {{vector.x, vector.y, vector.z, 1}};
}
[[nodiscard]]
constexpr static Mat<1, 4> MatColumnFromVector(const Vector3& vector) noexcept
{
return
{
{
vector.x,
vector.y,
vector.z,
1
}
};
return {{-1 / (aspectRatio * fovHalfTan) * lensZoom, 0, 0, 0},
{0, -1 / fovHalfTan * lensZoom, 0, 0},
{0, 0, -far / frustumHeight, -1},
{0, 0, near * far / frustumHeight, 0}};
}
private:
std::array<Type, Rows * Columns> m_data;
};
}
template<class T = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr static Mat<1, 4, T, St> MatRowFromVector(const Vector3& vector) noexcept
{
return {{vector.x, vector.y, vector.z, 1}};
}
template<class T = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr static Mat<4, 1, T, St> MatColumnFromVector(const Vector3& vector) noexcept
{
return {
{vector.x}, {vector.y}, {vector.z}, {1}};
}
template<class T = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr Mat<4, 4, T, St> MatTranslation(const Vector3& diff) noexcept
{
return {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{diff.x, diff.y, diff.z, 1},
};
}
} // namespace omath

View File

@@ -216,10 +216,6 @@ namespace omath
[[nodiscard]] Vector3 ViewAngleTo(const Vector3& other) const;
[[nodiscard]] static Vector3 ForwardVector(float pitch, float yaw);
[[nodiscard]] static Vector3 RightVector(float pitch, float yaw, float roll);
[[nodiscard]] static Vector3 UpVector(float pitch, float yaw, float roll);
[[nodiscard]] std::tuple<float, float, float> AsTuple() const
{
return std::make_tuple(x, y, z);

View File

@@ -2,34 +2,14 @@
// Created by Orange on 11/30/2024.
//
#pragma once
#include <type_traits>
#include <__algorithm/clamp.h>
#include "omath/Angles.hpp"
namespace omath
{
template<class Type, Type min = 0, Type max = 360>
requires std::is_arithmetic_v<Type>
class ViewAngles
template<class PitchType, class YawType, class RollType>
struct ViewAngles
{
Type pitch;
Type yaw;
Type roll;
constexpr void SetPitch(const Type& newPitch)
{
pitch = std::clamp(newPitch, min, max);
}
void SetYaw(const Type& newYaw)
{
yaw = std::clamp(newYaw, min, max);
}
void SetRoll(const Type& newRoll)
{
roll = angles::WrapAngle(newRoll, min, max);
}
PitchType pitch;
YawType yaw;
RollType roll;
};
}

View File

@@ -2,8 +2,12 @@
// Created by Orange on 11/24/2024.
//
#pragma once
#include "omath/Vector3.hpp"
#include "omath/Mat.hpp"
#include "omath/Vector3.hpp"
#include <omath/Angle.hpp>
#include <omath/ViewAngles.hpp>
#include <omath/projection/Camera.hpp>
namespace omath::source
{
@@ -11,22 +15,119 @@ namespace omath::source
constexpr Vector3 kAbsRight = {0, -1, 0};
constexpr Vector3 kAbsForward = {1, 0, 0};
using PitchAngle = Angle<float, -89.f, 89.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
template<class Type> requires std::is_floating_point_v<Type> || std::is_integral_v<Type>
[[nodiscard]] Mat<4, 4, Type, MatStoreType::COLUMN_MAJOR> PerspectiveProjectionMatrix(
const float fieldOfView, const Type &aspectRatio, const Type &near, const Type &far)
inline Vector3 ForwardVector(const ViewAngles& angles);
inline Vector3 RightVector(const ViewAngles& angles);
inline Vector3 UpVector(const ViewAngles& angles);
template<class Type = float>
requires std::is_floating_point_v<Type> || std::is_integral_v<Type>
[[nodiscard]] constexpr Mat<4, 4, Type, MatStoreType::COLUMN_MAJOR> ViewMatrixFromVecs(const Vector3& forward, const Vector3& right,
const Vector3& up, const Vector3& camera_pos)
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2);
return
{
{static_cast<Type>(1) / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, static_cast<Type>(1) / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(static_cast<Type>(2) * far * near) / (far - near)},
{0, 0, 1, 0},
return MatTranslation<float, MatStoreType::COLUMN_MAJOR>(-camera_pos) * Mat<4, 4, Type, MatStoreType::COLUMN_MAJOR>{
{right.x, up.x, forward.x, 0},
{right.y, up.y, forward.y, 0},
{right.z, up.z, forward.z, 0},
{0, 0, 0, 1},
};
}
}
template<class Type = float>
requires std::is_floating_point_v<Type> || std::is_integral_v<Type>
[[nodiscard]] Mat<4, 4, Type, MatStoreType::COLUMN_MAJOR> ViewMatrix(const ViewAngles& angles, const Vector3& cam_origin)
{
return ViewMatrixFromVecs(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
}
template<class Type>
requires std::is_floating_point_v<Type> || std::is_integral_v<Type>
[[nodiscard]] Mat<4, 4, Type, MatStoreType::COLUMN_MAJOR>
PerspectiveProjectionMatrix(const Type& fieldOfView, const Type& aspectRatio, const Type& near, const Type& far)
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2);
return {
{static_cast<Type>(1) / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, static_cast<Type>(1) / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(static_cast<Type>(2) * far * near) / (far - near)},
{0, 0, 1, 0},
};
}
// Copied from
// https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/mathlib/mathlib_base.cpp#L919
[[nodiscard]]
inline Vector3 ForwardVector(const ViewAngles& angles)
{
const auto cosPitch = angles.pitch.Cos();
const auto sinPitch = angles.pitch.Sin();
const auto cosYaw = angles.yaw.Cos();
const auto sinYaw = angles.yaw.Sin();
return {cosPitch * cosYaw, cosPitch * sinYaw, -sinPitch};
}
[[nodiscard]]
inline Vector3 RightVector(const ViewAngles& angles)
{
const auto cosPitch = angles.pitch.Cos();
const auto sinPitch = angles.pitch.Sin();
const auto cosYaw = angles.yaw.Cos();
const auto sinYaw = angles.yaw.Sin();
const auto cosRoll = angles.roll.Cos();
const auto sinRoll = angles.roll.Sin();
return
{
-1 * sinRoll * sinPitch * cosYaw + -1 * cosRoll * -sinYaw,
-1 * sinRoll * sinPitch * sinYaw + -1 * cosRoll * cosYaw,
-1 * sinRoll * cosPitch
};
}
[[nodiscard]]
inline Vector3 UpVector(const ViewAngles& angles)
{
const auto cosPitch = angles.pitch.Cos();
const auto sinPitch = angles.pitch.Sin();
const auto cosYaw = angles.yaw.Cos();
const auto sinYaw = angles.yaw.Sin();
const auto cosRoll = angles.roll.Cos();
const auto sinRoll = angles.roll.Sin();
return
{
cosRoll * sinPitch * cosYaw + - sinRoll * -sinYaw,
cosRoll * sinPitch * sinYaw + - sinRoll * cosYaw,
cosRoll * cosPitch,
};
}
using Camera = omath::projection::Camera<ViewAngles, decltype(ViewMatrix<float>), decltype(PerspectiveProjectionMatrix<float>)>;
// Camera(const Vector3& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort,
// const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far,
// const std::function<ViewMatFunc>& viewMatFunc, const std::function<ProjectionFunc>& projFunc)
inline Camera CreateCamera(const Vector3& position, const auto& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far)
{
return Camera(position, viewAngles, viewPort, fov, near, far, ViewMatrix<float>, PerspectiveProjectionMatrix<float>);
}
} // namespace omath::source

View File

@@ -5,9 +5,11 @@
#pragma once
#include <expected>
#include <omath/Vector3.hpp>
#include <omath/Mat.hpp>
#include <omath/Vector3.hpp>
#include "ErrorCodes.hpp"
#include <omath/Angle.hpp>
#include <type_traits>
namespace omath::projection
@@ -18,29 +20,60 @@ namespace omath::projection
float m_width;
float m_height;
[[nodiscard]] constexpr float AspectRatio() const {return m_width / m_height;}
[[nodiscard]] constexpr float AspectRatio() const
{
return m_width / m_height;
}
};
template<class ViewAnglesType, class ViewMatFunc, class ProjectionFunc>
requires std::is_same_v<std::invoke_result_t<ViewMatFunc, const ViewAnglesType&, const Vector3&>,
std::invoke_result_t<ProjectionFunc, const float&, const float&, const float&, const float&>>
class Camera
{
public:
Camera(const Vector3& position, const Vector3& viewAngles, const ViewPort& viewPort,
float fov, float near, float far, float lensZoom);
void SetViewAngles(const Vector3& viewAngles);
Camera(const Vector3& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far,
const std::function<ViewMatFunc>& viewMatFunc, const std::function<ProjectionFunc>& projFunc) :
m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near),
m_viewAngles(viewAngles), m_origin(position), CreateViewMatrix(viewMatFunc), CreateProjectionMatrix(projFunc)
{
}
[[nodiscard]] Mat<4, 4> GetViewMatrix() const;
void LookAt(const Vector3& target);
[[nodiscard]] std::expected<Vector3, Error> WorldToScreen(const Vector3& worldPosition) const;
[[nodiscard]] auto GetViewMatrix() const
{
return CreateViewMatrix(m_viewAngles, m_origin);
}
[[nodiscard]] auto GetProjectionMatrix() const
{
return CreateProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance, m_farPlaneDistance);
}
[[nodiscard]] std::expected<Vector3, Error> WorldToScreen([[maybe_unused]] const Vector3& worldPosition) const
{
using mat = std::invoke_result_t<ViewMatFunc, const ViewAnglesType&, const Vector3&>;
const auto vecAsMatrix = MatColumnFromVector<float, mat::GetStoreOrdering()>(worldPosition);
const auto projected = GetViewMatrix().Transposed() * vecAsMatrix;
return Vector3{projected.At(0,0), projected.At(1,0), projected.At(2,0)};
}
ViewPort m_viewPort{};
float m_fieldOfView;
Angle<float, 0.f, 180.f, AngleFlags::Clamped> m_fieldOfView;
float m_farPlaneDistance;
float m_nearPlaneDistance;
float m_lensZoom;
private:
Vector3 m_viewAngles;
ViewAnglesType m_viewAngles;
Vector3 m_origin;
std::function<ViewMatFunc> CreateViewMatrix;
std::function<ProjectionFunc> CreateProjectionMatrix;
};
}
} // namespace omath::projection