0
votes

I have a working per fragment lighting but I wonder what can I do to keep a lighting calculation in the modelspace where I don't have to multiply normals by normalModelMatrix as below in the fragment shader.

Shaders: ViewMatrix - camera transformation, ModelMatrix - objects transfomation. Light position - glm::vec4 lightPos(3.0f, 2.0f, -30.0f, 1.0f)

Render loop:

glUseProgram(ProgramId);
glUniformMatrix4fv(ViewMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr(ViewMatrix));
glUniform4f(lightIntensityUniformLocation, 0.8f, 0.8f, 0.8f, 1.0f);
glUniform4f(ambientIntensityUniformLocation, 0.2f, 0.2f, 0.2f, 0.2f);
glUniform3fv(dirToLightUniformLocation, 1, glm::value_ptr( lightPos));

ModelMatrixStack.push(ModelMatrix);
ModelMatrix = glm::translate(ModelMatrix, glm::vec3(0, 0, -30));
ModelMatrix = glm::rotate(ModelMatrix, 75.0f, glm::vec3(0,0,1)); 
normMatrix = glm::mat3(ModelMatrix);
glUniformMatrix4fv(ModelMatrixUniformLocation, 1, GL_FALSE,           
glm::value_ptr(ModelMatrix));   
glUniformMatrix3fv(normalModelMatrixUniformLocation, 1, GL_FALSE, 
glm::value_ptr(normMatrix));
drawTeapot();

ModelMatrix = ModelMatrixStack.top();
normMatrix = glm::mat3(ModelMatrix);

glUniformMatrix4fv(ModelMatrixUniformLocation, 1, GL_FALSE,  
glm::value_ptr(ModelMatrix));
glUniformMatrix3fv(normalModelMatrixUniformLocation, 1, GL_FALSE,  
glm::value_ptr(normMatrix));
myground.draw();

glUseProgram(0);

Vertex shader:

#version 400

layout(location=0) in vec4 in_position;
layout(location=1) in vec3 in_normal;
out vec3 normal;
out vec4 position;

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

void main(void)
{
     vec4 vertexPosition = ModelMatrix * in_position;
     gl_Position = ProjectionMatrix * ViewMatrix * vertexPosition;
     normal = in_normal;
     position = vertexPosition;
}

Fragment shader:

version 400

in vec3 normal;
in vec4 position;
out vec4 outputColor;

uniform vec3 lightPos;
uniform vec4 lightIntensity;
uniform vec4 ambientIntensity;
uniform mat3 normalModelMatrix;

void main(void)
{
     vec3 normCamSpace = normalize(normalModelMatrix * normalize(normal));
     vec3 dirToLight = normalize(lightPos - vec3(position));
     float cosAngIncidence = dot(normCamSpace, dirToLight);
     cosAngIncidence = clamp(cosAngIncidence, 0, 1);
     outputColor = (lightIntensity * cosAngIncidence) + ambientIntensity;
}
1

1 Answers

2
votes

The computational cost for doing illumination in model space is actually higher, than doing it in eye space, as you've to transform the light position and directions for individually each model. Those usually happen on the CPU side. Yet you still have to perform a transformation of the normals then.

modelspace where I don't have to multiply normals by normalModelMatrix as below in the fragment shader.

That calculation works as well in the vertex shader. Just move it there.


Update/EDIT

for clarification here the modified shader code:

Vertex shader:

#version 400

layout(location=0) in vec4 in_position;
layout(location=1) in vec3 in_normal;

out vec3 eyespaceNormal;
out vec4 eyespacePosition;

uniform mat4 ModelviewMatrix;
uniform mat3 NormalMatrix; // == inverse(transpose(ModelviewMatrix))
uniform mat4 ProjectionMatrixq;

void main(void)
{
     eyespacePosition = ModelviewMatrix * in_position;
     eyespaceNormal = normalize(NormalMatrix * in_normal);
     gl_Position = ProjectionMatrix * eyespacePosition;
}

Fragment shader:

#version 400

in vec3 eyespaceNormal;
in vec4 eyespacePosition;
out vec4 outputColor;

uniform vec3 lightPos;
uniform vec4 lightIntensity;
uniform vec4 ambientIntensity;

void main(void)
{
     vec3 dirToLight = normalize(lightPos - vec3(eyespacePosition));
     float cosAngIncidence = dot(eyespaceNormal, dirToLight);
     cosAngIncidence = clamp(cosAngIncidence, 0, 1);
     outputColor = (lightIntensity * cosAngIncidence) + ambientIntensity;
}

BTW: You normal transformation matrix was wrong. You must use the inverse of the transposed modelview matrix for this.