From 59d8d6914bbc8879a9a7d854b4fc658d370c16f5 Mon Sep 17 00:00:00 2001 From: eukara Date: Sun, 20 Oct 2024 19:12:16 -0700 Subject: [PATCH] WIP: linear fog mode (required for Source Engine compatible fog) (#223) * r_fog_linear implementation for GLSL and Vulkan path * Linear fog in the non-GLSL backend --- engine/client/renderer.c | 2 + engine/d3d/vid_d3d.c | 5 ++- engine/gl/gl_backend.c | 17 ++++--- engine/gl/gl_rmain.c | 6 ++- engine/gl/gl_vidcommon.c | 64 +++++++++++++++++--------- engine/shaders/vulkan/sys/fog.h | 80 ++++++++++++++++++++++++--------- engine/vk/vk_init.c | 5 ++- 7 files changed, 130 insertions(+), 49 deletions(-) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 23deda655..d040afe18 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -511,6 +511,7 @@ cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Apply gamma ramps upon the desktop rather than the window."); cvar_t r_fog_cullentities = CVARD ("r_fog_cullentities", "1", "0: Never cull entities by fog...\n1: Automatically cull entities according to fog.\n2: Force fog culling regardless "); +cvar_t r_fog_linear = CVARD ("r_fog_linear", "0", "0: Use Exp/Exp2 fog. 1: Use linear fog."); cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades with distance. 0 (matching DarkPlaces's default) is typically more realistic, while 1 (matching FitzQuake and others) is more common."); cvar_t r_fog_permutation = CVARFD ("r_fog_permutation", "1", CVAR_SHADERSYSTEM, "Renders fog using a material permutation. 0 plays nicer with q3 shaders, but 1 is otherwise a better choice."); @@ -602,6 +603,7 @@ void GLRenderer_Init(void) Cvar_Register (&gl_overbright_all, GRAPHICALNICETIES); Cvar_Register (&gl_dither, GRAPHICALNICETIES); Cvar_Register (&r_fog_cullentities, GRAPHICALNICETIES); + Cvar_Register (&r_fog_linear, GLRENDEREROPTIONS); Cvar_Register (&r_fog_exp2, GLRENDEREROPTIONS); Cvar_Register (&r_fog_permutation, GLRENDEREROPTIONS); diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 1e048ebab..bd0f82e7c 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1270,9 +1270,12 @@ static void (D3D9_R_RenderView) (void) if (!r_refdef.globalfog.density) { + extern cvar_t r_fog_linear; + int fogtype = ((r_refdef.flags & RDF_UNDERWATER) && cl.fog[FOGTYPE_WATER].density)?FOGTYPE_WATER:FOGTYPE_AIR; CL_BlendFog(&r_refdef.globalfog, &cl.oldfog[fogtype], realtime, &cl.fog[fogtype]); - r_refdef.globalfog.density /= 64; //FIXME + if (!r_fog_linear.ival) + r_refdef.globalfog.density /= 64; //FIXME } //check if we can do underwater warp diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index cae33f15e..443f0d9b4 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1441,6 +1441,8 @@ void Shader_LightPass(struct shaderparsestate_s *ps, const char *shortname, cons Shader_DefaultScript(ps, shortname, shadertext); } +extern cvar_t r_fog_linear; +extern cvar_t r_fog_exp2; void GenerateFogTexture(texid_t *tex, float density, float zscale) { #define FOGS 256 @@ -1460,12 +1462,15 @@ void GenerateFogTexture(texid_t *tex, float density, float zscale) z = (float)s / (FOGS-1); z *= zscale; - if (0)//q3 - f = pow(z, 0.5); - else if (1)//GL_EXP - f = 1-exp(-density * z); - else //GL_EXP2 - f = 1-exp(-(density*density) * z); + if (r_fog_linear.ival) { + f = 1.0 - ((density - z) / (density/* - r_refdef.globalfog.depthbias*/)); //pow(z, 0.5); + } else { + if (!r_fog_exp2.ival)//GL_EXP + f = 1-exp(-density * z); + else //GL_EXP2 + f = 1-exp(-(density*density) * z); + } + if (f < 0) f = 0; if (f > 1) diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index b7a3c9204..18ed9dcd6 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -2093,9 +2093,13 @@ void GLR_RenderView (void) if (!r_refdef.globalfog.density) { + extern cvar_t r_fog_linear; + int fogtype = ((r_refdef.flags & RDF_UNDERWATER) && cl.fog[FOGTYPE_WATER].density)?FOGTYPE_WATER:FOGTYPE_AIR; CL_BlendFog(&r_refdef.globalfog, &cl.oldfog[fogtype], realtime, &cl.fog[fogtype]); - r_refdef.globalfog.density /= 64; //FIXME + + if (!r_fog_linear.ival) + r_refdef.globalfog.density /= 64; //FIXME } if (!(r_refdef.flags & RDF_NOWORLDMODEL)) diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 36e39332b..9177475cf 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1830,23 +1830,35 @@ static const char *glsl_hdrs[] = "vec3 fog3(in vec3 regularcolour)" "{" - "float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" - "z = max(0.0,z-w_fogdepthbias);\n" - "#if #include \"cvar/r_fog_exp2\"\n" - "z *= z;\n" + "float z, fac;\n" + "#if #include \"cvar/r_fog_linear\"\n" + "z = gl_FragCoord.z / gl_FragCoord.w;\n" + "fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias);\n" + "#else\n" + "z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" + "z = max(0.0,z-w_fogdepthbias);\n" + "#if #include \"cvar/r_fog_exp2\"\n" + "z *= z;\n" + "#endif\n" + "fac = exp2(-(z * 1.442695));\n" "#endif\n" - "float fac = exp2(-(z * 1.442695));\n" "fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n" "return mix(w_fogcolour, regularcolour, fac);\n" "}\n" "vec3 fog3additive(in vec3 regularcolour)" "{" - "float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" - "z = max(0.0,z-w_fogdepthbias);\n" - "#if #include \"cvar/r_fog_exp2\"\n" - "z *= z;\n" + "float z, fac;\n" + "#if #include \"cvar/r_fog_linear\"\n" + "z = gl_FragCoord.z / gl_FragCoord.w;\n" + "fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias);\n" + "#else\n" + "z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" + "z = max(0.0,z-w_fogdepthbias);\n" + "#if #include \"cvar/r_fog_exp2\"\n" + "z *= z;\n" + "#endif\n" + "fac = exp2(-(z * 1.442695));\n" "#endif\n" - "float fac = exp2(-(z * 1.442695));\n" "fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n" "return regularcolour * fac;\n" "}\n" @@ -1856,23 +1868,35 @@ static const char *glsl_hdrs[] = "}\n" "vec4 fog4additive(in vec4 regularcolour)" "{" //fog function for additive blends - "float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" - "z = max(0.0,z-w_fogdepthbias);\n" - "#if #include \"cvar/r_fog_exp2\"\n" - "z *= z;\n" + "float z, fac;\n" + "#if #include \"cvar/r_fog_linear\"\n" + "z = gl_FragCoord.z / gl_FragCoord.w;\n" + "fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias);\n" + "#else\n" + "z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" + "z = max(0.0,z-w_fogdepthbias);\n" + "#if #include \"cvar/r_fog_exp2\"\n" + "z *= z;\n" + "#endif\n" + "fac = exp2(-(z * 1.442695));\n" "#endif\n" - "float fac = exp2(-(z * 1.442695));\n" "fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n" "return regularcolour * vec4(fac, fac, fac, 1.0);\n" "}\n" "vec4 fog4blend(in vec4 regularcolour)" "{" //fog function for regular alpha blends (uses the blend for fading, to avoid fighting the surface behind) - "float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" - "z = max(0.0,z-w_fogdepthbias);\n" - "#if #include \"cvar/r_fog_exp2\"\n" - "z *= z;\n" + "float z, fac;\n" + "#if #include \"cvar/r_fog_linear\"\n" + "z = gl_FragCoord.z / gl_FragCoord.w;\n" + "fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias);\n" + "#else\n" + "z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n" + "z = max(0.0,z-w_fogdepthbias);\n" + "#if #include \"cvar/r_fog_exp2\"\n" + "z *= z;\n" + "#endif\n" + "fac = exp2(-(z * 1.442695));\n" "#endif\n" - "float fac = exp2(-(z * 1.442695));\n" "fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n" "return regularcolour * vec4(1.0, 1.0, 1.0, fac);\n" "}\n" diff --git a/engine/shaders/vulkan/sys/fog.h b/engine/shaders/vulkan/sys/fog.h index d542be4d4..ddcabd5a3 100644 --- a/engine/shaders/vulkan/sys/fog.h +++ b/engine/shaders/vulkan/sys/fog.h @@ -6,11 +6,21 @@ { if (!FOG) return regularcolour; - float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; - z = max(0.0,z-w_fogdepthbias); - if (cvar_r_fog_exp2) - z *= z; - float fac = exp2(-(z * 1.442695)); + + float z; + float fac; + + if (cvar_r_fog_linear) { + z = gl_FragCoord.z / gl_FragCoord.w; + fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias); + } else { + z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; + z = max(0.0,z-w_fogdepthbias); + if (cvar_r_fog_exp2) + z *= z; + fac = exp2(-(z * 1.442695)); + } + fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha); return mix(w_fogcolour, regularcolour, fac); } @@ -18,11 +28,21 @@ { if (!FOG) return regularcolour; - float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; - z = max(0.0,z-w_fogdepthbias); - if (cvar_r_fog_exp2) - z *= z; - float fac = exp2(-(z * 1.442695)); + + float z; + float fac; + + if (cvar_r_fog_linear) { + z = gl_FragCoord.z / gl_FragCoord.w; + fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias); + } else { + z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; + z = max(0.0,z-w_fogdepthbias); + if (cvar_r_fog_exp2) + z *= z; + fac = exp2(-(z * 1.442695)); + } + fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha); return regularcolour * fac; } @@ -36,11 +56,21 @@ { if (!FOG) return regularcolour; - float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; - z = max(0.0,z-w_fogdepthbias); - if (cvar_r_fog_exp2) - z *= z; - float fac = exp2(-(z * 1.442695)); + + float z; + float fac; + + if (cvar_r_fog_linear) { + z = gl_FragCoord.z / gl_FragCoord.w; + fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias); + } else { + z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; + z = max(0.0,z-w_fogdepthbias); + if (cvar_r_fog_exp2) + z *= z; + fac = exp2(-(z * 1.442695)); + } + fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha); return regularcolour * vec4(fac, fac, fac, 1.0); } @@ -48,11 +78,21 @@ { if (!FOG) return regularcolour; - float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; - z = max(0.0,z-w_fogdepthbias); - if (cvar_r_fog_exp2) - z *= z; - float fac = exp2(-(z * 1.442695)); + + float z; + float fac; + + if (cvar_r_fog_linear) { + z = gl_FragCoord.z / gl_FragCoord.w; + fac = (w_fogdensity - z) / (w_fogdensity - w_fogdepthbias); + } else { + z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w; + z = max(0.0,z-w_fogdepthbias); + if (cvar_r_fog_exp2) + z *= z; + fac = exp2(-(z * 1.442695)); + } + fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha); return regularcolour * vec4(1.0, 1.0, 1.0, fac); } diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 7baa6edbb..a306762fe 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -2949,9 +2949,12 @@ void VK_R_RenderView (void) if (!r_refdef.globalfog.density) { + extern cvar_t r_fog_linear; + int fogtype = ((r_refdef.flags & RDF_UNDERWATER) && cl.fog[FOGTYPE_WATER].density)?FOGTYPE_WATER:FOGTYPE_AIR; CL_BlendFog(&r_refdef.globalfog, &cl.oldfog[fogtype], realtime, &cl.fog[fogtype]); - r_refdef.globalfog.density /= 64; //FIXME + if (!r_fog_linear.ival) + r_refdef.globalfog.density /= 64; //FIXME } custompostproc = NULL;