Hey guys, here is an video of the problem: Deferred lighting shadow issue - YouTube
I’m designing a lighting system in my game, and originally was using the shader from this tutorial: ShaderLesson6 · mattdesl/lwjgl-basics Wiki · GitHub
I was able to implement that, and it looked great (its the first one you see in the video of the problem).
Now I’m adapting that version to a “deferred lighting” system so that I can use a lot of lights, and although it seems to be working, the shadows near the center of the light look harsh/bad. It also looks like the original shader can actually ‘brighten’ the scene, whereas the new-shader can only darken (add shadows) since the blending is set to multiply (see the “rundown” section below). EDIT: After taking another look at the video, it seems like this might be the main issue (not being able to ‘brighten’ the scene). Not sure what to do though.
This is the shader from “ShaderLesson6” that I was previously using, and looked good:
//GL ES specific stuff
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
//attributes from vertex shader
varying LOWP vec4 vColor;
varying vec2 vTexCoord;
//our texture samplers
uniform sampler2D u_texture; //diffuse map
uniform sampler2D u_normals; //normal map
//values used for shading algorithm...
uniform vec2 Resolution; //resolution of screen
uniform vec3 LightPos; //light position, normalized
uniform LOWP vec4 LightColor; //light RGBA -- alpha is intensity
uniform LOWP vec4 AmbientColor; //ambient RGBA -- alpha is intensity
uniform vec3 Falloff; //attenuation coefficients
void main() {
//RGBA of our diffuse color
vec4 DiffuseColor = texture2D(u_texture, vTexCoord);
//RGB of our normal map
vec3 NormalMap = texture2D(u_normals, vTexCoord).rgb;
//The delta position of light
vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);
//Correct for aspect ratio
LightDir.x *= Resolution.x / Resolution.y;
//Determine distance (used for attenuation) BEFORE we normalize our LightDir
float D = length(LightDir);
//normalize our vectors
vec3 N = normalize(NormalMap * 2.0 - 1.0);
vec3 L = normalize(LightDir);
//Pre-multiply light color with intensity
//Then perform \"N dot L\" to determine our diffuse term
vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(N, L), 0.0);
//pre-multiply ambient color with intensity
vec3 Ambient = AmbientColor.rgb * AmbientColor.a;
//calculate attenuation
float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );
//the calculation which brings it all together
vec3 Intensity = Ambient + Diffuse * Attenuation;
vec3 FinalColor = DiffuseColor.rgb * Intensity;
gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);
}";
This is the “deferred lighting” shader that I’m using now, which is basically the same thing except this new one is used for each light, and only calculates the light’s intensity:
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
//attributes from vertex shader
varying LOWP vec4 vColor;
varying vec2 vTexCoord;
//texture samplers
uniform sampler2D u_texture;
//values for shading algorithm
uniform vec2 resolution; //Resolution of Screen
uniform vec3 lightPosition; //Position of Light, normalized
uniform LOWP vec4 lightColor; //Light RGBA -- alpha is intensity
uniform vec3 falloff; //attenuation coefficients
uniform float zoomModifier; //Inverse of camera zoom (1f/camera.zoom)
void main() {
//RGBA of our normal map
vec4 normalMapColor = texture2D(u_texture, vTexCoord);
//The Delta position of light
vec3 lightDir = vec3(lightPosition.xy - (gl_FragCoord.xy / resolution.xy), lightPosition.z);
//Correct for aspect ratio
lightDir.x *= resolution.x / resolution.y;
//Correct for camera zoom
lightDir.xy *= zoomModifier;
//Determine distance (used for attenuation) BEFORE we normalize our LightDir
float D = length(lightDir);
//Normalized-normalMapColor
vec3 N = normalize(normalMapColor * 2.0 - 1.0);
//Normalized-lightDirection
vec3 L = normalize(lightDir);
//Pre-multiply light color with intensity, then perform "N dot L" to determine diffuse term
vec3 diffuse = (lightColor.rgb * lightColor.a) * max(dot(N,L), 0.0);
//Calculate attenuation
float attenuation = 1.0 / (falloff.x + (falloff.y * D) + (falloff.z * D * D));
//Calculate intensity
vec3 finalIntensity = diffuse * attenuation;
gl_FragColor = vColor * vec4(finalIntensity.rgb, normalMapColor.a);
}
This is the rundown of what I’m doing with the new shader:
-
Render the scene normally to the screen (default shader, regular textures)
-
Draw all of my normal-maps to a FrameBuffer (“normalMapBuffer”)
-
On another FrameBuffer (“intensityFrameBuffer”), clear with the ambient light color
-
Set blending to additive (GL_ONE, GL_ONE)
-
For each of my lights, draw light to the intensityFrameBuffer using the normalMapBuffer texture and the newly-written shader
-
Set blending to multiply (GL_DST_COLOR, GL_ZERO)
-
Draw the intensityFrameBuffer to the screen
I’m pretty new to lighting/shaders, so I’m hoping its something simple I’m doing wrong, like using the wrong blending settings.
Original Shader with light intensity = 1:
Original Shader with light intensity = 2:
New Shader with light intensity = 1:
New Shader with light intensity = 2: