Game Development Stack Exchange is a question and answer site for professional and independent game developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I now have changed from GLKBaseEffect to a own shader implementation. I have a shader management, which compiles and applies a shader to the right time and does some shader setup like lights. Please have a look at my vertex shader code. Now, light direction should be provided in eye space, but I think there is something I don't get right.

After I setup my view with camera I save a lightMatrix to transform the light from global space to eye space.

My modelview and projection setup:

- (void)setupViewWithWidth:(int)width height:(int)height camera:(N3DCamera *)aCamera {

    aCamera.aspect = (float)width / (float)height;
    float aspect = aCamera.aspect;
    float far = aCamera.far;
    float near = aCamera.near;
    float vFOV = aCamera.fieldOfView;

    float top = near * tanf(M_PI * vFOV / 360.0f);
    float bottom = -top;
    float right = aspect * top;
    float left = -right;

    // projection
    GLKMatrixStackLoadMatrix4(projectionStack, GLKMatrix4MakeFrustum(left, right, bottom, top, near, far));

    // identity modelview
    GLKMatrixStackLoadMatrix4(modelviewStack, GLKMatrix4Identity);

    // switch to left handed coord system (forward = z+)
    GLKMatrixStackMultiplyMatrix4(modelviewStack, GLKMatrix4MakeScale(1, 1, -1));  

    // transform camera
    GLKMatrixStackMultiplyMatrix4(modelviewStack, GLKMatrix4MakeWithMatrix3(GLKMatrix3Transpose(aCamera.orientation)));
    GLKMatrixStackTranslate(modelviewStack, -aCamera.position.x, -aCamera.position.y, -aCamera.position.z);

- (GLKMatrix4)modelviewMatrix {
    return GLKMatrixStackGetMatrix4(modelviewStack);

- (GLKMatrix4)projectionMatrix {
    return GLKMatrixStackGetMatrix4(projectionStack);

- (GLKMatrix4)modelviewProjectionMatrix {
    return GLKMatrix4Multiply([self projectionMatrix], [self modelviewMatrix]);

- (GLKMatrix3)normalMatrix {
    return GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3([self modelviewProjectionMatrix]), NULL);

After that, I save the lightMatrix like this:

[self.renderer setupViewWithWidth:view.drawableWidth height:view.drawableHeight];
self.lightMatrix = [self.renderer modelviewProjectionMatrix];

And just before I render a 3d entity of the scene graph, I setup the light config for its shader with the lightMatrix like this:

- (N3DLight)transformedLight:(N3DLight)light transformation:(GLKMatrix4)matrix {
    N3DLight transformedLight = N3DLightMakeDisabled();
    if (N3DLightIsDirectional(light)) {
        GLKVector3 direction = GLKVector3MakeWithArray(GLKMatrix4MultiplyVector4(matrix, light.position).v);
        direction = GLKVector3Negate(direction);    // HACK -> TODO: get lightMatrix right!
        transformedLight = N3DLightMakeDirectional(direction, light.diffuse, light.specular);
    } else {
    return transformedLight;

You see the line, where I negate the direction!? I can't explain why I need to do that, but if I do, the lights are correct as far as I can tell.

Please help me, to get rid of the hack.

I'am scared that this has something to do, with my switch to left handed coord system.

My vertex shader looks like this:

attribute highp     vec4    inPosition;
attribute lowp      vec4    inNormal;

uniform highp   mat4    MVP;
uniform highp   mat4    MV;
uniform lowp    mat3    N;

uniform lowp    vec4    constantColor;
uniform lowp    vec4    ambient;
uniform lowp    vec4    light0Position;
uniform lowp    vec4    light0Diffuse;
uniform lowp    vec4    light0Specular;

varying lowp    vec4    vColor;
varying lowp    vec3    vTexCoord0;

vec4 calcDirectional(vec3 dir, vec4 diffuse, vec4 specular, vec3 normal) {
    float NdotL = max(dot(normal, dir), 0.0);
    return NdotL * diffuse;


vec4 calcLight(vec4 pos, vec4 diffuse, vec4 specular, vec3 normal) {
    if (pos.w == 0.0) {             // Directional Light
        return calcDirectional(normalize(, diffuse, specular, normal);
    } else {

void main(void) {

    // position
    highp vec4 position = MVP * inPosition;        
    gl_Position = position;

    // normal
    lowp vec3 normal = / inNormal.w;
    normal = N * normal;
    normal = normalize(normal);

    // colors
    vColor = constantColor * ambient;

    // add lights
    vColor += calcLight(light0Position, light0Diffuse, light0Specular, normal);

share|improve this question
Out of the box, OpenGL is a right handed coordinate system... – stephelton Apr 19 '12 at 18:35
@stephelton: No, it isn't. – Nicol Bolas Apr 20 '12 at 0:37
@NicolBolas umm, yes it is... – stephelton Apr 20 '12 at 0:41
@stephelton: Regurgitating wrong information doesn't make it right. Clip-space, NDC space, Window-Space, using the default values of OpenGL is left handed. All of the "right-handed" spaces you're used to, like view space, model space, and so forth? Those don't exist in OpenGL ES 2.0+. They don't exist in core Desktop GL 3.2+. If you're using shaders, your final values are in a left-handed coordinate system. Your projection matrix can take right-handed values, but it needs to negate the Z, just as the fixed-function OpenGL projection matrix does. – Nicol Bolas Apr 20 '12 at 0:45
@NicolBolas, I didn't recognize your link in your first response until now. That's very interesting, I'm glad you pointed it out, and I'm glad that I read it. There seems to be a great deal of confusion related to handedness and OpenGL; just search something along the lines of "is OpenGL right or left handed?" You should get on chat more often :) – stephelton Apr 20 '12 at 2:14

I found the answer by myself. My engine represents the light direction, as the direction from the light source to the target surface. BUT, the shader needs the direction towards the light source and hence I have to negate the direction vector before passing to the shader.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.