I have for a long time put off fixing up the lighting in a project i am working on in OpenTK. The problem basically is that when i rotate the camera, lighting displayed on the terrain i am showing also rotates.
Here's a snippet of my onRenderFrame code:
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
float dist = (float)Math.Sin(Math.PI / 3) * camZoom;
Matrix4 view = Matrix4.LookAt(new Vector3(-(float)Math.Cos(camRot) * dist, dist, -(float)Math.Sin(camRot) * dist) + camPos, camPos, new Vector3(0, 1, 0));
//Note: camPos isn't actually the position of the camera, rather the target of it. The actual camera position is calculated above.
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref view);
float tx = 50;
float ty = 20;
float tz = -15;
GL.Light(LightName.Light0, LightParameter.Position, new float[] { tx, ty, tz});
GL.Begin(BeginMode.Lines);
DrawBox(tx - 2, tx + 2, ty - 2, ty + 2, tz - 2, tz + 2);
GL.End();
... Drawing of terrain is here
I used my quick DrawBox function to draw a simple box around the location of the light. It is working fine, i even implemented some movement such as a sun around the earth. While the camera hadn't been moved, this was working great. But once i turned the camera, the lighting no longer showed what it should have, it seemed to have 'moved' the light, without actually moving it (the box drawn wasn't moved, only the effect of the light).
According to the OpenGL spec for glLight with the GL_POSITION parameter:
GL_POSITION: params contains four integer or floating-point values that specify the position of the light in homogeneous object coordinates. Both integer and floating-point values are mapped directly. Neither integer nor floating-point values are clamped.
The position is transformed by the modelview matrix when glLight is called (just as if it were a point), and it is stored in eye coordinates. If the w component of the position is 0, the light is treated as a directional source. Diffuse and specular lighting calculations take the light's direction, but not its actual position, into account, and attenuation is disabled. Otherwise, diffuse and specular lighting calculations are based on the actual location of the light in eye coordinates, and attenuation is enabled. The initial position is (0, 0, 1, 0); thus, the initial light source is directional, parallel to, and in the direction of the - z axis.
You only pass in three floats. I can't be certain what OpenTK uses as the fourth (w) component, but I would guess it makes any unspecified parameters 0, thereby making your light directional and ignoring the position you give. I would try adding a 1.0 to the end of the array you pass in and see if that fixes things.