From here:
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glLight.xml
for GL_POSITION it says "params contains four integer or floating-point
values that specify the position of the light in homogeneous object
coordinates." and "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."
glLight is called before the camera is set up so it should be consistent in
eye coordinates, i.e. fixed relative to the camera, not the world. This is
certainly true in the GUI gimbal mode. When you rotate around the world the
light is always coming from over your left shoulder.
Both camera modes call gluLookat(), with the same up vector. In gimbal mode
it always looks down the Y axis and then rotates the world. The vector mode
just looks along an arbitrary vector. Since the light positions have been
previously baked into eye coordinates I don't understand how they end up
different in vector mode. They both set up the projection matrix with the
same calls, just slightly different parameters. Yes the gimbal mode then
messes with the MODELVIEW matrix but we can see that doesn't affect the
lighting relative to the camera.
I refactored setupCamera() to use the same code for both cameras:
void GLView::setupCamera()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const bool gimbal = cam.type == Camera::CameraType::GIMBAL;
auto center = gimbal ? Vector3d(0.0,0.0,0.0) :
cam.center;
auto eye = gimbal ? Vector3d(0.0, -cam.zoomValue(), 0.0) : cam.eye;
auto dist = (center - eye).norm();
switch (this->cam.projection) {
case Camera::ProjectionType::PERSPECTIVE: {
gluPerspective(cam.fov, aspectratio, 0.1*dist, 100*dist);
break;
}
case Camera::ProjectionType::ORTHOGONAL: {
auto height = dist * tan(cam.fov/2*M_PI/180);
glOrtho(-height*aspectratio, height*aspectratio,
-height, height,
-100*dist, +100*dist);
break;
}
}
Vector3d dir(eye - center);
Vector3d up(0.0,0.0,1.0);
if (dir.cross(up).norm() < 0.001) { // View direction is ~parallel with
up vector
up << 0.0,1.0,0.0;
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye[0], eye[1], eye[2],
center[0], center[1], center[2],
up[0], up[1], up[2]);
if(gimbal) {
glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
}
}
If the Camera class maintained correct values in object_rot, eye and centre
it wouldn't even need a type. The different modes are just different ways
of setting those properties.
All the test still pass but the GUI now looks the same as the tests, i.e.
lit from below. The difference is the position of glLoadIdentity()relative
to gluLookAt(). I think gluLookAt just sets the model view matrix, so
calling glLoadIdentity after it erases its effect.
So without really understanding the bug I can fix it by unifying the camera
modes. The problem is the lights from below are not ideal. I can probably
change the light setup to make the GUI mode the same as it was, but then
half the tests will fail.
Post by nop headPost by nop headBut the lighting code is already the same for both cameras. I don't
understand why it comes out different. Are the lighting positions relative
to the world or the camera?
The two cameras have slightly different ways of managing OpenGL matrices (
* The gimbal camera sets up the camera parameters in GL_PROJECTION mode,
then resets the MODELVIEW matrix and rotates the scene
* The vector camera set up the camera projection in GL_PROJECTION mode,
then does a gluLookat().
Without looking at this in great detail, Iâd guess that the gimbal mode is
messing with stuff it shouldnât do with the PROJECTION matrix, causing the
lights to have different relative directions in gimbal and vector modes.
Setting up OpenGL cameras and lights using these low-level functions can
be tricky and is error prone...
-Marius
_______________________________________________
OpenSCAD mailing list
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org