diff --git a/misc/D3D11ShaderGen.c b/misc/D3D11ShaderGen.c index 558ebfd81..724aa8859 100644 --- a/misc/D3D11ShaderGen.c +++ b/misc/D3D11ShaderGen.c @@ -84,12 +84,12 @@ static const char PS_SOURCE[] = " if (color.a < 0.5) { discard; return color; } \n" \ "#endif \n" \ "#ifdef PS_FOG_LINEAR \n" \ -" float depth = input.position.z * input.position.w; \n" \ +" float depth = input.position.w; \n" \ " float fog = saturate((fogEnd - depth) / fogEnd); \n" \ " color.rgb = lerp(fogColor, color.rgb, fog); \n" \ "#endif \n" \ "#ifdef PS_FOG_DENSITY \n" \ -" float depth = input.position.z * input.position.w; \n" \ +" float depth = input.position.w; \n" \ " float fog = saturate(exp(fogDensity * depth)); \n" \ " color.rgb = lerp(fogColor, color.rgb, fog); \n" \ "#endif \n" \ diff --git a/src/Camera.c b/src/Camera.c index 9bd233584..659e119a6 100644 --- a/src/Camera.c +++ b/src/Camera.c @@ -27,7 +27,7 @@ static void Camera_OnRawMovement(float deltaX, float deltaY) { static void PerspectiveCamera_GetProjection(struct Matrix* proj) { float fovy = Camera.Fov * MATH_DEG2RAD; float aspectRatio = (float)Game.Width / (float)Game.Height; - Gfx_CalcPerspectiveMatrix(fovy, aspectRatio, (float)Game_ViewDistance, proj); + Gfx_CalcPerspectiveMatrix(proj, fovy, aspectRatio, (float)Game_ViewDistance); } static void PerspectiveCamera_GetView(struct Matrix* mat) { @@ -137,7 +137,8 @@ static void PerspectiveCamera_CalcViewBobbing(float t, float velTiltScale) { static Vec2 FirstPersonCamera_GetOrientation(void) { struct Entity* p = &LocalPlayer_Instance.Base; Vec2 v; - v.X = p->Yaw * MATH_DEG2RAD; v.Y = p->Pitch * MATH_DEG2RAD; + v.X = p->Yaw * MATH_DEG2RAD; + v.Y = p->Pitch * MATH_DEG2RAD; return v; } @@ -173,7 +174,8 @@ static float dist_third = DEF_ZOOM, dist_forward = DEF_ZOOM; static Vec2 ThirdPersonCamera_GetOrientation(void) { struct Entity* p = &LocalPlayer_Instance.Base; Vec2 v; - v.X = p->Yaw * MATH_DEG2RAD; v.Y = p->Pitch * MATH_DEG2RAD; + v.X = p->Yaw * MATH_DEG2RAD; + v.Y = p->Pitch * MATH_DEG2RAD; if (cam_isForwardThird) { v.X += MATH_PI; v.Y = -v.Y; } v.X += cam_rotOffset.X * MATH_DEG2RAD; diff --git a/src/Graphics.h b/src/Graphics.h index c3c441c7e..26743ad76 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -202,9 +202,9 @@ CC_API void Gfx_EnableTextureOffset(float x, float y); CC_API void Gfx_DisableTextureOffset(void); /* Calculates an orthographic projection matrix suitable with this backend. (usually for 2D) */ -void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix); +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar); /* Calculates a perspective projection matrix suitable with this backend. (usually for 3D) */ -void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix); +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar); /* NOTE: Projection matrix calculation is here because it can depend the graphics backend */ /* (e.g. OpenGL uses a Z clip space range of [-1, 1], whereas Direct3D9 uses [0, 1]) */ diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c index 40ab6e6b2..f29bd0739 100644 --- a/src/Graphics_3DS.c +++ b/src/Graphics_3DS.c @@ -441,11 +441,11 @@ void Gfx_SetFogMode(FogFunc func) { *#########################################################################################################################*/ static C3D_Mtx _view, _proj; -void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { - Mtx_OrthoTilt(matrix, 0.0f, width, height, 0.0f, ORTHO_NEAR, ORTHO_FAR, true); +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) { + Mtx_OrthoTilt(matrix, 0.0f, width, height, 0.0f, zNear, zFar, true); } -void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) { +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { Mtx_PerspTilt(matrix, fov, aspect, 0.1f, zFar, true); } diff --git a/src/Graphics_D3D11.c b/src/Graphics_D3D11.c index 043449364..5c14ad9af 100644 --- a/src/Graphics_D3D11.c +++ b/src/Graphics_D3D11.c @@ -432,24 +432,40 @@ void Gfx_SetDynamicVbData(GfxResourceID vb, void* vertices, int vCount) { /*########################################################################################################################* *---------------------------------------------------------Matrices--------------------------------------------------------* *#########################################################################################################################*/ -void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { - Matrix_Orthographic(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR); - matrix->row3.Z = 1.0f / (ORTHO_NEAR - ORTHO_FAR); - matrix->row4.Z = ORTHO_NEAR / (ORTHO_NEAR - ORTHO_FAR); +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) { + // Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthooffcenterrh + // The simplified calculation below uses: L = 0, R = width, T = 0, B = height + // NOTE: This calculation is shared with Direct3D 9 backend + *matrix = Matrix_Identity; + + matrix->row1.X = 2.0f / width; + matrix->row2.Y = -2.0f / height; + matrix->row3.Z = 1.0f / (zNear - zFar); + + matrix->row4.X = -1.0f; + matrix->row4.Y = 1.0f; + matrix->row4.Z = zNear / (zNear - zFar); } -static float CalcZNear(float fov) { - /* With reversed z depth, near Z plane can be much closer (with sufficient depth buffer precision) */ - /* This reduces clipping with high FOV without sacrificing depth precision for faraway objects */ - /* However for low FOV, don't reduce near Z in order to gain a bit more depth precision */ - if (depthBits < 24 || fov <= 70 * MATH_DEG2RAD) return 0.05f; - if (fov <= 100 * MATH_DEG2RAD) return 0.025f; - if (fov <= 150 * MATH_DEG2RAD) return 0.0125f; - return 0.00390625f; -} +static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { + // Deliberately swap zNear/zFar in projection matrix calculation to produce + // a projection matrix that results in a reversed depth buffer + // https://developer.nvidia.com/content/depth-precision-visualized + float zNear_ = zFar; + float zFar_ = Reversed_CalcZNear(fov, 24); // TODO don't always hardcode to 24 bits -void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) { - Matrix_PerspectiveFieldOfView(matrix, fov, aspect, CalcZNear(fov), zFar); + // Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh + // NOTE: This calculation is shared with Direct3D 9 backend + float c = (float)Cotangent(0.5f * fov); + *matrix = Matrix_Identity; + + matrix->row1.X = c / aspect; + matrix->row2.Y = c; + matrix->row3.Z = zFar_ / (zNear_ - zFar_); + matrix->row3.W = -1.0f; + matrix->row4.Z = (zNear_ * zFar_) / (zNear_ - zFar_); + matrix->row4.W = 0.0f; } //#####################z################################################################################################### @@ -874,7 +890,7 @@ static cc_bool gfx_depthTest, gfx_depthWrite; static void OM_Clear(void) { ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer, gfx_clearColor); - ID3D11DeviceContext_ClearDepthStencilView(context, depthbufferView, D3D11_CLEAR_DEPTH, 1.0f, 0); + ID3D11DeviceContext_ClearDepthStencilView(context, depthbufferView, D3D11_CLEAR_DEPTH, 0.0f, 0); } static void OM_InitTargets(void) { @@ -906,7 +922,7 @@ static void OM_InitTargets(void) { static void OM_CreateDepthStates(void) { D3D11_DEPTH_STENCIL_DESC desc = { 0 }; HRESULT hr; - desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + desc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; for (int i = 0; i < Array_Elems(om_depthStates); i++) { desc.DepthEnable = (i & 1) != 0; diff --git a/src/Graphics_D3D9.c b/src/Graphics_D3D9.c index 189066abf..6850d01e5 100644 --- a/src/Graphics_D3D9.c +++ b/src/Graphics_D3D9.c @@ -716,11 +716,10 @@ void Gfx_DisableTextureOffset(void) { IDirect3DDevice9_SetTransform(device, D3DTS_TEXTURE0, (const D3DMATRIX*)&Matrix_Identity); } -void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) { /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthooffcenterrh */ /* The simplified calculation below uses: L = 0, R = width, T = 0, B = height */ /* NOTE: This calculation is shared with Direct3D 11 backend */ - float zNear = ORTHO_NEAR, zFar = ORTHO_FAR; *matrix = Matrix_Identity; matrix->row1.X = 2.0f / width; @@ -733,7 +732,7 @@ void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { } static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } -void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) { +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { /* Deliberately swap zNear/zFar in projection matrix calculation to produce */ /* a projection matrix that results in a reversed depth buffer */ /* https://developer.nvidia.com/content/depth-precision-visualized */ diff --git a/src/Graphics_PSP.c b/src/Graphics_PSP.c index 1d6df08cc..fd5b7f61a 100644 --- a/src/Graphics_PSP.c +++ b/src/Graphics_PSP.c @@ -188,12 +188,38 @@ void Gfx_SetDepthTest(cc_bool enabled) { GU_Toggle(GU_DEPTH_TEST); } /*########################################################################################################################* *---------------------------------------------------------Matrices--------------------------------------------------------* *#########################################################################################################################*/ -void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { - Matrix_Orthographic(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR); +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) { + // Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glortho + // The simplified calculation below uses: L = 0, R = width, T = 0, B = height + // NOTE: Shared with OpenGL. might be wrong to do that though? + *matrix = Matrix_Identity; + + matrix->row1.X = 2.0f / width; + matrix->row2.Y = -2.0f / height; + matrix->row3.Z = -2.0f / (zFar - zNear); + + matrix->row4.X = -1.0f; + matrix->row4.Y = 1.0f; + matrix->row4.Z = -(zFar + zNear) / (zFar - zNear); } -void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) { + +static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar); + float c = (float)Cotangent(0.5f * fov); + + // Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum + // For a FOV based perspective matrix, left/right/top/bottom are calculated as: + // left = -c * aspect, right = c * aspect, bottom = -c, top = c + // Calculations are simplified because of left/right and top/bottom symmetry + *matrix = Matrix_Identity; + + matrix->row1.X = c / aspect; + matrix->row2.Y = c; + matrix->row3.Z = -(zFar + zNear) / (zFar - zNear); + matrix->row3.W = -1.0f; + matrix->row4.Z = -(2.0f * zFar * zNear) / (zFar - zNear); + matrix->row4.W = 0.0f; } diff --git a/src/HeldBlockRenderer.c b/src/HeldBlockRenderer.c index 9a3ca284f..abe6a8120 100644 --- a/src/HeldBlockRenderer.c +++ b/src/HeldBlockRenderer.c @@ -93,7 +93,8 @@ static void SetBaseOffset(void) { static void OnProjectionChanged(void* obj) { float fov = 70.0f * MATH_DEG2RAD; float aspectRatio = (float)Game.Width / (float)Game.Height; - Gfx_CalcPerspectiveMatrix(fov, aspectRatio, (float)Game_ViewDistance, &held_blockProjection); + Gfx_CalcPerspectiveMatrix(&held_blockProjection, + fov, aspectRatio, (float)Game_ViewDistance); } /* Based off incredible gifs from (Thanks goodlyay!) diff --git a/src/Vectors.c b/src/Vectors.c index 371c5bd8e..32c951e9c 100644 --- a/src/Vectors.c +++ b/src/Vectors.c @@ -166,37 +166,6 @@ void Matrix_Mul(struct Matrix* result, const struct Matrix* left, const struct M result->row4.W = (((lM41 * rM14) + (lM42 * rM24)) + (lM43 * rM34)) + (lM44 * rM44); } -void Matrix_Orthographic(struct Matrix* result, float left, float right, float top, float bottom, float zNear, float zFar) { - /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glortho */ - *result = Matrix_Identity; - - result->row1.X = 2.0f / (right - left); - result->row2.Y = 2.0f / (top - bottom); - result->row3.Z = -2.0f / (zFar - zNear); - - result->row4.X = -(right + left) / (right - left); - result->row4.Y = -(top + bottom) / (top - bottom); - result->row4.Z = -(zFar + zNear) / (zFar - zNear); -} - -static double Tan_Simple(double x) { return Math_Sin(x) / Math_Cos(x); } -void Matrix_PerspectiveFieldOfView(struct Matrix* result, float fovy, float aspect, float zNear, float zFar) { - float c = (float)Tan_Simple(0.5f * fovy); - - /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ - /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ - /* left = -c * aspect, right = c * aspect, bottom = -c, top = c */ - /* Calculations are simplified because of left/right and top/bottom symmetry */ - *result = Matrix_Identity; - - result->row1.X = 1.0f / (c * aspect); - result->row2.Y = 1.0f / c; - result->row3.Z = -(zFar + zNear) / (zFar - zNear); - result->row4.Z = -(2.0f * zFar * zNear) / (zFar - zNear); - result->row3.W = -1.0f; - result->row4.W = 0.0f; -} - void Matrix_LookRot(struct Matrix* result, Vec3 pos, Vec2 rot) { struct Matrix rotX, rotY, trans; Matrix_RotateX(&rotX, rot.Y); @@ -274,8 +243,8 @@ void FrustumCulling_CalcFrustumEquations(struct Matrix* projection, struct Matri FrustumCulling_Normalise(&frustum30, &frustum31, &frustum32, &frustum33); /* Extract the FAR plane (Different for each graphics backend) */ -#if defined CC_BUILD_D3D9 - /* OpenGL and Direct3D9 require slightly different behaviour for NEAR clipping planes */ +#if defined CC_BUILD_D3D9 || defined CC_BUILD_D3D11 + /* OpenGL and Direct3D require slightly different behaviour for NEAR clipping planes */ /* https://www.gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf */ /* (and because reverse Z is used, 'NEAR' plane is actually the 'FAR' clipping plane) */ frustum40 = clip[2]; diff --git a/src/Vectors.h b/src/Vectors.h index 4638a2354..f6aadb886 100644 --- a/src/Vectors.h +++ b/src/Vectors.h @@ -129,8 +129,6 @@ CC_API void Matrix_Scale(struct Matrix* result, float x, float y, float z); /* NOTE: result can be the same pointer as left or right. */ CC_API void Matrix_Mul(struct Matrix* result, const struct Matrix* left, const struct Matrix* right); -void Matrix_Orthographic(struct Matrix* result, float left, float right, float top, float bottom, float zNear, float zFar); -void Matrix_PerspectiveFieldOfView(struct Matrix* result, float fovy, float aspect, float zNear, float zFar); void Matrix_LookRot(struct Matrix* result, Vec3 pos, Vec2 rot); cc_bool FrustumCulling_SphereInFrustum(float x, float y, float z, float radius); diff --git a/src/_GLShared.h b/src/_GLShared.h index c0ddae60e..dce8e524d 100644 --- a/src/_GLShared.h +++ b/src/_GLShared.h @@ -201,12 +201,37 @@ void Gfx_SetDepthTest(cc_bool enabled) { gl_Toggle(GL_DEPTH_TEST); } /*########################################################################################################################* *---------------------------------------------------------Matrices--------------------------------------------------------* *#########################################################################################################################*/ -void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { - Matrix_Orthographic(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR); +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) { + /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glortho */ + /* The simplified calculation below uses: L = 0, R = width, T = 0, B = height */ + *matrix = Matrix_Identity; + + matrix->row1.X = 2.0f / width; + matrix->row2.Y = -2.0f / height; + matrix->row3.Z = -2.0f / (zFar - zNear); + + matrix->row4.X = -1.0f; + matrix->row4.Y = 1.0f; + matrix->row4.Z = -(zFar + zNear) / (zFar - zNear); } -void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) { + +static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar); + float c = (float)Cotangent(0.5f * fov); + + /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ + /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ + /* left = -c * aspect, right = c * aspect, bottom = -c, top = c */ + /* Calculations are simplified because of left/right and top/bottom symmetry */ + *matrix = Matrix_Identity; + + matrix->row1.X = c / aspect; + matrix->row2.Y = c; + matrix->row3.Z = -(zFar + zNear) / (zFar - zNear); + matrix->row3.W = -1.0f; + matrix->row4.Z = -(2.0f * zFar * zNear) / (zFar - zNear); + matrix->row4.W = 0.0f; } diff --git a/src/_GraphicsBase.h b/src/_GraphicsBase.h index c01d6af99..f8f59e87b 100644 --- a/src/_GraphicsBase.h +++ b/src/_GraphicsBase.h @@ -18,8 +18,6 @@ const cc_string Gfx_LowPerfMessage = String_FromConst("&eRunning in reduced perf static const int strideSizes[2] = { SIZEOF_VERTEX_COLOURED, SIZEOF_VERTEX_TEXTURED }; /* Whether mipmaps must be created for all dimensions down to 1x1 or not */ static cc_bool customMipmapsLevels; -#define ORTHO_NEAR -10000.0f -#define ORTHO_FAR 10000.0f static cc_bool gfx_vsync, gfx_fogEnabled; static float gfx_minFrameMs; @@ -205,7 +203,8 @@ void Gfx_Make2DQuad(const struct Texture* tex, PackedCol color, struct VertexTex static cc_bool gfx_hadFog; void Gfx_Begin2D(int width, int height) { struct Matrix ortho; - Gfx_CalcOrthoMatrix((float)width, (float)height, &ortho); + Gfx_CalcOrthoMatrix(&ortho, + (float)width, (float)height, -10000.0f, 10000.0f); Gfx_LoadMatrix(MATRIX_PROJECTION, &ortho); Gfx_LoadIdentityMatrix(MATRIX_VIEW);