Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Getting harsh shadows with Deferred Lighting (video showing problem)

  1. #1
    Junior Member Newbie
    Join Date
    Jun 2017
    Posts
    3

    Getting harsh shadows with Deferred Lighting (video showing problem)

    Hey guys, here is an video of the problem: https://youtu.be/4nXbgaZw3x8

    I'm designing a lighting system in my game, and originally was using the shader from this tutorial: https://github.com/mattdesl/lwjgl-ba.../ShaderLesson6

    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:

    Code :
    //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:

    Code :
    #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:

    1) Render the scene normally to the screen (default shader, regular textures)

    2) Draw all of my normal-maps to a FrameBuffer ("normalMapBuffer")

    3) On another FrameBuffer ("intensityFrameBuffer"), clear with the ambient light color

    4) Set blending to additive (GL_ONE, GL_ONE)

    5) For each of my lights, draw light to the intensityFrameBuffer using the normalMapBuffer texture and the newly-written shader

    6) Set blending to multiply (GL_DST_COLOR, GL_ZERO)

    7) 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:

    Last edited by Jamez0r; 12-31-2017 at 02:31 PM.

  2. #2
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,329
    Quote Originally Posted by Jamez0r View Post
    ...whereas the new-shader can only darken (add shadows) since the blending is set to multiply
    ...
    6) Set blending to multiply (GL_DST_COLOR, GL_ZERO)
    ...
    You can do whatever you want, but if you want your lighting contributions to add to each other, you need to use an additive blending function.

    Moreover, if you want them to add correctly in a physically-realistic way, you need to use gamma-correct rendering and realistic material properties.

    NOTE: Shadow is the absence of a lighting contribution, not some artificial area where we've "sucked up" the existing illumination and thrown it away.

  3. #3
    Junior Member Newbie
    Join Date
    Jun 2017
    Posts
    3
    Quote Originally Posted by Dark Photon View Post
    You can do whatever you want, but if you want your lighting contributions to add to each other, you need to use an additive blending function.

    Moreover, if you want them to add correctly in a physically-realistic way, you need to use gamma-correct rendering and realistic material properties.

    NOTE: Shadow is the absence of a lighting contribution, not some artificial area where we've "sucked up" the existing illumination and thrown it away.
    Thanks for the help Photon and may the Schwartz be with you!

    My first goal is to recreate the lighting that I had in the original shader, but I saved a note to research gamma-correction / material properties so thanks for those keywords

    Keep in mind I'm pretty new to this so I'm fumbling my way through. I think I was incorrect in my complaint of how "harsh/pixelated" the shadows were. I think the only difference between the original shader's outcome and my new one is that I am ONLY rendering the shadows (though the multiply-blending) on the new one. I understand now that in order to have "highlights" I need an additive blending function.

    So I tried a couple things and came up with this:

    1) Render the scene normally to the screen (default shader, regular textures)

    2) Draw all of my normal-maps to a FrameBuffer ("normalMapBuffer")

    3) On another FrameBuffer ("intensityFrameBuffer"), clear with the ambient light color

    4) Set blending to additive (GL_ONE, GL_ONE)

    5) For each of my lights, draw light to the intensityFrameBuffer using the normalMapBuffer texture and the newly-written shader

    6) Set blending to multiply (GL_DST_COLOR, GL_ZERO)

    7) Draw the intensityFrameBuffer to the screen

    8) [NEW] Set blending back to additive (GL_ONE, GL_ONE)

    9) [NEW] On another FrameBuffer ("highlightFrameBuffer"), clear with Color(0,0,0,1)

    10) [NEW] Render each of the light's intensity onto the highlightFrameBuffer (same as step 5, but this time the FrameBuffer wasn't cleared with the ambient color)

    11) [NEW] Set blending mode to (GL_DST_COLOR, GL_ONE) --> I tried (GL_ONE, GL_ONE), but it didn't look as good. I'm totally guess-and-check'ing here, so if there is a recommended mode for this I'd be glad to learn about it

    12) [NEW] Render the highlightFrameBuffer to the screen


    The results looked pretty close to the original!




    So my question now... is there a more efficient way to have done this, or any other tips/suggestions?

    Thanks!!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •