Revisiting Lighting in GLSL ...

Started by
6 comments, last by L. Spiro 9 years, 2 months ago

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:

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:

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:

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.

Advertisement

diffuseReflection = attenuation * vec3(SunlightDiffuse) * vec3(DiffuseMeshColor) * max(0.0, dot(normalDirection, normalDirection));

max(0.0, dot(normalDirection, normalDirection)); <-- this should describe with a value from 0 to 1 how bright the surface is

( you compute the squared distance of the normalDirection, which should always evaluate to 1 )

replace with

max(0, dot(normalDirection, lightDirection))

if both vectors are normalized this gives you the cosine of the angle between the vectors

for testing i suggest to compute only

finalColor = vec4(vec3(max(0, dot(normalDirection, lightDirection))), 1);

vec3 viewDirection = normalize(vec3(InverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) - worldSpacePosition));

What is this computing?

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

first of all viewMatrix is a matrix that transforms from worldspace to camera space

the inverse therefore transforms camera space to worldspace

which means you transform the coordinate (0,0,0) from camera to worldspace, and this is the camera position in world space coordinate system

i usually just pass the camera position vec3 uniform to the shader which is much simpler and clearer

if this matrix multiplication is unclear to you it may be valuable todo the matrix multiplication once by hand, and you will see that multiplying with vec4(0,0,0,1) is same as extracting the translational part of the matrix

oh i didnt actually answer your question ...

as i explained in my previous post vec3(InverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) is equal to the camera position in world space

what you want is a directional vector pointing from the fragments worldspace position to the viewer (= camera position) which is computed by

vec3 viewDirection = normalize(cameraPosition - worldSpacePosition));

vec3 viewDirection = normalize(vec3(InverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) - worldSpacePosition));

Don’t.

#1: Lighting is done in view space unless you have a very specific reason otherwise. Transform your directional, point, and spot lights once on the CPU to put them into view space and then you can either assume the view direction is [0,0,-1] or you can do normalize(-gl_Position) for accuracy.
#2: Even if you light in world space, the above code is a hack. See oggs91’s above reply.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

vec3 viewDirection = normalize(vec3(InverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) - worldSpacePosition));

Don’t.

#1: Lighting is done in view space unless you have a very specific reason otherwise. Transform your directional, point, and spot lights once on the CPU to put them into view space and then you can either assume the view direction is [0,0,-1] or you can do normalize(-gl_Position) for accuracy.
#2: Even if you light in world space, the above code is a hack. See oggs91’s above reply.


L. Spiro

For correct view vector you can't normalize gl_Position at vertex shader but you need to interpolate unnormalized viewVector and normalize it at fragment shader.

https://interplayoflight.wordpress.com/2013/05/17/correctly-interpolating-viewlight-vectors-on-large-triangles/

For correct view vector you can't normalize gl_Position at vertex shader but you need to interpolate unnormalized viewVector and normalize it at fragment shader.

I certainly didn’t mean to imply otherwise. Just keeping the explanation necessarily simple.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement