Skip to content

Commit 2337799

Browse files
committed
Use depth-based fog shader for all fogs
Add a new macro variant of the 'fogGlobal' shader which can be used for fogs that the viewer is outside of. Now when material system is not active, this shader is used for all fogs. The "outside" version of the shader is more complex than the inside one, since it is necessary to trace against all planes of the fog to find the length in fog. This change removes the requirement that a fog be enclosed by opaque walls on all sides except one (the "surface plane"). Now fogs can be rendered (almost) correctly from any side. The exception is that if eye position is very close but not inside the fog, within about 5 qu, the inside fog shader has to be used instead of the outside one to avoid near plane culling. This causes an artifact when passing into the fog through a non-surface side which can be noticed if you look closely.
1 parent c57dde8 commit 2337799

12 files changed

Lines changed: 230 additions & 45 deletions

File tree

src/engine/renderer/VertexSpecification.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ enum
4444

4545
ATTR_INDEX_FOG_SURFACE,
4646

47+
// This occupies 5 attribute slots
48+
ATTR_INDEX_FOG_PLANES_0,
49+
ATTR_INDEX_FOG_PLANES_LAST = ATTR_INDEX_FOG_PLANES_0 + 4,
50+
4751
ATTR_INDEX_MAX
4852
};
4953

@@ -58,6 +62,7 @@ static const char* const attributeNames[] =
5862
"attr_Position2",
5963
"attr_QTangent2",
6064
"attr_FogSurface",
65+
"attr_FogPlanes", nullptr, nullptr, nullptr, nullptr,
6166
};
6267

6368
enum
@@ -74,6 +79,7 @@ enum
7479
ATTR_QTANGENT2 = BIT( ATTR_INDEX_QTANGENT2 ),
7580

7681
ATTR_FOG_SURFACE = BIT( ATTR_INDEX_FOG_SURFACE ),
82+
ATTR_FOG_PLANES = BIT( ATTR_INDEX_FOG_PLANES_0 ) * ( BIT( 5 ) - 1 ),
7783

7884
ATTR_INTERP_BITS = ATTR_POSITION2 | ATTR_QTANGENT2,
7985
};

src/engine/renderer/gl_shader.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,7 +2007,10 @@ void GLShaderManager::BindAttribLocations( GLuint program ) const
20072007
{
20082008
for ( uint32_t i = 0; i < ATTR_INDEX_MAX; i++ )
20092009
{
2010-
glBindAttribLocation( program, i, attributeNames[ i ] );
2010+
if ( attributeNames[ i ] != nullptr )
2011+
{
2012+
glBindAttribLocation( program, i, attributeNames[ i ] );
2013+
}
20112014
}
20122015
}
20132016

@@ -2729,7 +2732,8 @@ GLShader_fogGlobal::GLShader_fogGlobal() :
27292732
u_Color_Float( this ),
27302733
u_Color_Uint( this ),
27312734
u_ViewOrigin( this ),
2732-
u_FogGradient( this )
2735+
u_FogGradient( this ),
2736+
GLCompileMacro_OUTSIDE_FOG( this )
27332737
{
27342738
}
27352739

src/engine/renderer/gl_shader.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ class GLCompileMacro
919919
// It also works regardless of RTTI is enabled or not.
920920
enum EGLCompileMacro : unsigned
921921
{
922+
OUTSIDE_FOG,
922923
USE_BSP_SURFACE,
923924
USE_VERTEX_SKINNING,
924925
USE_VERTEX_ANIMATION,
@@ -985,6 +986,40 @@ class GLCompileMacro
985986
virtual ~GLCompileMacro() = default;
986987
};
987988

989+
class GLCompileMacro_OUTSIDE_FOG :
990+
GLCompileMacro
991+
{
992+
public:
993+
GLCompileMacro_OUTSIDE_FOG( GLShader *shader ) :
994+
GLCompileMacro( shader )
995+
{
996+
}
997+
998+
const char *GetName() const override
999+
{
1000+
return "OUTSIDE_FOG";
1001+
}
1002+
1003+
EGLCompileMacro GetType() const override
1004+
{
1005+
return EGLCompileMacro::OUTSIDE_FOG;
1006+
}
1007+
1008+
int GetShaderTypes() const override {
1009+
return ShaderType::VERTEX | ShaderType::FRAGMENT;
1010+
}
1011+
1012+
void SetOutsideFog( bool enable )
1013+
{
1014+
SetMacro( enable );
1015+
}
1016+
1017+
uint32_t GetRequiredVertexAttributes() const override
1018+
{
1019+
return ATTR_FOG_PLANES;
1020+
}
1021+
};
1022+
9881023
class GLCompileMacro_USE_BSP_SURFACE :
9891024
GLCompileMacro
9901025
{
@@ -3215,7 +3250,8 @@ class GLShader_fogGlobal :
32153250
public u_Color_Float,
32163251
public u_Color_Uint,
32173252
public u_ViewOrigin,
3218-
public u_FogGradient
3253+
public u_FogGradient,
3254+
public GLCompileMacro_OUTSIDE_FOG
32193255
{
32203256
public:
32213257
GLShader_fogGlobal();

src/engine/renderer/glsl_source/fogGlobal_fp.glsl

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3030
IN(smooth) vec3 var_Position;
3131
IN(flat) vec4 var_FogSurface;
3232

33+
#ifdef OUTSIDE_FOG
34+
#define NUM_PLANES 5
35+
IN(flat) vec4 var_FogPlanes[NUM_PLANES];
36+
#endif
37+
3338
uniform sampler2D u_DepthMap;
3439

3540
uniform colorPack u_Color;
@@ -40,7 +45,24 @@ uniform mat4 u_UnprojectMatrix;
4045

4146
DECLARE_OUTPUT(vec4)
4247

43-
// This shader can be used to draw a fog volume the viewer is inside of.
48+
#ifdef OUTSIDE_FOG
49+
// Trace against the inner sides of the fog brush
50+
float FogDistance(vec3 start, vec3 dir)
51+
{
52+
vec4 start4 = vec4(-start, 1.0);
53+
float minDist = 1.0e20;
54+
for (int i = 0; i < NUM_PLANES; i++)
55+
{
56+
float dist = dot(start4, var_FogPlanes[i]) / dot(dir, var_FogPlanes[i].xyz) ;
57+
if (dist >= 0.0)
58+
{
59+
minDist = min(minDist, dist);
60+
}
61+
}
62+
return minDist < 1.0e20 ? minDist : 0.0;
63+
}
64+
#endif
65+
4466
void main()
4567
{
4668
#insert material_fp
@@ -53,9 +75,17 @@ void main()
5375
vec4 P = u_UnprojectMatrix * vec4(gl_FragCoord.xy, depth, 1.0);
5476
P.xyz /= P.w;
5577

56-
// calculate the length in fog
57-
float depthDist = distance(u_ViewOrigin, P.xyz);
58-
float fogBoundaryDist = distance(u_ViewOrigin, var_Position);
78+
#ifdef OUTSIDE_FOG
79+
vec3 startPoint = var_Position;
80+
vec3 viewDir = normalize(var_Position - u_ViewOrigin);
81+
float fogBoundaryDist = FogDistance(var_Position, viewDir);
82+
#else
83+
vec3 startPoint = u_ViewOrigin;
84+
float fogBoundaryDist = distance(u_ViewOrigin, var_Position);
85+
#endif
86+
87+
float depthDist = distance(startPoint, P.xyz);
88+
5989
vec3 endPoint;
6090
float distInFog;
6191
if ( depthDist < fogBoundaryDist )
@@ -65,11 +95,16 @@ void main()
6595
}
6696
else
6797
{
68-
endPoint = var_Position;
98+
#ifdef OUTSIDE_FOG
99+
endPoint = var_Position + fogBoundaryDist * viewDir;
100+
#else
101+
endPoint = var_Position;
102+
#endif
103+
69104
distInFog = fogBoundaryDist;
70105
}
71106

72-
float t0 = dot(var_FogSurface.xyz, u_ViewOrigin) + var_FogSurface.w;
107+
float t0 = dot(var_FogSurface.xyz, startPoint) + var_FogSurface.w;
73108
float t1 = dot(var_FogSurface.xyz, endPoint) + var_FogSurface.w;
74109

75110
float s = distInFog * GetFogGradientModifier(u_FogGradient.y, t0, t1) * u_FogGradient.x;

src/engine/renderer/glsl_source/fogGlobal_vp.glsl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,23 @@ IN vec4 attr_FogSurface;
4040
OUT(smooth) vec3 var_Position;
4141
OUT(flat) vec4 var_FogSurface;
4242

43+
#ifdef OUTSIDE_FOG
44+
#define NUM_PLANES 5
45+
IN vec4 attr_FogPlanes[NUM_PLANES];
46+
OUT(flat) vec4 var_FogPlanes[NUM_PLANES];
47+
#endif
48+
4349
void main()
4450
{
4551
vec4 position = vec4(attr_Position, 1.0);
4652
gl_Position = u_ModelViewProjectionMatrix * position;
4753
var_Position = attr_Position;
4854
var_FogSurface = attr_FogSurface;
55+
56+
#ifdef OUTSIDE_FOG
57+
for (int i = 0; i < NUM_PLANES; i++)
58+
{
59+
var_FogPlanes[i] = attr_FogPlanes[i];
60+
}
61+
#endif
4962
}

src/engine/renderer/tr_backend.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,9 @@ void Render_fogGlobal( shaderStage_t *stage )
14411441

14421442
RB_PrepareForSamplingDepthMap();
14431443

1444-
GL_Cull( cullType_t::CT_FRONT_SIDED );
1444+
GL_Cull( stage->shader->cullType );
1445+
1446+
gl_fogGlobalShader->SetOutsideFog( stage->type == stageType_t::ST_FOGMAP_OUTER );
14451447

14461448
gl_fogGlobalShader->BindProgram();
14471449

@@ -1454,12 +1456,26 @@ void Render_fogGlobal( shaderStage_t *stage )
14541456
SetUniform_Color( gl_fogGlobalShader, stage->shader->fogParms.color );
14551457
}
14561458

1457-
// It's important to avoid far plane clipping
1458-
matrix_t projection, mvp;
1459-
MatrixPerspectiveProjectionFovXYInfiniteRH( projection, tr.refdef.fov_x, tr.refdef.fov_y, 1.0f );
1460-
MatrixMultiply( projection, glState.modelViewMatrix[ glState.stackIndex ], mvp );
1459+
switch ( stage->type )
1460+
{
1461+
case stageType_t::ST_FOGMAP_INNER:
1462+
{
1463+
// It's important to avoid far plane clipping
1464+
matrix_t projection, mvp;
1465+
MatrixPerspectiveProjectionFovXYInfiniteRH( projection, tr.refdef.fov_x, tr.refdef.fov_y, 1.0f );
1466+
MatrixMultiply( projection, glState.modelViewMatrix[ glState.stackIndex ], mvp );
1467+
gl_fogGlobalShader->SetUniform_ModelViewProjectionMatrix( mvp );
1468+
break;
1469+
}
1470+
case stageType_t::ST_FOGMAP_OUTER:
1471+
{
1472+
gl_fogGlobalShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] );
1473+
break;
1474+
}
1475+
default:
1476+
ASSERT_UNREACHABLE();
1477+
}
14611478

