diff --git a/CMakeLists.txt b/CMakeLists.txt index 70e50dc..eff0da8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ target_sources(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/Engine/Utils/3DMaths_vec.inl" "${CMAKE_CURRENT_SOURCE_DIR}/Engine/Utils/3DMaths_mat.inl" "${CMAKE_CURRENT_SOURCE_DIR}/Engine/Utils/3DMaths_bs.inl" + "${CMAKE_CURRENT_SOURCE_DIR}/Engine/Utils/3DMaths_sc.inl" ) # targets build options diff --git a/Engine/Graphics/3DRenderer.cpp b/Engine/Graphics/3DRenderer.cpp index e8d3de1..a5f8ac6 100644 --- a/Engine/Graphics/3DRenderer.cpp +++ b/Engine/Graphics/3DRenderer.cpp @@ -109,7 +109,6 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) { M3D_BoundingFrustum camFrustrum(projMat, false); camFrustrum.Transform(camFrustrum, invViewMat); - const float sgRatio = std::tan(mMainCamera->GetLook3f().y); // -= Draw the sky =- // To avoid unfilled pixels on screen, the "sky-plane" will be rendered // all over the screen. @@ -124,8 +123,15 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) { // Depending of the camera pitch, the ratio sky/ground on screen vary. // Like the sky, the ground have an infinite z-depth (any objects will // be rendered over). - sf::RectangleShape gndRect(sf::Vector2f(1280, mRTSize.y * (0.5f - sgRatio))); - gndRect.setPosition(sf::Vector2f(0, mRTSize.y * (0.5f + sgRatio))); + const float sgRatio = ComputeSGRatio(); + sf::RectangleShape gndRect; + if (mMainCamera->GetPos3f().y >= 0) { + gndRect.setSize(sf::Vector2f(1280, mRTSize.y * (1.f - sgRatio))); + gndRect.setPosition(sf::Vector2f(0, mRTSize.y * sgRatio)); + } else { + gndRect.setSize(sf::Vector2f(1280, mRTSize.y * sgRatio)); + gndRect.setPosition(sf::Vector2f(0, 0)); + } gndRect.setFillColor(sf::Color::Green); context.draw(gndRect, sRS); @@ -228,6 +234,21 @@ void Graphic3DRenderer::UpdateInternalTestObjects() { mRenderList[3]->SetRotation(0.f, thetaAngle, 0.f); } +inline float Graphic3DRenderer::ComputeSGRatio() { + // FoV angle for Y axis is recovered using frustrum FoV and apply RT screen ratio to it + const float fovYAngle = M3D_Deg2Rad(mMainCamera->GetFoV() * (mRTSize.y/mRTSize.x)); + // Get the camera pitch angle over camera FoV ratio + float sgRatio = M3D_ScalarASinEst(mMainCamera->GetLook3f().y) / fovYAngle; + + // Clamp and re-scale + if (sgRatio > M3D_PIDIV2) + sgRatio = M3D_PIDIV2; + else if (sgRatio < -M3D_PIDIV2) + sgRatio = -M3D_PIDIV2; + + return ((sgRatio - M3D_PIDIV2) / M3D_PI) + 1.f; +} + inline static bool VertexClipTest(M3D_F4& V, sf::Vector2f& RTsize, float gb_factor) { // Guard band are usually 2-3x the viewport size for the clipping test return (V.x > -RTsize.x*gb_factor*V.w && V.x < RTsize.y*gb_factor*V.w && diff --git a/Engine/Graphics/3DRenderer.hpp b/Engine/Graphics/3DRenderer.hpp index 8cc2d53..cdcbfee 100644 --- a/Engine/Graphics/3DRenderer.hpp +++ b/Engine/Graphics/3DRenderer.hpp @@ -39,5 +39,6 @@ private: std::vector> mRenderList; // List of elements to be rendered next frame void UpdateInternalTestObjects(); - + float ComputeSGRatio(); + }; \ No newline at end of file diff --git a/Engine/Graphics/Camera.cpp b/Engine/Graphics/Camera.cpp index f546eda..4808206 100644 --- a/Engine/Graphics/Camera.cpp +++ b/Engine/Graphics/Camera.cpp @@ -7,6 +7,7 @@ Camera::Camera() { void Camera::SetFrustrum(float fov, float r, float zn, float zf) { //if (!frameDirty) + this->fov = fov; M3D_MATRIX pMat = M3D_TransformMatrixFrustrumFovLH(M3D_Deg2Rad(fov), r, zn, zf); M3D_V4StoreF4x4(&mProjMat, pMat); } diff --git a/Engine/Graphics/Camera.hpp b/Engine/Graphics/Camera.hpp index 01dc1fe..2d01b3f 100644 --- a/Engine/Graphics/Camera.hpp +++ b/Engine/Graphics/Camera.hpp @@ -13,6 +13,7 @@ public: Camera(Camera const&) = delete; Camera& operator= (Camera const&) = delete; + float GetFoV() const { return fov; } M3D_VECTOR GetPos() const { return M3D_V4LoadF3(&mPos); } M3D_F3 GetPos3f() const { return mPos; } M3D_VECTOR GetLook() const { return M3D_V4LoadF3(&mLook); } @@ -38,9 +39,17 @@ public: void Yaw(float angle); private: + float fov; + M3D_F4X4 mProjMat = M3D_MIdentity4x4(); M3D_F4X4 mViewMat = M3D_MIdentity4x4(); + /* + right-x up-x look-x pos-x + right-y up-y look-y pos-y + right-z up-z look-z pos-z + 0 0 0 1 + */ M3D_F3 mPos = {0.0f, 0.0f, 0.0f}; M3D_F3 mRight = {1.0f, 0.0f, 0.0f}; M3D_F3 mUp = {0.0f, 1.0f, 0.0f}; diff --git a/Engine/Utils/3DMaths.hpp b/Engine/Utils/3DMaths.hpp index e745ec7..b2a2e21 100644 --- a/Engine/Utils/3DMaths.hpp +++ b/Engine/Utils/3DMaths.hpp @@ -594,6 +594,18 @@ M3D_MATRIX M3D_TransformMatrixRotationAxis(M3D_VECTOR axis, float angle) noexcep M3D_MATRIX M3D_TransformMatrixViewport(float _w, float _h, float _wOffset, float _hOffset) noexcept; +// +// Math enhanced trigo +// +float M3D_ScalarSin(float Value) noexcept; +float M3D_ScalarSinEst(float Value) noexcept; +float M3D_ScalarCos(float Value) noexcept; +float M3D_ScalarCosEst(float Value) noexcept; +float M3D_ScalarASin(float Value) noexcept; +float M3D_ScalarASinEst(float Value) noexcept; +float M3D_ScalarACos(float Value) noexcept; +float M3D_ScalarACosEst(float Value) noexcept; + // // Common values for vector/matrix manipulation // @@ -898,4 +910,5 @@ M3D_GCONST M3D_V4F32 M3D_BBoxOffset[8] = { #include "3DMaths_vec.inl" #include "3DMaths_mat.inl" -#include "3DMaths_bs.inl" \ No newline at end of file +#include "3DMaths_bs.inl" +#include "3DMaths_sc.inl" \ No newline at end of file diff --git a/Engine/Utils/3DMaths_sc.inl b/Engine/Utils/3DMaths_sc.inl new file mode 100644 index 0000000..5f4e02e --- /dev/null +++ b/Engine/Utils/3DMaths_sc.inl @@ -0,0 +1,166 @@ +#pragma once + + +inline float M3D_ScalarSin(float Value) noexcept { + // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder. + float quotient = M3D_1DIV2PI * Value; + if (Value >= 0.0f) + quotient = static_cast(static_cast(quotient + 0.5f)); + else + quotient = static_cast(static_cast(quotient - 0.5f)); + float y = Value - M3D_2PI * quotient; + + // Map y to [-pi/2,pi/2] with sin(y) = sin(Value). + if (y > M3D_PIDIV2) + y = M3D_PI - y; + else if (y < -M3D_PIDIV2) + y = -M3D_PI - y; + + // 11-degree minimax approximation + float y2 = y * y; + return (((((-2.3889859e-08f * y2 + 2.7525562e-06f) * y2 - 0.00019840874f) * y2 + 0.0083333310f) * y2 - 0.16666667f) * y2 + 1.0f) * y; +} + +inline float M3D_ScalarSinEst(float Value) noexcept { + // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder. + float quotient = M3D_1DIV2PI * Value; + if (Value >= 0.0f) + quotient = static_cast(static_cast(quotient + 0.5f)); + else + quotient = static_cast(static_cast(quotient - 0.5f)); + float y = Value - M3D_2PI * quotient; + + // Map y to [-pi/2,pi/2] with sin(y) = sin(Value). + if (y > M3D_PIDIV2) + y = M3D_PI - y; + else if (y < -M3D_PIDIV2) + y = -M3D_PI - y; + + // 7-degree minimax approximation + float y2 = y * y; + return (((-0.00018524670f * y2 + 0.0083139502f) * y2 - 0.16665852f) * y2 + 1.0f) * y; +} + +inline float M3D_ScalarCos(float Value) noexcept { + // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder. + float quotient = M3D_1DIV2PI * Value; + if (Value >= 0.0f) + quotient = static_cast(static_cast(quotient + 0.5f)); + else + quotient = static_cast(static_cast(quotient - 0.5f)); + float y = Value - M3D_2PI * quotient; + + // Map y to [-pi/2,pi/2] with cos(y) = sign*cos(x). + float sign; + if (y > M3D_PIDIV2) { + y = M3D_PI - y; + sign = -1.0f; + } else if (y < -M3D_PIDIV2) { + y = -M3D_PI - y; + sign = -1.0f; + } else { + sign = +1.0f; + } + + // 10-degree minimax approximation + float y2 = y * y; + float p = ((((-2.6051615e-07f * y2 + 2.4760495e-05f) * y2 - 0.0013888378f) * y2 + 0.041666638f) * y2 - 0.5f) * y2 + 1.0f; + return sign * p; +} + +inline float M3D_ScalarCosEst(float Value) noexcept { + // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder. + float quotient = M3D_1DIV2PI * Value; + if (Value >= 0.0f) + quotient = static_cast(static_cast(quotient + 0.5f)); + else + quotient = static_cast(static_cast(quotient - 0.5f)); + float y = Value - M3D_2PI * quotient; + + // Map y to [-pi/2,pi/2] with cos(y) = sign*cos(x). + float sign; + if (y > M3D_PIDIV2) { + y = M3D_PI - y; + sign = -1.0f; + } else if (y < -M3D_PIDIV2) { + y = -M3D_PI - y; + sign = -1.0f; + } else { + sign = +1.0f; + } + + // 6-degree minimax approximation + float y2 = y * y; + float p = ((-0.0012712436f * y2 + 0.041493919f) * y2 - 0.49992746f) * y2 + 1.0f; + return sign * p; +} + +inline float M3D_ScalarASin(float Value) noexcept { + // Clamp input to [-1,1]. + bool nonnegative = (Value >= 0.0f); + float x = std::fabs(Value); + float omx = 1.0f - x; + if (omx < 0.0f) + omx = 0.0f; + float root = std::sqrt(omx); + + // 7-degree minimax approximation + float result = ((((((-0.0012624911f * x + 0.0066700901f) * x - 0.0170881256f) * x + 0.0308918810f) * x - 0.0501743046f) * x + 0.0889789874f) * x - 0.2145988016f) * x + 1.5707963050f; + result *= root; // acos(|x|) + + // acos(x) = pi - acos(-x) when x < 0, asin(x) = pi/2 - acos(x) + return (nonnegative ? M3D_PIDIV2 - result : result - M3D_PIDIV2); +} + +inline float M3D_ScalarASinEst(float Value) noexcept { + // Clamp input to [-1,1]. + bool nonnegative = (Value >= 0.0f); + float x = std::fabs(Value); + float omx = 1.0f - x; + if (omx < 0.0f) + { + omx = 0.0f; + } + float root = std::sqrt(omx); + + // 3-degree minimax approximation + float result = ((-0.0187293f * x + 0.0742610f) * x - 0.2121144f) * x + 1.5707288f; + result *= root; // acos(|x|) + + // acos(x) = pi - acos(-x) when x < 0, asin(x) = pi/2 - acos(x) + return (nonnegative ? M3D_PIDIV2 - result : result - M3D_PIDIV2); +} + +inline float M3D_ScalarACos(float Value) noexcept { + // Clamp input to [-1,1]. + bool nonnegative = (Value >= 0.0f); + float x = std::fabs(Value); + float omx = 1.0f - x; + if (omx < 0.0f) + omx = 0.0f; + float root = std::sqrt(omx); + + // 7-degree minimax approximation + float result = ((((((-0.0012624911f * x + 0.0066700901f) * x - 0.0170881256f) * x + 0.0308918810f) * x - 0.0501743046f) * x + 0.0889789874f) * x - 0.2145988016f) * x + 1.5707963050f; + result *= root; + + // acos(x) = pi - acos(-x) when x < 0 + return (nonnegative ? result : M3D_PI - result); +} + +inline float M3D_ScalarACosEst(float Value) noexcept { + // Clamp input to [-1,1]. + bool nonnegative = (Value >= 0.0f); + float x = std::fabs(Value); + float omx = 1.0f - x; + if (omx < 0.0f) + omx = 0.0f; + float root = std::sqrt(omx); + + // 3-degree minimax approximation + float result = ((-0.0187293f * x + 0.0742610f) * x - 0.2121144f) * x + 1.5707288f; + result *= root; + + // acos(x) = pi - acos(-x) when x < 0 + return (nonnegative ? result : M3D_PI - result); +} \ No newline at end of file