Terrain-sky smooth ratio rendering

This commit is contained in:
JackCarterSmith 2024-12-11 17:21:23 +01:00
parent bf7b10850e
commit 2854da4053
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
7 changed files with 217 additions and 5 deletions

View File

@ -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_vec.inl"
"${CMAKE_CURRENT_SOURCE_DIR}/Engine/Utils/3DMaths_mat.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_bs.inl"
"${CMAKE_CURRENT_SOURCE_DIR}/Engine/Utils/3DMaths_sc.inl"
) )
# targets build options # targets build options

View File

@ -109,7 +109,6 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) {
M3D_BoundingFrustum camFrustrum(projMat, false); M3D_BoundingFrustum camFrustrum(projMat, false);
camFrustrum.Transform(camFrustrum, invViewMat); camFrustrum.Transform(camFrustrum, invViewMat);
const float sgRatio = std::tan(mMainCamera->GetLook3f().y);
// -= Draw the sky =- // -= Draw the sky =-
// To avoid unfilled pixels on screen, the "sky-plane" will be rendered // To avoid unfilled pixels on screen, the "sky-plane" will be rendered
// all over the screen. // 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. // 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 // Like the sky, the ground have an infinite z-depth (any objects will
// be rendered over). // be rendered over).
sf::RectangleShape gndRect(sf::Vector2f(1280, mRTSize.y * (0.5f - sgRatio))); const float sgRatio = ComputeSGRatio();
gndRect.setPosition(sf::Vector2f(0, mRTSize.y * (0.5f + sgRatio))); 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); gndRect.setFillColor(sf::Color::Green);
context.draw(gndRect, sRS); context.draw(gndRect, sRS);
@ -228,6 +234,21 @@ void Graphic3DRenderer::UpdateInternalTestObjects() {
mRenderList[3]->SetRotation(0.f, thetaAngle, 0.f); 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) { 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 // 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 && return (V.x > -RTsize.x*gb_factor*V.w && V.x < RTsize.y*gb_factor*V.w &&

View File

@ -39,5 +39,6 @@ private:
std::vector<std::shared_ptr<WorldObject>> mRenderList; // List of elements to be rendered next frame std::vector<std::shared_ptr<WorldObject>> mRenderList; // List of elements to be rendered next frame
void UpdateInternalTestObjects(); void UpdateInternalTestObjects();
float ComputeSGRatio();
}; };

View File

@ -7,6 +7,7 @@ Camera::Camera() {
void Camera::SetFrustrum(float fov, float r, float zn, float zf) { void Camera::SetFrustrum(float fov, float r, float zn, float zf) {
//if (!frameDirty) //if (!frameDirty)
this->fov = fov;
M3D_MATRIX pMat = M3D_TransformMatrixFrustrumFovLH(M3D_Deg2Rad(fov), r, zn, zf); M3D_MATRIX pMat = M3D_TransformMatrixFrustrumFovLH(M3D_Deg2Rad(fov), r, zn, zf);
M3D_V4StoreF4x4(&mProjMat, pMat); M3D_V4StoreF4x4(&mProjMat, pMat);
} }

View File

@ -13,6 +13,7 @@ public:
Camera(Camera const&) = delete; Camera(Camera const&) = delete;
Camera& operator= (Camera const&) = delete; Camera& operator= (Camera const&) = delete;
float GetFoV() const { return fov; }
M3D_VECTOR GetPos() const { return M3D_V4LoadF3(&mPos); } M3D_VECTOR GetPos() const { return M3D_V4LoadF3(&mPos); }
M3D_F3 GetPos3f() const { return mPos; } M3D_F3 GetPos3f() const { return mPos; }
M3D_VECTOR GetLook() const { return M3D_V4LoadF3(&mLook); } M3D_VECTOR GetLook() const { return M3D_V4LoadF3(&mLook); }
@ -38,9 +39,17 @@ public:
void Yaw(float angle); void Yaw(float angle);
private: private:
float fov;
M3D_F4X4 mProjMat = M3D_MIdentity4x4(); M3D_F4X4 mProjMat = M3D_MIdentity4x4();
M3D_F4X4 mViewMat = 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 mPos = {0.0f, 0.0f, 0.0f};
M3D_F3 mRight = {1.0f, 0.0f, 0.0f}; M3D_F3 mRight = {1.0f, 0.0f, 0.0f};
M3D_F3 mUp = {0.0f, 1.0f, 0.0f}; M3D_F3 mUp = {0.0f, 1.0f, 0.0f};

View File

@ -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; 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 // Common values for vector/matrix manipulation
// //
@ -898,4 +910,5 @@ M3D_GCONST M3D_V4F32 M3D_BBoxOffset[8] = {
#include "3DMaths_vec.inl" #include "3DMaths_vec.inl"
#include "3DMaths_mat.inl" #include "3DMaths_mat.inl"
#include "3DMaths_bs.inl" #include "3DMaths_bs.inl"
#include "3DMaths_sc.inl"

166
Engine/Utils/3DMaths_sc.inl Normal file
View File

@ -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<float>(static_cast<int>(quotient + 0.5f));
else
quotient = static_cast<float>(static_cast<int>(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<float>(static_cast<int>(quotient + 0.5f));
else
quotient = static_cast<float>(static_cast<int>(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<float>(static_cast<int>(quotient + 0.5f));
else
quotient = static_cast<float>(static_cast<int>(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<float>(static_cast<int>(quotient + 0.5f));
else
quotient = static_cast<float>(static_cast<int>(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);
}