I've been using the LearnOpenGL tutorials to calculate directional light. The diffuse works perfectly fine but the specular seems only work properly when the camera is near the origin and the specular is applied the same to all objects.
When I look at the second to last object i expect the specular to be the same as the object around the origin but instead it seems reacts to the origin and not the camera.
My guess is it's something to do with converting something to model space instead of camera space but as i'm new to glsl i'm lost as to where to look first.
Vertex shader:
#version 330 core
layout (location = 0) in vec3 vertexPosition;
layout (location = 1) in vec2 vertexUV;
layout (location = 2) in vec3 vertexNormal;
out vec3 VectorWorldPosition;
out vec2 UV;
out vec3 Normal_cameraspace;
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
void main()
{
gl_Position = MVP * vec4(vertexPosition, 1.0f);
VectorWorldPosition = (M * vec4(vertexPosition, 1.0f)).xyz;
Normal_cameraspace = vertexNormal;//(M*V* vec4(vertexNormal, 1.0f)).xyz;
UV = vertexUV;
}
Fragment Shader:
#version 330 core
in vec3 vertexWorldPosition;
in vec2 UV;
in vec3 Normal_cameraspace;
out vec4 color;
struct DirectionalLight{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct Material{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
uniform DirectionalLight dirLight;
uniform Material material;
uniform vec3 viewPos;
vec3 CalcDirectionalLight(DirectionalLight light, vec3 normal, vec3 viewDir);
void main()
{
vec3 output = vec3(0.0f);
vec3 norm = normalize(Normal_cameraspace);
vec3 viewDir = normalize(viewPos - vertexWorldPosition);
output += CalcDirectionalLight(dirLight, norm, viewDir);
color = vec4(output, 1.0f);
}
vec3 CalcDirectionalLight(DirectionalLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDirection = normalize(light.position);
float diff = clamp(dot(normal, lightDirection), 0.0, 1.0);
vec3 reflectDir = reflect(-lightDirection, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 ambient = light.ambient * vec3(texture(material.diffuse, UV));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, UV));
vec3 specular = light.specular * spec * vec3(texture(material.specular, UV));
return (ambient + diffuse + specular);
}
I'm using light position here when the tutorial asks to use direction. My thinking is that relative to the origin, position will be equal to direction. This works fine for diffuse so it should it work for specular.
Answer
You need to make sure that all your lighting calculations are done in the same space. Assuming your VertexNormal input is in model space, you can't just output it and call it 'Normal_CameraSpace'.
Decide where all your maths will be done. If it's in 'World' Space, then you need your normals to be transformed by the Inverse Transpose of the world matrix. Or the IT of the WorldView matrix if in camera space.
Your light vector needs to be transformed to the same space too.
And if you are calculating a vector to the viewer, then you need the world space location of your camera.
If you are in view/camera space, then your camera is always at the origin.
And of course, you need to transform the vertex position to the same space as well. I find it easier to think in 'WorldSpace'. You might want to start there...
Vertex Shader:
// World space position
vec4 world_pos = M * vec4(in_position, 1.0);
// perspective transformed position
gl_Position = MVP * vec4(in_position, 1.0);
// Matrix for transforming normals
mat4 invtransmodel = transpose(inverse(M));
world_normal = normalize((invtransmodel * vec4(in_normal, 0.0)).xyz);
No comments:
Post a Comment