我的 OpenGL 渲染器中有一个相机对象。它工作正常。但是,我需要将其作为父节点的父节点,以便父节点可以像在 Adobe AfterEffects 中使用 Null 对象那样操作相机。如果您不熟悉 AE,那么这里是它的工作原理。Null Object 是一个空容器。如果相机是它的父对象并且对象本身位于目标位置,那么当空对象旋转时,在目标上具有其兴趣点(又名lookAt)的相机将围绕目标定向。这是问题的核心。在我的实现中,当我旋转将相机作为子相机并位于目标位置的父级时,相机不会保持锁定在父级的位置,但它的外观方向也会发生变化。这是描述该问题的屏幕截图:
左边的截图是错误的行为:相机的父级在中心,但相机的方向是旋转而不是相机。在右侧的屏幕截图中,它应该是这样以及它在 AE 中的工作方式:旋转 Null 对象会围绕空对象中心轴旋转相机。我确信我在这里做了一些愚蠢的错误矩阵顺序的事情。所以这是我在代码中的做法:
我像这样计算相机的lookAt矩阵:
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.
}
Glm:lookAt 是来自 C++ GLM 数学库的端口,它看起来像这样:
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));
}
这是第一部分,我在其中创建相机“模型”矩阵。下一步是创建世界矩阵,同时考虑到相机的父节点:
Mat4 world= Mat4.mul( this.getTransform().parentMatr, this.getTransform().getModel());
this.getTransform().setView(world);
稍后在管道中,每个将要渲染的几何对象访问相机的视图矩阵(我刚刚使用 setView 设置),并计算模型、视图、投影矩阵,然后将其发送到顶点着色器。
奇怪的是,如果我在将世界矩阵传递给setView()
方法之前反转世界矩阵并且不否定 GLM 中的眼睛矢量,那么它可以工作!但在这种情况下,它在相机没有父级的模式下不起作用。请不要建议我使用 OpenGL 4.0 Core 的基于固定管道的解决方案。