对于 LWJGL,我一直在努力实现带有 GLU.lookat() 之类的旋转的相机,就像您在 Blender 或 Maya 等程序中找到的一样。一位队友设置了一个基本的 LWJGL 项目,其中有一个可用的第一人称相机:以下代码允许我们在 3D 空间的所有 6 个方向上移动,以及拖动鼠标旋转屏幕。当屏幕旋转时,z 轴(向前-向后)会相应更新,保持向前、向后等到相机的视角。
这里是标准的Camera类,供参考:
import org.joml.*;
import java.lang.Math;
public class Camera {
private Vector3f direction;
private Vector3f position;
private Vector3f right;
private Vector2f rotation;
private Vector3f up;
private Matrix4f viewMatrix;
public Camera() {
direction = new Vector3f();
right = new Vector3f();
up = new Vector3f();
position = new Vector3f();
viewMatrix = new Matrix4f();
rotation = new Vector2f();
pivot = new Vector3f();
}
public void addRotation(float x, float y) {
rotation.add(x, y);
recalculate();
}
public Vector3f getPosition() {
return position;
}
public Matrix4f getViewMatrix() {
return viewMatrix;
}
public void moveBackwards(float inc) {
viewMatrix.positiveZ(direction).negate().mul(inc);
position.sub(direction);
recalculate();
}
public void moveDown(float inc) {
viewMatrix.positiveY(up).mul(inc);
position.sub(up);
recalculate();
}
public void moveForward(float inc) {
viewMatrix.positiveZ(direction).negate().mul(inc);
position.add(direction);
recalculate();
}
public void moveLeft(float inc) {
viewMatrix.positiveX(right).mul(inc);
position.sub(right);
recalculate();
}
public void moveRight(float inc) {
viewMatrix.positiveX(right).mul(inc);
position.add(right);
recalculate();
}
public void moveUp(float inc) {
viewMatrix.positiveY(up).mul(inc);
position.add(up);
recalculate();
}
private void recalculate() {
viewMatrix.identity()
.rotateX(rotation.x)
.rotateY(rotation.y)
.translate(-position.x, -position.y, -position.z);
}
public void setPosition(float x, float y, float z) {
position.set(x, y, z);
recalculate();
}
public void setRotation(float x, float y) {
rotation.set(x, y);
recalculate();
}
}
为了实现围绕枢轴的旋转,我在 Camera 类中添加了一个枢轴点作为实例变量,并相应地更新它:
public void moveUp(float inc) {
viewMatrix.positiveY(up).mul(inc);
position.add(up);
pivot.add(up);
recalculate();
}
这对所有“移动”功能都是一样的。在旋转功能中,我采取了以下步骤:
首先,我用旋转矩阵做了这个,手动进行矩阵手动乘法,但我的旋转都很奇怪。因此,我采用了一种更简单的方法,以下示例仅限于 XZ 平面上的旋转:
public void addRotation(float x /* This variable is not yet used */, float y) {
Vector3f originVec = new Vector3f(position.x(), position.y(), position.z()).sub(pivot);
Vector3f oldOrg = new Vector3f(originVec.x(), originVec.y(), originVec.z());
originVec.rotateY(y);
// Move delta z forward
viewMatrix.positiveZ(direction).negate().mul(originVec.z() - oldOrg.z());
position.add(direction);
// Move delta x to the right
viewMatrix.positiveX(right).mul(originVec.x() - oldOrg.x());
position.add(right);
recalculate();
System.out.println("Origin vector: " + originVec);
// By setting x to 0, we are only rotating on 1 2-dimensional plane.
x = 0;
rotation.add(x, y);
recalculate();
}
然而,这根本不会导致正确的轮换;甚至不可能进行 360 度转弯,因为位置 x 和 y 会慢慢变大。
需要注意的是,轴在旋转后随相机一起旋转,这意味着在枢轴旋转发生后,向量originVec在下次调用时仍然是相同的值。
我真的很想听听您对我们可能做错了什么计算导致这种行为的想法。经过几个小时的研究,我们得出结论,我们不明白为什么枢轴旋转不起作用。我们的数学有问题吗?