Skip to content

Commit be78626

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 39f2fe0 commit be78626

File tree

12 files changed

+230
-45
lines changed

12 files changed

+230
-45
lines changed

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
@@ -1440,7 +1440,9 @@ void Render_fogGlobal( shaderStage_t *stage )
14401440

14411441
RB_PrepareForSamplingDepthMap();
14421442

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

14451447
gl_fogGlobalShader->BindProgram();
14461448

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

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

1461-
gl_fogGlobalShader->SetUniform_ModelViewProjectionMatrix( mvp );
14621478
gl_fogGlobalShader->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix );
14631479

14641480
// 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
@@ -1542,7 +1542,11 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
15421542
gl_fogQuake3Shader->MarkProgramForBuilding();
15431543
}
15441544

1545-
gl_fogGlobalShader->MarkProgramForBuilding();
1545+
for ( bool outer : { false, true } )
1546+
{
1547+
gl_fogGlobalShader->SetOutsideFog( outer );
1548+
gl_fogGlobalShader->MarkProgramForBuilding();
1549+
}
15461550
}
15471551

15481552
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
@@ -940,6 +940,7 @@ enum
940940
ST_LIQUIDMAP,
941941
ST_FOGMAP,
942942
ST_FOGMAP_INNER, // a fog seen from inside
943+
ST_FOGMAP_OUTER, // a fog seen from outside
943944
ST_LIGHTMAP,
944945
ST_STYLELIGHTMAP,
945946
ST_STYLECOLORMAP,
@@ -1204,6 +1205,7 @@ enum
12041205
struct shader_t *depthShader;
12051206
struct shader_t *fogShader;
12061207
struct shader_t *fogInnerShader;
1208+
struct shader_t *fogOuterShader;
12071209
struct shader_t *next;
12081210
};
12091211

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

3356-
bool R_InsideFog( int fognum );
3357-
void R_AddInnerFogSurfaces();
3358+
void R_AddFogBrushSurfaces();
33583359

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

0 commit comments

Comments
 (0)