mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +00:00
Fixes Unreal Engine view angle matrix order
The view angle rotation matrix order in Unreal Engine was incorrect, leading to incorrect camera orientation. This commit fixes the order of rotation matrices to roll, pitch, yaw to correctly implement Unreal Engine camera rotations. Adds comprehensive unit tests for Unreal Engine formulas, camera and constants. Marks Unreal Engine as supported in README.md.
This commit is contained in:
7
.idea/codeStyles/Project.xml
generated
7
.idea/codeStyles/Project.xml
generated
@@ -182,19 +182,12 @@
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=2AD8EC23F81C6F4AB06852FBF796A3D1/@EntryIndexedValue" value="" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=2AD8EC23F81C6F4AB06852FBF796A3D1/@EntryIndexRemoved" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=299C42B75F5A8C4DB381AE89010A7CC8/@EntryIndexedValue" value="<NamingElement Priority="1" Title="Namespaces"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="namespace" /><type Name="namespace alias" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aa_bb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=299C42B75F5A8C4DB381AE89010A7CC8/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=A279BB9D47B8754E9482D81B5D3B3489/@EntryIndexedValue" value="<NamingElement Priority="2" Title="Types"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="__interface" /><type Name="class" /><type Name="concept" /><type Name="enum" /><type Name="struct" /><type Name="type alias" /><type Name="type template parameter" /><type Name="typedef" /><type Name="union" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=A279BB9D47B8754E9482D81B5D3B3489/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=82D01E1970D2F6419CE2737C415D3A01/@EntryIndexedValue" value="<NamingElement Priority="3" Title="Functions"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="global function" /><type Name="member function" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aa_bb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=82D01E1970D2F6419CE2737C415D3A01/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=2A0CD4590563D04B89402AC0279B5E10/@EntryIndexedValue" value="<NamingElement Priority="4" Title="Fields"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="class field" /><type Name="struct field" /><type Name="union member" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aa_bb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=2A0CD4590563D04B89402AC0279B5E10/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=DC1F6BB6E0EFFC49A38E940DB8A84CF6/@EntryIndexedValue" value="<NamingElement Priority="5" Title="Variables"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="global variable" /><type Name="lambda" /><type Name="local variable" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aa_bb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=DC1F6BB6E0EFFC49A38E940DB8A84CF6/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=AA17EF9DE2E5364DAEBE52F9EBBEA658/@EntryIndexedValue" value="<NamingElement Priority="6" Title="Parameters"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="function parameter" /><type Name="lambda parameter" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aa_bb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=AA17EF9DE2E5364DAEBE52F9EBBEA658/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=9BA140847B0718418342A07C8F0CE1ED/@EntryIndexedValue" value="<NamingElement Priority="7" Title="Macros"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="macro" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AA_BB" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=9BA140847B0718418342A07C8F0CE1ED/@EntryIndexRemoved" />
|
||||
</RiderCodeStyleSettings>
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
|
||||
1
.idea/codeStyles/codeStyleConfig.xml
generated
1
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +1,6 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
@@ -42,7 +42,8 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
|
||||
| Source | ✅YES |
|
||||
| Unity | ✅YES |
|
||||
| IWEngine | ✅YES |
|
||||
| Unreal | ❌NO |
|
||||
| OpenGL | ✅YES |
|
||||
| Unreal | ✅YES |
|
||||
|
||||
## Supported Operating Systems
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ namespace omath::unreal_engine
|
||||
}
|
||||
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
||||
{
|
||||
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch)
|
||||
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.yaw)
|
||||
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll);
|
||||
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.roll)
|
||||
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.pitch)
|
||||
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw);
|
||||
}
|
||||
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
||||
const float far) noexcept
|
||||
|
||||
@@ -1,3 +1,108 @@
|
||||
//
|
||||
// Created by Vlad on 8/25/2025.
|
||||
//
|
||||
//
|
||||
// Created by Orange on 11/27/2024.
|
||||
//
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/engines/unreal_engine/camera.hpp>
|
||||
#include <omath/engines/unreal_engine/constants.hpp>
|
||||
#include <omath/engines/unreal_engine/formulas.hpp>
|
||||
#include <print>
|
||||
|
||||
TEST(unit_test_unreal_engine, ForwardVector)
|
||||
{
|
||||
const auto forward = omath::unreal_engine::forward_vector({});
|
||||
|
||||
EXPECT_EQ(forward, omath::unreal_engine::k_abs_forward);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, ForwardVectorRotationYaw)
|
||||
{
|
||||
omath::unreal_engine::ViewAngles angles;
|
||||
|
||||
angles.yaw = omath::unreal_engine::YawAngle::from_degrees(90.f);
|
||||
|
||||
const auto forward = omath::unreal_engine::forward_vector(angles);
|
||||
EXPECT_NEAR(forward.x, omath::unreal_engine::k_abs_right.x, 0.00001f);
|
||||
EXPECT_NEAR(forward.y, omath::unreal_engine::k_abs_right.y, 0.00001f);
|
||||
EXPECT_NEAR(forward.z, omath::unreal_engine::k_abs_right.z, 0.00001f);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, ForwardVectorRotationPitch)
|
||||
{
|
||||
omath::unreal_engine::ViewAngles angles;
|
||||
|
||||
angles.pitch = omath::unreal_engine::PitchAngle::from_degrees(-90.f);
|
||||
|
||||
const auto forward = omath::unreal_engine::forward_vector(angles);
|
||||
EXPECT_NEAR(forward.x, omath::unreal_engine::k_abs_up.x, 0.00001f);
|
||||
EXPECT_NEAR(forward.y, omath::unreal_engine::k_abs_up.y, 0.00001f);
|
||||
EXPECT_NEAR(forward.z, omath::unreal_engine::k_abs_up.z, 0.00001f);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, ForwardVectorRotationRoll)
|
||||
{
|
||||
omath::unreal_engine::ViewAngles angles;
|
||||
|
||||
angles.roll = omath::unreal_engine::RollAngle::from_degrees(-90.f);
|
||||
|
||||
const auto forward = omath::unreal_engine::up_vector(angles);
|
||||
EXPECT_NEAR(forward.x, omath::unreal_engine::k_abs_right.x, 0.00001f);
|
||||
EXPECT_NEAR(forward.y, omath::unreal_engine::k_abs_right.y, 0.00001f);
|
||||
EXPECT_NEAR(forward.z, omath::unreal_engine::k_abs_right.z, 0.00001f);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, RightVector)
|
||||
{
|
||||
const auto right = omath::unreal_engine::right_vector({});
|
||||
|
||||
EXPECT_EQ(right, omath::unreal_engine::k_abs_right);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, UpVector)
|
||||
{
|
||||
const auto up = omath::unreal_engine::up_vector({});
|
||||
EXPECT_EQ(up, omath::unreal_engine::k_abs_up);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, ProjectTargetMovedFromCamera)
|
||||
{
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||
const auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
|
||||
for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
|
||||
{
|
||||
const auto projected = cam.world_to_screen({distance, 0, 0});
|
||||
|
||||
EXPECT_TRUE(projected.has_value());
|
||||
|
||||
if (!projected.has_value())
|
||||
continue;
|
||||
|
||||
EXPECT_NEAR(projected->x, 640, 0.00001f);
|
||||
EXPECT_NEAR(projected->y, 360, 0.00001f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, CameraSetAndGetFov)
|
||||
{
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 90.f);
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, CameraSetAndGetOrigin)
|
||||
{
|
||||
auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
|
||||
|
||||
EXPECT_EQ(cam.get_origin(), omath::Vector3<float>{});
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
Reference in New Issue
Block a user