Skip to content

Commit 0d188fe

Browse files
committed
Use deferred shader for applying directional lights
This moves all lighting operations into the deferred shading phase of the rendering pipeline. Previously, directional lights were applied to all objects while they were being rendered. This was probably done to avoid doing multiple full screen passes later but caused some problems since the color information in the G-buffers was not correct for doing later lighting operations. This was especially noticable in dark scenes where point lights would appear to ignore the color of the rendered objects. This should be fixed with these changes. I did some performance testing and to my surprise this actually improves performance in very demanding scenes. My guess would be that applying the shadows while rendering the objects caused a lot of overdraw which is not the case anymore since shadows are only computed for visible pixels. In simple scenes the opposite happens which leads to decreased performance in those cases but in my opinion the improvement in demanding scenes outweights this performance decrease.
1 parent 77b6648 commit 0d188fe

20 files changed

Lines changed: 366 additions & 160 deletions

code/def_files/data/effects/deferred-clear-f.sdr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ out vec4 fragOut0;
22
out vec4 fragOut1;
33
out vec4 fragOut2;
44
out vec4 fragOut3;
5+
out vec4 fragOut4;
56
void main()
67
{
78
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
89
fragOut1 = vec4(0.0, 0.0, -1000000.0, 1.0); // position
910
fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal
1011
fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular
11-
}
12+
fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive
13+
}

code/def_files/data/effects/deferred-f.sdr

Lines changed: 83 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
#include "lighting.sdr"
33

4+
#include "shadows.sdr"
5+
46
in vec3 beamVec;
57
in vec3 lightPosition;
68
out vec4 fragOut0;
@@ -9,10 +11,23 @@ uniform sampler2D ColorBuffer;
911
uniform sampler2D NormalBuffer;
1012
uniform sampler2D PositionBuffer;
1113
uniform sampler2D SpecBuffer;
14+
uniform sampler2DArray shadow_map;
15+
16+
layout (std140) uniform globalDeferredData {
17+
mat4 shadow_mv_matrix;
18+
mat4 shadow_proj_matrix[4];
1219

13-
uniform float specFactor;
14-
uniform float invScreenWidth;
15-
uniform float invScreenHeight;
20+
mat4 inv_view_matrix;
21+
22+
float veryneardist;
23+
float neardist;
24+
float middist;
25+
float fardist;
26+
27+
float specFactor;
28+
float invScreenWidth;
29+
float invScreenHeight;
30+
};
1631

