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 camera:self.camera];
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(pos.xyz), diffuse, specular, normal);
} else {
...
}
}
void main(void) {
// position
highp vec4 position = MVP * inPosition;
gl_Position = position;
// normal
lowp vec3 normal = inNormal.xyz / inNormal.w;
normal = N * normal;
normal = normalize(normal);
// colors
vColor = constantColor * ambient;
// add lights
vColor += calcLight(light0Position, light0Diffuse, light0Specular, normal);
...
}