Lighting Shader Confusion

Started by
5 comments, last by TheOrestes 9 years, 3 months ago

Hi,

I am encountering an issue where am sure I am the culprit but am not able to quite figure out what is it that I am doing wrong. Here is the vertex shader :


#version 400

layout(location=0) in vec3 in_Position;
layout(location=1) in vec3 in_Normal;
layout(location=2) in vec2 in_Tex;

out vec2 vs_outTex;
out vec3 vs_outNormal;
out vec3 vs_outLightDir;
out vec4 vs_outObjColor;

// uniforms...
uniform mat4 matWorld;
uniform mat4 matView;
uniform mat4 matProj;

vec3 LightDirection = vec3(1,1,1);
vec4 objColor = vec4(1,0,0,1);

void main()
{	
	mat4 WVP = matProj * matView * matWorld;
	gl_Position = WVP * vec4(in_Position, 1.0);

	vs_outNormal = in_Normal;
	vs_outLightDir = normalize(LightDirection);
	vs_outTex = in_Tex;
	vs_outObjColor = objColor;
}

and here is the fragment shader :


#version 400

in vec2 vs_outTex;
in vec3 vs_outNormal;
in vec3 vs_outLightDir;
in vec4 vs_outObjColor;

out vec4 outColor;

uniform sampler2D texture_diffuse1;

void main()
{
	vec4 baseColor = vec4(texture(texture_diffuse1, vs_outTex));
		
	float NdotL = max(dot(vs_outNormal, vs_outLightDir), 0);

	vec4 Emissive = baseColor;
	vec4 Ambient = vec4(0.2, 0.2, 0.2, 1);
	vec4 DiffuseDirect = vec4(NdotL);

	outColor = vs_outObjColor * DiffuseDirect; //Emissive; // * (Ambient + DiffuseDirect);
}

Here is the output produced by the shader during rendering :

Model_Space.png

Obviously, you guys must have noticed that I have not transformed object normals from object space to world space. Due to this, when the object rotates the lighting rotates with it giving a feeling that light is attached to the object and rotates with it. However, logically what I am trying to do is implement simple directional light shader where direction is suppose to be in world space, so no matter what orientation object is in, lighting direction remains constant.

For this to work, I took my object space normals to world space by doing following changes to the code in vertex shader :


vs_outNormal = (matWorld * vec4(in_Normal, 1.0)).xyz;

After doing this, here is the output I get :

World_Space.png

This time around, deer at the center receives proper lighting & gives impression of light ( which is global directional light ) being static if object rotates etc. However, other deer object's lighting has gone for the toss! Interestingly the closer i get left & right deers to the center deer object, lighting seems to be working fine. Here is the outptut :

World_Space_Close.png

Can anyone suggest where am I screwing up things? Why lighting seems to be working fine only when Object is at (0,0,0) but the time we move to left or right, lighting seem to be changing? ( Obviously this will happen in case the light source is point light with attenutation, but its directional light for me! )

Any thoughts or way forward in debugging will be really helpful.

Thanks.

Advertisement

vs_outNormal = (matWorld * vec4(in_Normal, 1.0)).xyz;

This is the problem. You should put w = 0 and not 1.0. This ensure that you are not translating the normal like position. You also need to renormalize the normal after that. Also make sure you aren't using nonuniform scaling.

Another way is to move directional light to object space. This way you don't need any transformations at vertex shader and just one inverse transform per object.

Looks like bit of more perseverance from my end would have helped me. So, instead of me taking all the normals to world space, I applied World Inverse transformation on the light direction vector, which did the trick for me.

Here is the modified code :


vs_outNormal = normalize(in_Normal);
vs_outLightDir = normalize((matWorldInv * vec4(LightDirection,0.0)).xyz);

Here is the output :

World_Inv_Fixed.png

Thanks.

P.S : Still in case you find anything wrong with the shader conceptually please let me know.

vs_outNormal = (matWorld * vec4(in_Normal, 1.0)).xyz;

This is the problem. You should put w = 0 and not 1.0. This ensure that you are not translating the normal like position. You also need to renormalize the normal after that. Also make sure you aren't using nonuniform scaling.

Another way is to move directional light to object space. This way you don't need any transformations at vertex shader and just one inverse transform per object.

Ahhh ... the W being 1 :( that was purely insane mistake from my end as its the vector i am transforming and not the point!

However, your second suggestion is exactly what i did to recify the mistake. Thanks a lot for assistance. :)

Fist of all your light direction should be normalized coz you only want to get the "cos" of the angle of light direction and normal and second when your changing your view you should use mat3(WV)*n_Normal and i guess you're calculating WVP in a wrong way it should be WVP = matWorld * matView * matProj; however it may not make big difference in how your scene is drawn but the standard is in this way. and also until your moving the camera and object it will feel like your light is static and your object is moving coz you are not multiplying light direction by WV

vs_outLightDir = normalize((matWorldInv * vec4(LightDirection,0.0)).xyz);

This being uniform per object you should do it at CPU once.

Yup. Totally. Thanks :-)

This topic is closed to new replies.

Advertisement