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 7 of 7

Thread: Revisiting Lighting in GLSL ...

  1. #1
    Junior Member Regular Contributor
    Join Date
    Apr 2014
    Posts
    109

    Revisiting Lighting in GLSL ...

    Hello,

    I know folks have helped me in the past on this and I truly believe I am almost there.

    So, after much work I believe my directional light is working in the scene, sort of, but I still get weird artifacts and effects.

    Positional lighting doesn't seem to work at all.

    Also, my entire scene is poorly lit and I am not sure what I am doing wrong to have this binary "on, off" effect with lighting.

    Anyway, here is what I am talking about.

    With positional lighting coming from a point in one direction, the entire scene is dark, as shown below:



    When I enable just directional lighting per my shader code; I get the light coming from the right direction but it essentially comes in as an "on, off" thing. You'll see that I highlighted the areas in the image below where essentially the object is getting light and then right in the next pixel over there is no light:



    To show people that I am loading normals, I did a simple "finalColor = NormalColor" colorizer in my shader code.

    Here is the resultant image of the scene at the same angle:



    Also, per usual, here is my vertex shader:

    Code :
    #version 330 core
    #extension GL_ARB_explicit_attrib_location : require
     
    layout(location = 0) in vec3 vPosition;
    layout(location = 1) in vec3 vNormal;
    layout(location = 2) in vec2 vUV;
     
    layout (std140) uniform Sunlight
    {
     
      vec4 SunlightPosition;
      vec4 SunlightDiffuse;
      vec4 SunlightSpecular;
      vec4 SunlightDirection;
      float constantAttenuation, linearAttenuation, quadraticAttenuation;
      float spotCutoff, spotExponent;
      float	EnableLighting;
      float	EnableSun;
      float ExtraValue;
     
    };
     
    out vec4 worldSpacePosition;  // position of the vertex (and fragment) in world space
    out vec3 vertexNormalDirection;  // surface normal vector in world space
    out vec2 TextureCoordinates;
    out vec3 NormalColor;
     
    uniform mat4 MVP;
    uniform mat4 ModelMatrix;
    uniform mat4 ViewMatrix;
    uniform mat4 ViewModelMatrix;
    uniform mat4 InverseViewMatrix;
    uniform mat3 NormalMatrix;
     
    void main()
    {
     
    	gl_Position = MVP * vec4(vPosition, 1.0);
    	TextureCoordinates = vUV;
    	worldSpacePosition = ModelMatrix * vec4(vPosition, 1.0);
    	vertexNormalDirection = normalize(NormalMatrix * vNormal);
    	NormalColor = vNormal;
     
    }

    And here is my fragment shader:

    Code :
    #version 330
    #extension GL_ARB_explicit_attrib_location : require
     
    precision highp float;
     
    uniform mat4 MVP;
    uniform mat4 ModelMatrix;
    uniform mat4 ViewMatrix;
    uniform mat4 ViewModelMatrix;
    uniform mat4 InverseViewMatrix;
    uniform mat3 NormalMatrix;
     
    //
    // These values vary per Mesh
    //
     
    uniform vec4 	AmbientMeshColor;
    uniform vec4 	EmissiveMeshColor;
    uniform vec4 	DiffuseMeshColor;
    uniform vec4 	SpecularMeshColor;
    uniform vec4	SceneBrightnessColor;
    uniform float 	MeshShininess;
    uniform float	ObjectHasTextureFile;
     
    //
    // Sunlight Settings.
    //
     
    layout (std140) uniform Sunlight
    {
     
      vec4 SunlightPosition;
      vec4 SunlightDiffuse;
      vec4 SunlightSpecular;
      vec4 SunlightDirection;
      float constantAttenuation, linearAttenuation, quadraticAttenuation;
      float spotCutoff, spotExponent;
      float	EnableLighting;
      float	EnableSun;
      float ExtraValue;
     
    };
     
    uniform vec4		SceneAmbient;
     
    //
    // Whether Materials are enabled at all.
    //
     
    uniform float		IfEnableTextures;
     
    //
    // If we are just simply drawing the skybox.
    //
     
    uniform float		DrawingSkyBox;
     
    uniform float 		DrawNormals;
     
    uniform float		EnableWireframe;
     
    uniform vec4		WireframeColor;
     
    uniform float		TextureCoordinateDebug;
     
    uniform sampler2D MainTextureSampler; 
     
    in vec4 worldSpacePosition;
    in vec3 vertexNormalDirection;
    in vec2 TextureCoordinates;
    in vec3 NormalColor;
     
    vec4 finalDiffuseColor;
     
    out vec4 finalColor;
     
    void DrawSkyBox() {
     
    	finalColor = texture(MainTextureSampler, TextureCoordinates);
     
    }
     
    void DrawWireFrame() {
     
    	finalColor = WireframeColor;
     
    }
     
    void main()
     
    {
     
    	if (DrawingSkyBox != 1.0) {
     
    		if (DrawNormals == 1.0) {
     
    			finalColor = vec4(NormalColor, 1.0);
     
    		} else {
     
    			vec3 normalDirection = normalize(vertexNormalDirection);
     
    			vec3 viewDirection = normalize(vec3(InverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) - worldSpacePosition));
     
    			vec3 lightDirection;
     
    			float attenuation;
     
    			if (SunlightPosition.w == 0.0) // directional light?
    			{
     
    				attenuation = 1.0; // no attenuation
    				lightDirection = normalize(vec3(SunlightPosition));
     
    			} 
    			else // point light or spotlight (or other kind of light) 
    			{
     
    				vec3 positionToLightSource = vec3(SunlightPosition - worldSpacePosition);
    				float distance = length(positionToLightSource);
    				lightDirection = normalize(positionToLightSource);
    				attenuation = 1.0 / (constantAttenuation
    							   + linearAttenuation * distance
    							   + quadraticAttenuation * distance * distance);
     
    				if (spotCutoff <= 90.0) // spotlight?
    				{
     
    					float clampedCosine = max(0.0, dot(-lightDirection, vec3(SunlightDirection)));
    					if (clampedCosine < cos(radians(spotCutoff))) // outside of spotlight cone?
    					{
    						attenuation = 0.0;
    					}
    					else
    					{
     
    					  attenuation = attenuation * pow(clampedCosine, spotExponent); 
     
    					}
    				}
    			}
     
    			vec4 ambientLighting = SceneAmbient * AmbientMeshColor;
     
    			vec3 diffuseReflection;
     
    			if (ObjectHasTextureFile == 1.0) {
     
    				diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(texture(MainTextureSampler, TextureCoordinates)) * max(0.0, dot(normalDirection, normalDirection));
     
    			} else {
     
    				diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(DiffuseMeshColor) * max(0.0, dot(normalDirection, normalDirection));
     
    			}
     
    			vec3 specularReflection;
     
    			if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?
    			{
     
    				specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection
     
    			}
    			else // light source on the right side
    			{
     
    				specularReflection = attenuation * vec3(SunlightSpecular) * vec3(SpecularMeshColor) * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), MeshShininess);
     
    			}
     
    			finalColor = vec4(vec3(ambientLighting) + diffuseReflection + specularReflection, DiffuseMeshColor.a);
     
    		}
     
    	} else {
     
    		DrawSkyBox();
     
    	}
     
    }

    Thank you for your time.
    Last edited by tmason; 02-11-2015 at 06:28 AM.

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,463
    Quote Originally Posted by tmason View Post
    Code :
    		if (ObjectHasTextureFile == 1.0) {
    			diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(texture(MainTextureSampler, TextureCoordinates)) * max(0.0, dot(normalDirection, normalDirection));
    		} else {
    			diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(DiffuseMeshColor) * max(0.0, dot(normalDirection, normalDirection));
    		}
    Should dot(normalDirection, normalDirection) be dot(normalDirection, lightDirection)? The former is just the square of the magnitude of normalDirection, which will be 1.0 (as normalDirection is normalised).

    At present, lightDirection is only used in calculating specularReflection.

  3. #3
    Junior Member Regular Contributor
    Join Date
    Apr 2014
    Posts
    109
    Thank you for catching that! Unfortunately, it didn't make much of a difference:

    Here is the updated fragment shader code:

    Code :
    #version 330
    #extension GL_ARB_explicit_attrib_location : require
     
    precision highp float;
     
    uniform mat4 MVP;
    uniform mat4 ModelMatrix;
    uniform mat4 ViewMatrix;
    uniform mat4 ViewModelMatrix;
    uniform mat4 InverseViewMatrix;
    uniform mat3 NormalMatrix;
     
    //
    // These values vary per Mesh
    //
     
    uniform vec4 	AmbientMeshColor;
    uniform vec4 	EmissiveMeshColor;
    uniform vec4 	DiffuseMeshColor;
    uniform vec4 	SpecularMeshColor;
    uniform vec4	SceneBrightnessColor;
    uniform float 	MeshShininess;
    uniform float	ObjectHasTextureFile;
     
    //
    // Sunlight Settings.
    //
     
    layout (std140) uniform Sunlight
    {
     
      vec4 SunlightPosition;
      vec4 SunlightDiffuse;
      vec4 SunlightSpecular;
      vec4 SunlightDirection;
      float constantAttenuation, linearAttenuation, quadraticAttenuation;
      float spotCutoff, spotExponent;
      float	EnableLighting;
      float	EnableSun;
      float ExtraValue;
     
    };
     
    uniform vec4		SceneAmbient;
     
    //
    // Whether Materials are enabled at all.
    //
     
    uniform float		IfEnableTextures;
     
    //
    // If we are just simply drawing the skybox.
    //
     
    uniform float		DrawingSkyBox;
     
    uniform float 		DrawNormals;
     
    uniform float		EnableWireframe;
     
    uniform vec4		WireframeColor;
     
    uniform float		TextureCoordinateDebug;
     
    uniform sampler2D MainTextureSampler; 
     
    in vec4 worldSpacePosition;
    in vec3 vertexNormalDirection;
    in vec2 TextureCoordinates;
    in vec3 NormalColor;
     
    vec4 finalDiffuseColor;
     
    out vec4 finalColor;
     
    void DrawSkyBox() {
     
    	finalColor = texture(MainTextureSampler, TextureCoordinates);
     
    }
     
    void DrawWireFrame() {
     
    	finalColor = WireframeColor;
     
    }
     
    void main()
     
    {
     
    	if (DrawingSkyBox != 1.0) {
     
    		if (DrawNormals == 1.0) {
     
    			finalColor = vec4(NormalColor, 1.0);
     
    		} else {
     
    			vec3 normalDirection = normalize(vertexNormalDirection);
     
    			vec3 viewDirection = normalize(vec3(InverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) - worldSpacePosition));
     
    			vec3 lightDirection;
     
    			float attenuation;
     
    			if (SunlightPosition.w == 0.0) // directional light?
    			{
     
    				attenuation = 1.0; // no attenuation
    				lightDirection = normalize(vec3(SunlightPosition));
     
    			} 
    			else // point light or spotlight (or other kind of light) 
    			{
     
    				vec3 positionToLightSource = vec3(SunlightPosition - worldSpacePosition);
    				float distance = length(positionToLightSource);
    				lightDirection = normalize(positionToLightSource);
    				attenuation = 1.0 / (constantAttenuation
    							   + linearAttenuation * distance
    							   + quadraticAttenuation * distance * distance);
     
    				if (spotCutoff <= 90.0) // spotlight?
    				{
     
    					float clampedCosine = max(0.0, dot(-lightDirection, vec3(SunlightDirection)));
    					if (clampedCosine < cos(radians(spotCutoff))) // outside of spotlight cone?
    					{
    						attenuation = 0.0;
    					}
    					else
    					{
     
    					  attenuation = attenuation * pow(clampedCosine, spotExponent); 
     
    					}
    				}
    			}
     
    			vec4 ambientLighting = SceneAmbient * AmbientMeshColor;
     
    			vec3 diffuseReflection;
     
    			if (ObjectHasTextureFile == 1.0) {
     
    				diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(texture(MainTextureSampler, TextureCoordinates)) * max(0.0, dot(normalDirection, lightDirection));
     
    			} else {
     
    				diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(DiffuseMeshColor) * max(0.0, dot(normalDirection, lightDirection));
     
    			}
     
    			vec3 specularReflection;
     
    			if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?
    			{
     
    				specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection
     
    			}
    			else // light source on the right side
    			{
     
    				specularReflection = attenuation * vec3(SunlightSpecular) * vec3(SpecularMeshColor) * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), MeshShininess);
     
    			}
     
    			finalColor = vec4(vec3(ambientLighting) + diffuseReflection + specularReflection, DiffuseMeshColor.a);
     
    		}
     
    	} else {
     
    		DrawSkyBox();
     
    	}
     
    }

    And here are the update images based on the above code:



    With directional light, I still get the on/off effect:



    And here is the normal shown from the exact same angle:


  4. #4
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,463
    Looking more closely, your normals look wrong.

    E.g. the right-facing surfaces on the left-hand wall are bright green, as are the viewpoint-facing surfaces on the stairs. On the pillar in the foreground, right-facing surfaces are red (and no part shows any green or blue); but the right-hand wall has red on viewpoint-facing surfaces.

    Try replacing NormalMatrix with ModelMatrix just to eliminate one possible source of error. Provided that ModelMatrix contains only rotations, translations and uniform scaling, there's no need for a separate normal matrix.

    Also, much of the information is missing because you're writing signed values to an unsigned texture format, so negative values are being clamped to zero; consider writing out (NormalColor+vec3(1))/2 instead.

    Apart from that, try writing out individual lighting components (diffuse, specular) to narrow down the problem.

  5. #5
    Senior Member OpenGL Lord
    Join Date
    May 2009
    Posts
    5,923
    By the way:

    Code :
    #version 330 core
    #extension GL_ARB_explicit_attrib_location : require

    Explicit attribute location is part of OpenGL 3.3 (and thus GLSL 3.30). So you don't have to specify it twice; just the version will be sufficient.

  6. #6
    Junior Member Regular Contributor
    Join Date
    Apr 2014
    Posts
    109
    You were correct! My normal Matrix was being created from the MVP instead of the ModelMatrix.

    This was causing all kinds of problems as folks can imagine.

    I still need a bit of assistance but things are working a bit more consistent now.

    Quote Originally Posted by GClements View Post
    Looking more closely, your normals look wrong.

    E.g. the right-facing surfaces on the left-hand wall are bright green, as are the viewpoint-facing surfaces on the stairs. On the pillar in the foreground, right-facing surfaces are red (and no part shows any green or blue); but the right-hand wall has red on viewpoint-facing surfaces.

    Try replacing NormalMatrix with ModelMatrix just to eliminate one possible source of error. Provided that ModelMatrix contains only rotations, translations and uniform scaling, there's no need for a separate normal matrix.

    Also, much of the information is missing because you're writing signed values to an unsigned texture format, so negative values are being clamped to zero; consider writing out (NormalColor+vec3(1))/2 instead.

    Apart from that, try writing out individual lighting components (diffuse, specular) to narrow down the problem.

  7. #7
    Junior Member Regular Contributor
    Join Date
    Apr 2014
    Posts
    109
    Thank you; will remove.

    Quote Originally Posted by Alfonse Reinheart View Post
    By the way:

    Code :
    #version 330 core
    #extension GL_ARB_explicit_attrib_location : require

    Explicit attribute location is part of OpenGL 3.3 (and thus GLSL 3.30). So you don't have to specify it twice; just the version will be sufficient.

Tags for this Thread

Posting Permissions

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