1732
layout (std140) uniform lightData {
1833
vec3 diffuseLightColor;
@@ -27,60 +42,92 @@ layout (std140) uniform lightData {
2742
vec3 scale;
2843
float lightRadius;
2944

45+
vec3 lightDir;
3046
int lightType;
47+
48+
bool enable_shadows;
3149
};
3250

51+
void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
52+
{
53+
if (lightType == LT_DIRECTIONAL) {
54+
lightDir = normalize(lightPosition);
55+
attenuation = 1.0;
56+
} else {
57+
// Positional light source
58+
lightDir = lightPosition - position.xyz;
59+
float dist = length(lightDir);
60+
attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
61+
62+
if(dist > lightRadius && lightType != LT_TUBE) {
63+
discard;
64+
}
65+
66+
if (lightType == LT_TUBE) { // Tube light
67+
float beamLength = length(beamVec);
68+
vec3 beamDir = beamVec / beamLength;
69+
// Get nearest point on line
70+
float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
71+
// Move back from the endpoint of the beam along the beam by the distance we calculated
72+
vec3 nearest = lightPosition - beamDir * neardist;
73+
lightDir = nearest - position.xyz;
74+
dist = length(lightDir);
75+
if(dist > lightRadius) {
76+
discard;
77+
}
78+
} else if (lightType == LT_CONE) {
79+
float coneDot = dot(normalize(-lightDir), coneDir);
80+
if(dualCone) {
81+
if(abs(coneDot) < coneAngle) {
82+
discard;
83+
} else {
84+
attenuation *= smoothstep(coneAngle, coneInnerAngle, abs(coneDot));
85+
}
86+
} else {
87+
if (coneDot < coneAngle) {
88+
discard;
89+
} else {
90+
attenuation *= smoothstep(coneAngle, coneInnerAngle, coneDot);
91+
}
92+
}
93+
}
94+
95+
lightDir = normalize(lightDir);
96+
}
97+
}
98+
3399
void main()
34100
{
35101
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
36102
vec3 position = texture(PositionBuffer, screenPos).xyz;
37103

38104
if(abs(dot(position, position)) < 0.1)
39105
discard;
40-
vec3 lightDir = lightPosition - position.xyz;
41-
float dist = length(lightDir);
42-
if(dist > lightRadius && lightType != 1)
43-
discard;
106+
44107
vec3 color = texture(ColorBuffer, screenPos).rgb;
45108
vec4 normal = texture(NormalBuffer, screenPos);
46109
vec4 specColor = texture(SpecBuffer, screenPos);
47110
float gloss = normal.a;
48111
float fresnel = specColor.a;
49112
vec3 eyeDir = normalize(-position);
50113

51-
if(lightType == 1)
52-
{
53-
float beamLength = length(beamVec);
54-
vec3 beamDir = beamVec / beamLength;
55-
// Get nearest point on line
56-
float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
57-
// Move back from the endpoint of the beam along the beam by the distance we calculated
58-
vec3 nearest = lightPosition - beamDir * neardist;
59-
lightDir = nearest - position.xyz;
60-
dist = length(lightDir);
61-
if(dist > lightRadius)
62-
discard;
63-
}
114+
vec3 lightDir;
115+
float attenuation;
64116

65-
float attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
117+
GetLightInfo(position, lightDir, attenuation);
66118

67-
if(lightType == 2)
68-
{
69-
float coneDot = dot(normalize(-lightDir), coneDir);
70-
if(dualCone) {
71-
if(abs(coneDot) < coneAngle)
72-
discard;
73-
else
74-
attenuation *= smoothstep(coneAngle, coneInnerAngle, abs(coneDot));
75-
} else {
76-
if(coneDot < coneAngle)
77-
discard;
78-
else
79-
attenuation *= smoothstep(coneAngle, coneInnerAngle, coneDot);
80-
}
119+
if (enable_shadows) {
120+
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
121+
vec4 fragShadowUV[4];
122+
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
123+
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
124+
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
125+
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
126+
127+
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
128+
neardist, veryneardist);
81129
}
82130

83-
lightDir /= dist;
84131
vec3 halfVec = normalize(lightDir + eyeDir);
85132
float NdotL = clamp(dot(normal.xyz, lightDir), 0.0, 1.0);
86133
vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);

code/def_files/data/effects/deferred-v.sdr

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2+
#include "lighting.sdr"
3+
14
in vec4 vertPosition;
25
uniform mat4 modelViewMatrix;
36
uniform mat4 projMatrix;
@@ -15,15 +18,23 @@ layout (std140) uniform lightData {
1518
vec3 scale;
1619
float lightRadius;
1720

21+
vec3 lightDir;
1822
int lightType;
23+
24+
bool enable_shadows;
1925
};
2026

2127
out vec3 lightPosition;
2228
out vec3 beamVec;
2329
void main()
2430
{
25-
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
26-
lightPosition = modelViewMatrix[3].xyz;
27-
if(lightType == 1)
28-
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
31+
if (lightType == LT_DIRECTIONAL) {
32+
gl_Position = vec4(vertPosition.xyz, 1.0);
33+
lightPosition = lightDir;
34+
} else {
35+
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
36+
lightPosition = modelViewMatrix[3].xyz;
37+
if(lightType == LT_TUBE)
38+
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
39+
}
2940
}

code/def_files/data/effects/lighting.sdr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11

2+
const int LT_DIRECTIONAL = 0; // A light like a sun
3+
const int LT_POINT = 1; // A point light, like an explosion
4+
const int LT_TUBE = 2; // A tube light, like a fluorescent light
5+
const int LT_CONE = 3; // A cone light, like a flood light
6+
27
const float SPEC_INTENSITY_POINT = 5.3 ;// Point light
38
const float SPEC_INTENSITY_DIRECTIONAL = 3.0 ;// Directional light
49
const float SPECULAR_FACTOR = 1.75;

code/def_files/data/effects/main-f.sdr

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ out vec4 fragOut0;
146146
out vec4 fragOut1;
147147
out vec4 fragOut2;
148148
out vec4 fragOut3;
149+
out vec4 fragOut4;
149150

150151
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
151152
{
@@ -213,12 +214,15 @@ void main()
213214
#ifdef FLAG_SHADOW_MAP
214215
// need depth and depth squared for variance shadow maps
215216
fragOut0 = vec4(fragPosition.z, fragPosition.z * fragPosition.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
216-
return;
217+
if (true) {
218+
return;
219+
}
217220
#endif
218221
vec3 eyeDir = vec3(normalize(-fragPosition).xyz);
219222
vec2 texCoord = fragTexCoord.xy;
220223
vec4 baseColor = color;
221224
vec4 specColor = vec4(0.0, 0.0, 0.0, 1.0);
225+
vec4 emissiveColor = vec4(0.0, 0.0, 0.0, 1.0);
222226
float fresnelFactor = 0.0;
223227
float glossData = 0.6;
224228
#ifdef FLAG_LIGHT
@@ -295,30 +299,45 @@ void main()
295299
baseColor.rgb = max(baseColor.rgb, vec3(0.0));
296300
#endif
297301
#endif
302+
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
303+
#ifdef FLAG_DEFERRED
304+
#ifdef FLAG_LIGHT
305+
// Ambient lighting still needs to be done since that counts as an "emissive" color
306+
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
307+
emissiveColor.rgb += baseColor.rgb * lightAmbient;
308+
#else
309+
#ifdef FLAG_SPEC_MAP
310+
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
311+
#endif
312+
// If there is no lighting then we copy the color data so far into the
313+
emissiveColor.rgb += baseColor.rgb;
314+
#endif
315+
#else
316+
#ifdef FLAG_LIGHT
298317
float shadow = 1.0;
299-
#ifdef FLAG_SHADOWS
318+
#ifdef FLAG_SHADOWS
300319
shadow = getShadowValue(shadow_map, -fragPosition.z, fragShadowPos.z, fragShadowUV, fardist, middist, neardist, veryneardist);
301-
#endif
302-
#ifdef FLAG_LIGHT
320+
#endif
303321
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
304-
#else
305-
#ifdef FLAG_SPEC_MAP
322+
#else
323+
#ifdef FLAG_SPEC_MAP
306324
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
325+
#endif
307326
#endif
308327
#endif
309328
#ifdef FLAG_ENV_MAP
310-
vec3 envReflectNM = fragEnvReflect;
329+
vec3 envReflectNM = fragEnvReflect;
311330
#ifdef FLAG_NORMAL_MAP
312-
envReflectNM += vec3(normalSample, 0.0);
331+
envReflectNM += vec3(normalSample, 0.0);
313332
envReflectNM = normalize(envReflectNM);
314333
#endif
315334
float mip = (envGloss) ? (1.0 - glossData) * 7.0 : 0.0;
316-
vec4 envColour = textureLod(sEnvmap, envReflectNM, mip);
335+
vec4 envColour = textureLod(sEnvmap, envReflectNM, mip);
317336
#ifdef FLAG_HDR
318337
envColour.rgb = pow(envColour.rgb, vec3(SRGB_GAMMA));
319338
#endif
320339
envColour.rgb *= (envGloss) ? 1.0 : specColor.a;
321-
baseColor.rgb += envColour.rgb * FresnelLazarovEnv(specColor.rgb, eyeDir, normal, glossData);
340+
emissiveColor.rgb += envColour.rgb * FresnelLazarovEnv(specColor.rgb, eyeDir, normal, glossData);
322341
#endif
323342
#ifdef FLAG_GLOW_MAP
324343
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
@@ -332,7 +351,7 @@ void main()
332351
glowColor = team_glow_enabled ? mix((base * teamMask.b) + (stripe * teamMask.a), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
333352
#endif
334353
#endif
335-
baseColor.rgb += glowColor * GLOW_MAP_INTENSITY;
354+
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
336355
#endif
337356

338357
#ifdef FLAG_FOG
@@ -355,15 +374,13 @@ void main()
355374
#ifdef FLAG_ANIMATED
356375
if (effect_num == 0) {
357376
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
358-
baseColor.rgb = baseColor.rgb + vec3(shinefactor);
377+
emissiveColor.rgb += vec3(shinefactor);
359378
baseColor.a = baseColor.a * clamp(shinefactor * (fract(abs(texCoord.x))-anim_timer) * -10000.0,0.0,1.0);
360379
}
361380
if (effect_num == 1) {
362381
float shinefactor = 1.0/(1.0 + pow(abs(fragPosition.y-anim_timer), 2.0));
363-
baseColor.rgb = baseColor.rgb + vec3(shinefactor);
364-
#ifdef FLAG_LIGHT
365-
baseColor.a = baseColor.a;
366-
#else
382+
emissiveColor.rgb += vec3(shinefactor);
383+
#ifndef FLAG_LIGHT
367384
// ATI Wireframe fix *grumble*
368385
baseColor.a = clamp((fragPosition.y-anim_timer) * 10000.0,0.0,1.0);
369386
#endif
@@ -382,11 +399,16 @@ void main()
382399
#ifdef FLAG_NORMAL_ALPHA
383400
float normViewOffset = dot(vec3(0.0, 0.0, 1.0), normal);
384401
baseColor.a = smoothstep(min(normalAlphaMinMax.x, normalAlphaMinMax.y), max(normalAlphaMinMax.x, normalAlphaMinMax.y), clamp(normalAlphaMinMax.x > normalAlphaMinMax.y ? normViewOffset : 1.0 - normViewOffset, 0.0, 1.0));
402+
#endif
403+
#ifndef FLAG_DEFERRED
404+
// emissive colors won't be added later when we are using forward rendering so we need to do that here
405+
baseColor.rgb += emissiveColor.rgb;
385406
#endif
386407
fragOut0 = baseColor;
387408
#ifdef FLAG_DEFERRED
388409
fragOut1 = vec4(fragPosition.xyz, 1.0);
389410
fragOut2 = vec4(normal, glossData);
390411
fragOut3 = vec4(specColor.rgb, fresnelFactor);
412+
fragOut4 = emissiveColor;
391413
#endif
392414
}

code/def_files/data/effects/main-v.sdr

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#extension GL_ARB_gpu_shader5: enable
22

3+
#include "shadows.sdr"
4+
35
#define MAX_LIGHTS 8
46

57
struct model_light {
@@ -144,18 +146,6 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
144146
transform[3].w = 1.0;
145147
}
146148
#endif
147-
#ifdef FLAG_SHADOWS
148-
vec4 transformToShadowMap(int i, vec4 pos)
149-
{
150-
vec4 shadow_proj;
151-
shadow_proj = shadow_proj_matrix[i] * pos;
152-
shadow_proj += 1.0;
153-
shadow_proj *= 0.5;
154-
shadow_proj.w = shadow_proj.z;
155-
shadow_proj.z = float(i);
156-
return shadow_proj;
157-
}
158-
#endif
159149
void main()
160150
{
161151
vec4 position;
@@ -210,10 +200,10 @@ void main()
210200
#endif
211201
#ifdef FLAG_SHADOWS
212202
fragShadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
213-
fragShadowUV[0] = transformToShadowMap(0, fragShadowPos);
214-
fragShadowUV[1] = transformToShadowMap(1, fragShadowPos);
215-
fragShadowUV[2] = transformToShadowMap(2, fragShadowPos);
216-
fragShadowUV[3] = transformToShadowMap(3, fragShadowPos);
203+
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
204+
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
205+
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
206+
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
217207
#endif
218208
#ifdef FLAG_NORMAL_MAP
219209
// Setup stuff for normal maps

0 commit comments

Comments
 (0)