1462-
gl_fogGlobalShader->SetUniform_ModelViewProjectionMatrix( mvp );
14631479
gl_fogGlobalShader->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix );
14641480

14651481
// bind u_DepthMap

src/engine/renderer/tr_bsp.cpp

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3264,10 +3264,11 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump )
32643264

32653265
struct FogVert
32663266
{
3267-
float position[ 3 ];
3267+
vec3_t position;
32683268
vec4_t surface;
3269+
vec4_t planes[ 5 ]; // faces other than the current triangle's
32693270
};
3270-
std::vector<FogVert> fogVerts(8 * count);
3271+
std::vector<FogVert> fogVerts(24 * count);
32713272
std::vector<glIndex_t> fogIndexes(36 * count);
32723273

32733274
for ( i = 0; i < count; i++, fogs++ )
@@ -3349,22 +3350,50 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump )
33493350
out->surface[ 3 ] = -s_worldData.planes[ planeNum ].dist;
33503351
}
33513352

3352-
// add faces of fog brush for drawing fog from inside
3353-
for ( int p = 0; p < 8; p++ )
3353+
// add faces of fog brush with information about the other planes
3354+
// TODO: allow non-axis-aligned boxes. The GLSL can draw any brush with up to 6 faces.
3355+
constexpr int faces[ 6 ][ 4 ]
33543356
{
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 ];
3357+
{ 2, 0, 6, 4 },
3358+
{ 1, 3, 5, 7 },
3359+
{ 0, 1, 4, 5 },
3360+
{ 3, 2, 7, 6 },
3361+
{ 2, 3, 0, 1 },
3362+
{ 7, 6, 5, 4 }
3363+
};
3364+
3365+
for ( int face = 0; face < 6; face++ )
3366+
{
3367+
for ( int v = 0; v < 4; v++ )
3368+
{
3369+
FogVert &vert = fogVerts[ i * 24 + face * 4 + v ];
3370+
int p = faces[ face ][ v ];
3371+
vert.position[ 0 ] = out->bounds[ p & 1 ][ 0 ];
3372+
vert.position[ 1 ] = out->bounds[ ( p >> 1 ) & 1 ][ 1 ];
3373+
vert.position[ 2 ] = out->bounds[ p >> 2 ][ 2 ];
33583374

3359-
VectorCopy( out->surface, fogVerts[ i * 8 + p ].surface );
3360-
fogVerts[ i * 8 + p ].surface[ 3 ] = -out->surface[ 3 ];
3361-
}
3375+
VectorCopy( out->surface, vert.surface );
3376+
vert.surface[ 3 ] = -out->surface[ 3 ];
33623377

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 ];
3378+
vec4_t *plane = vert.planes;
3379+
for ( int otherFace = 0; otherFace < 6; otherFace++ )
3380+
{
3381+
if ( face != otherFace )
3382+
{
3383+
planeNum = LittleLong( sides[ firstSide + otherFace ].planeNum );
3384+
VectorCopy( s_worldData.planes[ planeNum ].normal, *plane );
3385+
( *plane )[ 3 ] = s_worldData.planes[ planeNum ].dist;
3386+
++plane;
3387+
}
3388+
}
3389+
}
3390+
3391+
fogIndexes[ 36 * i + 6 * face + 0 ] = i * 24 + face * 4 + 0;
3392+
fogIndexes[ 36 * i + 6 * face + 1 ] = i * 24 + face * 4 + 1;
3393+
fogIndexes[ 36 * i + 6 * face + 2 ] = i * 24 + face * 4 + 2;
3394+
fogIndexes[ 36 * i + 6 * face + 3 ] = i * 24 + face * 4 + 2;
3395+
fogIndexes[ 36 * i + 6 * face + 4 ] = i * 24 + face * 4 + 1;
3396+
fogIndexes[ 36 * i + 6 * face + 5 ] = i * 24 + face * 4 + 3;
33683397
}
33693398

