Skip to content

Commit 39f2fe0

Browse files
committed
Draw inside of fog with modified global fog shader
When the viewer is inside a fog volume, render the fog with a single draw call instead of drawing a corresponding fog surface for every opaque surface. The fogGlobal GLSL shader is modified to use a vertex position so it can handle finite-sized fogs. Before: - Each opaque surface inside a fog volume is drawn a second time using the fog shader with GL_EQUAL depth test. - The underside of the fog plane is drawn with a normal depth test, to cover things outside the fog when the viewer is inside. After: - If the viewer is inside the fog, draw all inside faces of the fog brush, using the depth buffer to reduce the fog distance in the case that something is in front of the fog boundary. - If the viewer is outside the fog, do everything as before. For the moment this is only used when material system is disabled. Fixes seams at the edge of fog that appear when MSAA is enabled.
1 parent 2e2055f commit 39f2fe0

File tree

14 files changed

+245
-47
lines changed

14 files changed

+245
-47
lines changed

src.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ set(GLSL_EMBED_LIST
108108
blur_fp.glsl
109109
cameraEffects_fp.glsl
110110
contrast_fp.glsl
111-
fogGlobal_fp.glsl
112111
fxaa_fp.glsl
113112
fxaa3_11_fp.glsl
114113
motionblur_fp.glsl
@@ -130,6 +129,8 @@ set(GLSL_EMBED_LIST
130129
vertexSkinning_vp.glsl
131130

132131
# Regular shaders
132+
fogGlobal_vp.glsl
133+
fogGlobal_fp.glsl
133134
fogQuake3_vp.glsl
134135
fogQuake3_fp.glsl
135136
generic_vp.glsl

src/engine/renderer/VertexSpecification.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ enum
4141
// GPU vertex animations
4242
ATTR_INDEX_POSITION2,
4343
ATTR_INDEX_QTANGENT2,
44+
45+
ATTR_INDEX_FOG_SURFACE,
46+
4447
ATTR_INDEX_MAX
4548
};
4649

@@ -53,7 +56,8 @@ static const char* const attributeNames[] =
5356
"attr_Color",
5457
"attr_BoneFactors",
5558
"attr_Position2",
56-
"attr_QTangent2"
59+
"attr_QTangent2",
60+
"attr_FogSurface",
5761
};
5862

5963
enum
@@ -69,6 +73,8 @@ enum
6973
ATTR_POSITION2 = BIT( ATTR_INDEX_POSITION2 ),
7074
ATTR_QTANGENT2 = BIT( ATTR_INDEX_QTANGENT2 ),
7175

76+
ATTR_FOG_SURFACE = BIT( ATTR_INDEX_FOG_SURFACE ),
77+
7278
ATTR_INTERP_BITS = ATTR_POSITION2 | ATTR_QTANGENT2,
7379
};
7480

src/engine/renderer/gl_shader.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2719,15 +2719,17 @@ GLShader_fogQuake3Material::GLShader_fogQuake3Material() :
27192719
GLDeformStage( this ) {
27202720
}
27212721

2722+
// TODO: rename
27222723
GLShader_fogGlobal::GLShader_fogGlobal() :
2723-
GLShader( "fogGlobal", ATTR_POSITION,
2724-
false, "screenSpace", "fogGlobal" ),
2724+
GLShader( "fogGlobal", ATTR_POSITION | ATTR_FOG_SURFACE,
2725+
false, "fogGlobal", "fogGlobal" ),
27252726
u_DepthMap( this ),
2727+
u_ModelViewProjectionMatrix( this ),
27262728
u_UnprojectMatrix( this ),
27272729
u_Color_Float( this ),
27282730
u_Color_Uint( this ),
27292731
u_ViewOrigin( this ),
2730-
u_FogDensity( this )
2732+
u_FogGradient( this )
27312733
{
27322734
}
27332735

