I have a camera object in my OpenGL renderer. It works fine. However I need to parent it to a parent node so that the parent can manipulate camera as it is done in Adobe AfterEffects with Null Object. If you are not familiar with AE, so here is how it works. Null Object is an empty container. If the camera is parented to it and the object itself is located at the target position then the camera, having its point of interest (aka lookAt) at the target would orient around the target when null object is rotated. That is the core of the problem.In my implementation, when I rotate the parent, which has the camera as child and is located at target's position, the camera doesn't remain locked at the parent's position but its lookAt direction changes too. Here is the screenshot depicting the issue:
At the left screenshot is the wrong behavior:Camera's parent is at the center but the camera's direction is rotating instead of the camera. At the right screenshot that is how it should be and how it works in AE: rotating the Null Object rotates the camera around the null object center axis. I am sure I do some stupid wrong matrix order thing here. So here is how I do in the code:
I calculate camera's lookAt matrix like this:
public void lookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, Vec3 upPt) {
_eye.set(eyeX, eyeY, eyeZ);
_center.set(centerX, centerY, centerZ);
_up = upPt;
_direction = Vec3.sub(_center, _eye).normalize();
_viewMatr = Glm.lookAt(_eye, _center, _up);
_transform.setModel(Mat4.mul(rotMat, _viewMatr));
///rotMat is rotation matrix cached from rotation method call.
}
The Glm:lookAt is the port from C++ GLM math lib and it looks like this:
public static Mat4 lookAt(Vec3 eye, Vec3 center, Vec3 up) {
Vec3 f = normalize(Vec3.sub(center, eye));
Vec3 u = normalize(up);
Vec3 s = normalize(cross(f, u));
u = cross(s, f);
Mat4 result = new Mat4(1.0f);
result.set(0, 0, s.x);
result.set(1, 0, s.y);
result.set(2, 0, s.z);
result.set(0, 1, u.x);
result.set(1, 1, u.y);
result.set(2, 1, u.z);
result.set(0, 2, -f.x);
result.set(1, 2, -f.y);
result.set(2, 2, -f.z);
return translate(result, new Vec3(-eye.x,-eye.y,-eye.z));
}
So that is the first part , where I create camera "model" matrix.Nex step is create the world matrix taking into account camera's parent node:
Mat4 world= Mat4.mul( this.getTransform().parentMatr, this.getTransform().getModel());
this.getTransform().setView(world);
Later in the pipeline, view matrix of the camera (which I just have set with setView) is accessed by each geometry object which going to be rendered, and model, view, projection matrix is calculated and then sent to vertex shader.
The strange thing is, if I invert world matrix before passing it into setView()
method and don't negate eye vector in GLM, then it works!But in such a case it doesn't work in a mode where the camera is not parented.
Please don't suggest Fixed pipeline based solutions I work with OpenGL 4.0 Core.