Lighting Issue - Pre-/Post-Matrix-Multiplication


I’m confused why I have to use pre-multiplication to get correct lighting results when all samples seem to use post-multiplication without problems.

I created a simple example project, to isolate the issue. It contains a cube and a point light using basic Lambertian light calculation.

Standard post-multiplication results in incorrect lighting.
With pre-multiplication the lighting looks correct (identical to world space light calculation).


I haven’t tried your test app yet, but I should be able to explain a bit. Cinder uses the glm math library. It is designed to mimic OpenGL’s conventions. OpenGL uses row-major matrices. I always (still) have a problem remembering what row-major and column-major exactly mean, but I do know that row-major matrices need to be pre-multiplied to get proper results. Converting from object space to clip space, therefor, should be done like this:

gl_Position = ciProjectionMatrix * ciViewMatrix * ciModelMatrix * ciPosition;

(note: of course it’s easier to use ciModelViewProjection * ciPosition in this case, but that would not explain much).

The reason your lighting is incorrect is probably due to an error in your code. When transforming positions, always set the w-coordinate to 1:

uniform mat4 ciModelViewProjection;
uniform vec3 uLightWorldPosition;

in vec4 ciPosition;

out vec3 vLightViewPosition;

void main(void)
    vLightViewPosition = vec3( ciViewMatrix * vec4( uLightWorldPosition, 1 ) );
    gl_Position = ciModelViewProjection * ciPosition;

This is because the w-coordinate is multiplied with the translation component of the matrix (the 4th row). Setting it to 0 disables the translation.

Note: when transforming directions or normals (which are basically also directions), you only want to apply the rotation component (and sometimes the scaling component as well), so in those cases you set the w-coordinate to 0:

uniform vec3 uLightWorldDirection;
out vec3 vLightViewDirection;
vLightViewDirection = vec3( ciViewMatrix * vec4( uLightWorldDirection, 0 ) );

Let me know if you still have trouble getting your calculations to behave. Make sure your C++ code also applies the correct multiplication order and you should be fine.


Thank you very much Paul and sorry for wasting your time. I used w=0 for the light position. How could I not notice this…

No problem. Happy to help!

I tend to over-explain a bit, but this is so that less experienced users are also able to follow it.