src/engine/renderer/gl_shader.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3210,11 +3210,12 @@ class GLShader_fogQuake3Material :
32103210
class GLShader_fogGlobal :
32113211
public GLShader,
32123212
public u_DepthMap,
3213+
public u_ModelViewProjectionMatrix,
32133214
public u_UnprojectMatrix,
32143215
public u_Color_Float,
32153216
public u_Color_Uint,
32163217
public u_ViewOrigin,
3217-
public u_FogDensity
3218+
public u_FogGradient
32183219
{
32193220
public:
32203221
GLShader_fogGlobal();

src/engine/renderer/glsl_source/fogGlobal_fp.glsl

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2727

2828
#define DEPTHMAP_GLSL
2929

30+
IN(smooth) vec3 var_Position;
31+
IN(flat) vec4 var_FogSurface;
32+
3033
uniform sampler2D u_DepthMap;
3134

3235
uniform colorPack u_Color;
3336

3437
uniform vec3 u_ViewOrigin;
35-
uniform float u_FogDensity;
38+
uniform vec2 u_FogGradient;
3639
uniform mat4 u_UnprojectMatrix;
3740

3841
DECLARE_OUTPUT(vec4)
3942

43+
// This shader can be used to draw a fog volume the viewer is inside of.
4044
void main()
4145
{
4246
#insert material_fp
@@ -50,7 +54,25 @@ void main()
5054
P.xyz /= P.w;
5155

5256
// calculate the length in fog
53-
float s = distance(u_ViewOrigin, P.xyz) * u_FogDensity;
57+
float depthDist = distance(u_ViewOrigin, P.xyz);
58+
float fogBoundaryDist = distance(u_ViewOrigin, var_Position);
59+
vec3 endPoint;
60+
float distInFog;
61+
if ( depthDist < fogBoundaryDist )
62+
{
63+
endPoint = P.xyz;
64+
distInFog = depthDist;
65+
}
66+
else
67+
{
68+
endPoint = var_Position;
69+
distInFog = fogBoundaryDist;
70+
}
71+
72+
float t0 = dot(var_FogSurface.xyz, u_ViewOrigin) + var_FogSurface.w;
73+
float t1 = dot(var_FogSurface.xyz, endPoint) + var_FogSurface.w;
74+
75+
float s = distInFog * GetFogGradientModifier(u_FogGradient.y, t0, t1) * u_FogGradient.x;
5476

5577
vec4 color = vec4(1, 1, 1, GetFogAlpha(s));
5678

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2026 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
35+
uniform mat4 u_ModelViewProjectionMatrix;
36+
37+
IN vec3 attr_Position;
38+
IN vec4 attr_FogSurface;
39+
40+
OUT(smooth) vec3 var_Position;
41+
OUT(flat) vec4 var_FogSurface;
42+
43+
void main()
44+
{
45+
vec4 position = vec4(attr_Position, 1.0);
46+
gl_Position = u_ModelViewProjectionMatrix * position;
47+
var_Position = attr_Position;
48+
var_FogSurface = attr_FogSurface;
49+
}

src/engine/renderer/tr_backend.cpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,8 @@ void RB_RenderPostDepthLightTile()
14231423
GL_CheckErrors();
14241424
}
14251425

1426-
void RB_RenderGlobalFog()
1426+
// TODO: move with other Render_ functions
1427+
void Render_fogGlobal( shaderStage_t *stage )
14271428
{
14281429
if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL )
14291430
{
@@ -1435,42 +1436,39 @@ void RB_RenderGlobalFog()
14351436
return;
14361437
}
14371438

1438-
if ( !tr.world || tr.world->globalFog < 0 )
1439-
{
1440-
return;
1441-
}
1442-
14431439
GLIMP_LOGCOMMENT( "--- RB_RenderGlobalFog ---" );
14441440

14451441
RB_PrepareForSamplingDepthMap();
14461442

1447-
GL_Cull( cullType_t::CT_TWO_SIDED );
1443+
GL_Cull( cullType_t::CT_FRONT_SIDED );
14481444

14491445
gl_fogGlobalShader->BindProgram();
14501446

1451-
// go back to the world modelview matrix
1452-
backEnd.orientation = backEnd.viewParms.world;
1453-
14541447
{
1455-
fog_t* fog = &tr.world->fogs[ tr.world->globalFog ];
1456-
1457-
GLIMP_LOGCOMMENT( "--- RB_RenderGlobalFog( fogNum = %i ) ---", tr.world->globalFog );
1448+
GL_State( stage->stateBits );
14581449

1459-
GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
1460-
1461-
gl_fogGlobalShader->SetUniform_FogDensity( 1.0f / fog->shader->fogParms.depthForOpaque );
1450+
gl_fogGlobalShader->SetUniform_FogGradient(
1451+
1.0f / stage->shader->fogParms.depthForOpaque, stage->shader->fogParms.falloffExp );
14621452
gl_fogGlobalShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin );
1463-
SetUniform_Color( gl_fogGlobalShader, fog->shader->fogParms.color );
1453+
SetUniform_Color( gl_fogGlobalShader, stage->shader->fogParms.color );
14641454
}
14651455

1456+
// It's important to avoid far plane clipping
1457+
matrix_t projection, mvp;
1458+
MatrixPerspectiveProjectionFovXYInfiniteRH( projection, tr.refdef.fov_x, tr.refdef.fov_y, 1.0f );
1459+
MatrixMultiply( projection, glState.modelViewMatrix[ glState.stackIndex ], mvp );
1460+
1461+
gl_fogGlobalShader->SetUniform_ModelViewProjectionMatrix( mvp );
14661462
gl_fogGlobalShader->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix );
14671463

14681464
// bind u_DepthMap
14691465
gl_fogGlobalShader->SetUniform_DepthMapBindless(
14701466
GL_BindToTMU( 1, tr.depthSamplerImage )
14711467
);
14721468

