LWJGL 围绕枢轴旋转相机

问题描述 投票:0回答:0

对于 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();
}

这对所有“移动”功能都是一样的。在旋转功能中,我采取了以下步骤:

  1. 计算从枢轴点到相机的方向向量。
  2. 根据角度输入 x 和 y 旋转方向向量。
  3. 方向向量的新值减去旧值,得到delta x和delta y。

首先,我用旋转矩阵做了这个,手动进行矩阵手动乘法,但我的旋转都很奇怪。因此,我采用了一种更简单的方法,以下示例仅限于 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在下次调用时仍然是相同的值。

我真的很想听听您对我们可能做错了什么计算导致这种行为的想法。经过几个小时的研究,我们得出结论,我们不明白为什么枢轴旋转不起作用。我们的数学有问题吗?

opengl linear-algebra lwjgl joml
© www.soinside.com 2019 - 2024. All rights reserved.