Diffuse shading fix not working

I’ve got diffuse lighting working, but it seems to be stuck in world space. I’ve looked at a few guides and understand that the reason this is happening is because the model is being lit in world space and then once it’s transformed to model space, it keeps the lighting it received from world space. Great demonstration of the problem here.

To fix this, I’m doing the following (except it’s not working):

Vertex Shader


#version 440 compatibility
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in float offset;

out vec3 theNormal;
out vec3 thePosition;

uniform mat4 FullTransformMatrix;
uniform mat4 ModelToWorldTransformMatrix;

void main() {
	
	vec4 v = vec4(position, 1.0);
	gl_Position = FullTransformMatrix * v;
	theNormal = normal;
	thePosition = vec3(ModelToWorldTransformMatrix * v);
}

Fragment Shader


#version 440 compatibility
layout(location = 0) out vec4 outColor;
in vec3 theNormal;
in vec3 thePosition;

uniform vec3 LightPosition;

void main()
{
	vec3 lightVector = normalize(LightPosition - thePosition);
	float brightness = dot(lightVector, theNormal);
	outColor = vec4(brightness, brightness, brightness, 1.0);
}

Part of the update loop


		glm::mat4 ProjectionMatrix = mainCamera->getProjectionMatrix ();
		glm::mat4 ViewMatrix = mainCamera->getViewMatrix ();
	
		// Plane
		glBindVertexArray ( planeVertexArray );
		translation = glm::translate ( glm::mat4 ( 1 ), glm::vec3 ( 0.0f, 0.0f, 0.0f ) );
		ModelMatrix = glm::rotate ( translation, 0.0f, glm::vec3 ( 1.0f, 0.0f, 0.0f ) );
		mvp = ProjectionMatrix * ViewMatrix * ModelMatrix;
		glProgramUniformMatrix4fv ( program, modelToWorldMatrixLocation, 1, GL_FALSE, &ModelMatrix[0][0] );
		glProgramUniformMatrix4fv ( program, fullTransformMatrixLocation, 1, GL_FALSE, &mvp[0][0] );
		glDrawElements ( GL_TRIANGLES, planeIndices.size (), GL_UNSIGNED_INT, ( void* ) ( planeVertices.size () * sizeof ( GLfloat ) ) );
				
		glBindVertexArray ( vertexArray );
		// Object 1
		translation = glm::translate ( glm::mat4 ( 1 ), glm::vec3 ( 2.0f, 2.0f, -2.0f ) );
		ModelMatrix = glm::rotate (translation, 180.0f, glm::vec3 ( 0.0, 1.0f, 0.0f ) );
		mvp = ProjectionMatrix * ViewMatrix * ModelMatrix;
		glProgramUniformMatrix4fv ( program, fullTransformMatrixLocation, 1, GL_FALSE, &mvp[0][0] );
		glProgramUniformMatrix4fv ( program, modelToWorldMatrixLocation, 1, GL_FALSE, &ModelMatrix[0][0] );
		//glDrawElementsInstanced ( GL_TRIANGLES, suzIndices.size (), GL_UNSIGNED_INT, nullptr, 3 );
		glDrawElements ( GL_TRIANGLES, suzIndices.size (), GL_UNSIGNED_INT, ( void* ) (suzVertices.size() * sizeof(GLfloat)) );

		// Object 2
		translation = glm::translate ( glm::mat4 ( 1 ), glm::vec3 ( 0.0f, 2.0f, 2.0f ) );
		ModelMatrix = glm::rotate ( translation, 0.0f, glm::vec3 ( 0.0f, 1.0f, 0.0f ) );
		mvp = ProjectionMatrix * ViewMatrix * ModelMatrix;
		glProgramUniformMatrix4fv ( program, fullTransformMatrixLocation, 1, GL_FALSE, &mvp[0][0] );
		glProgramUniformMatrix4fv ( program, modelToWorldMatrixLocation, 1, GL_FALSE, &ModelMatrix[0][0] );
		glDrawElements ( GL_TRIANGLES, suzIndices.size (), GL_UNSIGNED_INT, ( void* ) ( suzVertices.size () * sizeof ( GLfloat ) ) );

What gives?

hi,

i just took a quik look, but i am very sure you forget to rotate the normals.
as the normals are relevant for the dotproduct of light, you need to have a matrix that only includes rotation .
multiply this one with the normals in the vertex shader and you should be fine …

cu
uwi2k2

Hm. Only rotation? I’m putting both translation and rotation (and in the future, scale) into the model matrix.


translation = glm::translate ( glm::mat4 ( 1 ), glm::vec3 ( 0.0f, 0.0f, 0.0f ) );
ModelMatrix = glm::rotate ( translation, 0.0f, glm::vec3 ( 1.0f, 0.0f, 0.0f ) );

In the vertex Shader, ModelMatrix is called ModelToWorldTransformMatrix. I multiple the position by it. I don’t see any diffuse shading examples where the normals are multiplied by a rotation matrix. This is essential what my shaders are (just different variable names and out of order): https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php

EDIT: All is good… had to get farther in that tutorial series… derp. Rotation wasn’t being factored in. So, you were right.

You need to ensure that any translation doesn’t affect the normal.

You can either extract the upper-left 3x3 submatrix and transform the normals by that, or convert the normal from vec3 to vec4 with zero as the w component (meaning that the values in the right-hand column of the matrix will always be multiplied by zero, resulting in them having no effect upon the transformed normal).

One other caveat: if the matrix isn’t orthogonal (e.g. if it includes non-uniform scaling), then the normals must be transformed by the inverse of the transpose of the matrix. If the matrix is orthogonal, then the inverse and the transpose are the same except for a uniform scaling factor, so you can just use the original matrix (so long as the normals are scaled correctly).

To see why this is required, consider “squashing” a shape vertically. The slope of each face will become closer to horizontal, meaning that its normal will become closer to vertical.