1473-
Tess_InstantScreenSpaceQuad();
1469+
gl_fogGlobalShader->SetRequiredVertexPointers();
1470+
1471+
Tess_DrawElements();
14741472

14751473
GL_CheckErrors();
14761474
}
@@ -2801,9 +2799,6 @@ static void RB_RenderView( bool depthPass )
28012799

28022800
RB_RenderSSAO();
28032801

2804-
// render global fog post process effect
2805-
RB_RenderGlobalFog();
2806-
28072802
TransitionMainToMSAA( GL_COLOR_BUFFER_BIT );
28082803

28092804
// draw everything that is translucent

src/engine/renderer/tr_bsp.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3262,6 +3262,14 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump )
32623262

32633263
sidesCount = sidesLump->filelen / sizeof( *sides );
32643264

3265+
struct FogVert
3266+
{
3267+
float position[ 3 ];
3268+
vec4_t surface;
3269+
};
3270+
std::vector<FogVert> fogVerts(8 * count);
3271+
std::vector<glIndex_t> fogIndexes(36 * count);
3272+
32653273
for ( i = 0; i < count; i++, fogs++ )
32663274
{
32673275
out->originalBrushNumber = LittleLong( fogs->brushNum );
@@ -3331,6 +3339,7 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump )
33313339
if ( sideNum < 0 || sideNum >= sidesCount )
33323340
{
33333341
out->hasSurface = false;
3342+
Vector4Set( out->surface, 0.0f, 0.0f, 0.0f, -1.0e10f );
33343343
}
33353344
else
33363345
{
@@ -3340,9 +3349,47 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump )
33403349
out->surface[ 3 ] = -s_worldData.planes[ planeNum ].dist;
33413350
}
33423351

3352+
// add faces of fog brush for drawing fog from inside
3353+
for ( int p = 0; p < 8; p++ )
3354+
{
3355+
fogVerts[ i * 8 + p ].position[ 0 ] = out->bounds[ p & 1 ][ 0 ];
3356+
fogVerts[ i * 8 + p ].position[ 1 ] = out->bounds[ ( p >> 1 ) & 1 ][ 1 ];
3357+
fogVerts[ i * 8 + p ].position[ 2 ] = out->bounds[ p >> 2 ][ 2 ];
3358+
3359+
VectorCopy( out->surface, fogVerts[ i * 8 + p ].surface );
3360+
fogVerts[ i * 8 + p ].surface[ 3 ] = -out->surface[ 3 ];
3361+
}
3362+
3363+
constexpr int box[ 36 ] = { 2, 3, 0, 0, 3, 1, 0, 1, 4, 4, 1, 5, 2, 0, 6, 6, 0, 4,
3364+
1, 3, 5, 5, 3, 7, 3, 2, 7, 7, 2, 6, 7, 6, 5, 5, 6, 4 };
3365+
for ( int p = 0; p < 36; p++ )
3366+
{
3367+
fogIndexes[ 36 * i + p ] = 8 * i + box[ p ];
3368+
}
3369+
3370+
// add draw surf for fog brush faces
3371+
out->surf.firstIndex = 36 * i;
3372+
out->surf.numTriangles = 12;
3373+
out->surf.surfaceType = surfaceType_t::SF_TRIANGLES;
3374+
33433375
out++;
33443376
}
33453377

3378+
vertexAttributeSpec_t attributes[] {
3379+
{ ATTR_INDEX_POSITION, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].position, 3, sizeof( fogVerts[ 0 ] ), 0 },
3380+
{ ATTR_INDEX_FOG_SURFACE, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].surface, 4, sizeof( fogVerts[ 0 ] ), 0 },
3381+
};
3382+
VBO_t *fogVBO = R_CreateStaticVBO(
3383+
"fogs VBO", std::begin( attributes ), std::end( attributes ), fogVerts.size() );
3384+
IBO_t *fogIBO = R_CreateStaticIBO( "fogs IBO", &fogIndexes[ 0 ], fogIndexes.size() );
3385+
SetupVAOBuffers( fogVBO, fogIBO, ATTR_POSITION | ATTR_FOG_SURFACE, &fogVBO->VAO );
3386+
3387+
for ( int j = 1; j < s_worldData.numFogs; j++ )
3388+
{
3389+
s_worldData.fogs[ j ].surf.vbo = fogVBO;
3390+
s_worldData.fogs[ j ].surf.ibo = fogIBO;
3391+
}
3392+
33463393
Log::Debug("%i fog volumes loaded", s_worldData.numFogs );
33473394
}
33483395

src/engine/renderer/tr_init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
15411541
gl_fogQuake3Shader->SetDeform( 0 );
15421542
gl_fogQuake3Shader->MarkProgramForBuilding();
15431543
}
1544+
1545+
gl_fogGlobalShader->MarkProgramForBuilding();
15441546
}
15451547

15461548
for ( int i = 0; i < tr.numModels; i++ ) {

0 commit comments

Comments
 (0)