I am trying to implement a shader for directional lights correctly, but I am bit confused as to why it works when it shouldn't and vice versa.
People usually encounter problem with lights changing direction with camera. This is corrected by multiplying normals with model(view) matrix.
But my problem is opposite.
When I don't multiply normals with model(view) matrix then it works and when I try to use (supposedly) correct version it is having that "lights rotating with camera" problem.
Any ideas?
Working vertex shader:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
out vec2 texCoord0;
out vec3 normal0;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main()
{
normal0 = normal;
gl_Position = proj * view * model* vec4(position, 1.0);
texCoord0 = texCoord;
}
Fragment shader:
#version 330
in vec2 texCoord0;
in vec3 normal0;
out vec4 outColor;
struct BaseLight
{
vec3 color;
float intensity;
};
struct DirectionalLight
{
BaseLight base;
vec3 direction;
};
uniform vec3 baseColor;
uniform vec3 ambientLight;
uniform sampler2D sampler;
uniform DirectionalLight directionalLight;
vec4 calcLight(BaseLight base, vec3 direction, vec3 normal)
{
float diffuseFactor = dot(normal, -direction);
vec4 diffuseColor = vec4(0,0,0,0);
if(diffuseFactor > 0)
{
diffuseColor = vec4(base.color, 1.0) * base.intensity * diffuseFactor;
}
return diffuseColor;
}
vec4 calcDirectionalLight(DirectionalLight directionalLight, vec3 normal)
{
return calcLight(directionalLight.base, -directionalLight.direction, normal);
}
void main()
{
vec4 totalLight = vec4(ambientLight,1);
vec3 normal = normalize(normal0);
totalLight += calcDirectionalLight(directionalLight, normal);
outColor = texture(sampler, texCoord0.xy) * vec4(baseColor, 1) * totalLight;
}
Draw method:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex::SIZE* 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex::SIZE * 4, (const GLvoid*)12);
glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex::SIZE * 4, (const GLvoid*)20);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
Matices:
ViewTranslate = glm::mat4(1.0f);
cam->control(windowHandle, 0.01, 0.3, true, &ViewTranslate);
cam->updateCamera(&ViewTranslate);
glm::mat4 Projection =
glm::perspective(70.0f, 800.0f / 600.0f, 0.1f, 10000.0f);
glm::mat4 view = glm::lookAt(
glm::vec3(0, 0, 1),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
);
shader->bind();
shader->setUniform("model", glm::value_ptr(ViewTranslate));
shader->setUniform("view", glm::value_ptr(view));
shader->setUniform("proj", glm::value_ptr(Projection));
shader->setUniform("ambientLight", ambientLight);
Not working shader code:
void main()
{
normal0 = (model * vec4(normal, 0.0)).xzy;
gl_Position = proj * view * model* vec4(position, 1.0);
texCoord0 = texCoord;
}
or
void main()
{
normal0 = (model * view * vec4(normal, 0.0)).xzy;
gl_Position = proj * view * model* vec4(position, 1.0);
texCoord0 = texCoord;
}
or
void main()
{
normal0 = (model * view * vec4(normal, 1.0)).xzy;
gl_Position = proj * view * model* vec4(position, 1.0);
texCoord0 = texCoord;
}
or
void main()
{
normal0 = (transpose(inverse(model * view)) * vec4(normal, 1.0)).xzy;
gl_Position = proj * view * model* vec4(position, 1.0);
texCoord0 = texCoord;
}
...
Any ideas how I should do this correctly?