mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-11 16:45:48 -04:00
Direct3D11: Use reverse depth buffer for better range precision (Thanks 123DMWM)
This should reduce Z-fighting with very far away objects, e.g. the water/bedrock outside level with a view distance of 4096
This commit is contained in:
parent
9411b5d63f
commit
cc18e0a449
@ -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" \
|
||||
|
@ -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;
|
||||
|
@ -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]) */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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!)
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user