PDA

View Full Version : Revisiting Lighting in GLSL ...



tmason
02-11-2015, 05:22 AM
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:

http://s3.postimg.org/qwmbxdgwz/Spotlight_No_Color_Whatsoever.jpg

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:

http://s28.postimg.org/azqyvt0el/Weird_Triangles_Commented.jpg

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:

http://s2.postimg.org/mbdio71k9/Room_With_Normals.jpg

Also, per usual, here is my vertex shader:



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



#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.

GClements
02-11-2015, 05:42 AM
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.

tmason
02-11-2015, 06:12 AM
Thank you for catching that! Unfortunately, it didn't make much of a difference:

Here is the updated 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, 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:

http://s8.postimg.org/vdruj6j2d/Nothing_with_Positional_Light.jpg

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

http://s2.postimg.org/ld86ivyqx/Triangulation_Still_There_Commented.jpg

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

http://s4.postimg.org/nf4utev7h/Normals_from_Same_Angle.jpg

GClements
02-11-2015, 10:16 AM
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.

Alfonse Reinheart
02-11-2015, 03:51 PM
By the way:



#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.

tmason
02-12-2015, 04:23 AM
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.


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.

tmason
02-12-2015, 04:23 AM
Thank you; will remove.


By the way:



#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.