33703399
// add draw surf for fog brush faces
@@ -3378,11 +3407,16 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump )
33783407
vertexAttributeSpec_t attributes[] {
33793408
{ ATTR_INDEX_POSITION, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].position, 3, sizeof( fogVerts[ 0 ] ), 0 },
33803409
{ ATTR_INDEX_FOG_SURFACE, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].surface, 4, sizeof( fogVerts[ 0 ] ), 0 },
3410+
{ ATTR_INDEX_FOG_PLANES_0 + 0, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].planes[ 0 ], 4, sizeof( FogVert ), 0 },
3411+
{ ATTR_INDEX_FOG_PLANES_0 + 1, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].planes[ 1 ], 4, sizeof( FogVert ), 0 },
3412+
{ ATTR_INDEX_FOG_PLANES_0 + 2, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].planes[ 2 ], 4, sizeof( FogVert ), 0 },
3413+
{ ATTR_INDEX_FOG_PLANES_0 + 3, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].planes[ 3 ], 4, sizeof( FogVert ), 0 },
3414+
{ ATTR_INDEX_FOG_PLANES_0 + 4, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ].planes[ 4 ], 4, sizeof( FogVert ), 0 },
33813415
};
33823416
VBO_t *fogVBO = R_CreateStaticVBO(
33833417
"fogs VBO", std::begin( attributes ), std::end( attributes ), fogVerts.size() );
33843418
IBO_t *fogIBO = R_CreateStaticIBO( "fogs IBO", &fogIndexes[ 0 ], fogIndexes.size() );
3385-
SetupVAOBuffers( fogVBO, fogIBO, ATTR_POSITION | ATTR_FOG_SURFACE, &fogVBO->VAO );
3419+
SetupVAOBuffers( fogVBO, fogIBO, ATTR_POSITION | ATTR_FOG_SURFACE | ATTR_FOG_PLANES, &fogVBO->VAO );
33863420

33873421
for ( int j = 1; j < s_worldData.numFogs; j++ )
33883422
{

src/engine/renderer/tr_init.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,11 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
15591559
gl_fogQuake3Shader->MarkProgramForBuilding();
15601560
}
15611561

1562-
gl_fogGlobalShader->MarkProgramForBuilding();
1562+
for ( bool outer : { false, true } )
1563+
{
1564+
gl_fogGlobalShader->SetOutsideFog( outer );
1565+
gl_fogGlobalShader->MarkProgramForBuilding();
1566+
}
15631567
}
15641568

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

src/engine/renderer/tr_local.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,7 @@ enum
942942
ST_LIQUIDMAP,
943943
ST_FOGMAP,
944944
ST_FOGMAP_INNER, // a fog seen from inside
945+
ST_FOGMAP_OUTER, // a fog seen from outside
945946
ST_LIGHTMAP,
946947
ST_STYLELIGHTMAP,
947948
ST_STYLECOLORMAP,
@@ -1206,6 +1207,7 @@ enum
12061207
struct shader_t *depthShader;
12071208
struct shader_t *fogShader;
12081209
struct shader_t *fogInnerShader;
1210+
struct shader_t *fogOuterShader;
12091211
struct shader_t *next;
12101212
};
12111213

@@ -3355,8 +3357,7 @@ void GLimp_LogComment_( std::string comment );
33553357
void RE_AddPolyToSceneET( qhandle_t hShader, int numVerts, const polyVert_t *verts );
33563358
void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys );
33573359

3358-
bool R_InsideFog( int fognum );
3359-
void R_AddInnerFogSurfaces();
3360+
void R_AddFogBrushSurfaces();
33603361

33613362
void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t hShader, int flags );
33623363
void RE_AddDynamicLightToSceneQ3A( const vec3_t org, float intensity, float r, float g, float b );

0 commit comments

Comments
 (0)