【问题标题】:LWJGL 3 - Model rotating around wrong axisLWJGL 3 - 模型围绕错误的轴旋转
【发布时间】:2017-10-30 20:15:51
【问题描述】:

我的 3D 模型围绕错误的轴旋转。除了 X 轴之外的所有东西都可以工作。当我将 Y 和 Z 的角度设置为 0 时,X 工作正常,但如果旋转它,例如。绕 Z 轴 90 度并绕 X 旋转,然后它也绕 Z 旋转。所以当使用 Y 或 Z 时,X 围绕 Z 旋转。所以如果我让我的模型围绕 Z 旋转 90 度并围绕 X 旋转 -90 度,它会完全保持静止。

我的转换矩阵函数。如果我将matrix.translate(position); 移动到旋转下,我的模型会旋转一个大圆圈(可能围绕世界原点)。

public static Matrix4f createTransformationMatrix(Vector3f position, Vector3f rotation, Vector3f scale) {

    Matrix4f matrix = new Matrix4f();

    matrix.scale(scale);

    matrix.translate(position);

    matrix.rotate((float) Math.toRadians(rotation.x), new Vector3f(1, 0, 0));
    matrix.rotate((float) Math.toRadians(rotation.y), new Vector3f(0, 1, 0));
    matrix.rotate((float) Math.toRadians(rotation.z), new Vector3f(0, 0, 1));

    return matrix;
}

将矩阵转换为浮点缓冲区,以便我可以将其传递给着色器:

public static FloatBuffer toFloatBuffer(Matrix4f matrix) {

    FloatBuffer buffer = BufferUtils.createFloatBuffer(16);

    buffer.put(matrix.m00());
    buffer.put(matrix.m01());
    buffer.put(matrix.m02());
    buffer.put(matrix.m03());
    buffer.put(matrix.m10());
    buffer.put(matrix.m11());
    buffer.put(matrix.m12());
    buffer.put(matrix.m13());
    buffer.put(matrix.m20());
    buffer.put(matrix.m21());
    buffer.put(matrix.m22());
    buffer.put(matrix.m23());
    buffer.put(matrix.m30());
    buffer.put(matrix.m31());
    buffer.put(matrix.m32());
    buffer.put(matrix.m33());

    buffer.flip();

    return buffer;
}

在着色器中的使用:

gl_Position = transformationMatrix * vec4(position, 1.0) * viewMatrix * projectionMatrix;

模型的零点已设置为其原点,我确信发送到这些函数的所有数据都是正确的。我已经调试了一段时间了。我正在使用 LWJGL 3。

【问题讨论】:

  • 如果组合旋转,则在第一次平移后在坐标系中应用第二次旋转。示例:如果围绕 X 旋转 90 度,则局部 Y 轴将沿全局 Z 轴指向,依此类推。
  • 不相关,但着色器中的转换顺序看起来错误。除非视图和投影被转置,否则从右侧将它们相乘是没有意义的。
  • @Rabbid76 仍然无法解决我的问题 –
  • @Rabbid76 我真的不明白你的意思,但你不能看看上面的代码。输入向量旋转仅包含度数 (0-360)。我认为这是因为 Y 旋转输入为 90 而有人回答的 Gimbal Lock。我只是不知道如何修复它。
  • @Rabbid76 必须有其他人使用的解决方案

标签: opengl matrix rotation lwjgl


【解决方案1】:

我认为你面对的是Gimbal Lock。 这意味着,应用旋转的顺序很重要,然后您可能会得到奇怪的结果,例如您所经历的结果。

要解决这个问题,你必须使用Quaternions

基本上,你必须:

  • 创建旋转四元数并将它们与其他旋转四元数相乘。
  • 您必须创建一个表示 X 轴旋转的旋转四元数,以此类推表示 Y 轴和 Z 轴

  • 你把它们相乘

  • 最后,您必须将生成的四元数转换为矩阵。

在此处阅读有关how to implement Rotation Quaternions in OpenGL 的信息?

编辑:

在此处阅读有关如何将四元数转换为矩阵的信息:Convert Quaternion rotation to rotation matrix?

这是我的 Camera 类(不幸的是,它使用像 Quaternion 这样的 JOGL 库,但应该可以移植到 LWJGL。它以 Euler 或 Quaternion 方式提供围绕中心的缩放、移动、旋转,以及检索指向方向等的方法。

public class Camera {
    public Matrix4 matrix;
    public Quaternion rotation;
    public Vector3 position;
    public Vector3 scale;
    public Vector3 center;
    public Vector2 frictionx;
    public Vector2 frictiony;
    public Vector2 frictionz;
    public Camera() {
        matrix=new Matrix4();
        rotation=new Quaternion();
        position=new Vector3(0f,0f,0f);
        scale=new Vector3(1f,1f,1f);
        center=new Vector3(0f,0f,0f);
        frictionx=new Vector2(0,0);
        frictiony=new Vector2(0,0);
        frictionz=new Vector2(0,0);
    }
    public float tryFric(float a, float b) {
        try {
            float r=a/b;
            if (r == Float.NaN) {
                return 0;
            }
            return r;
        }
        catch (Exception e) {
            return 0;
        }
    }
    public void getFrictions(Vector3 pointing) {
        frictionx.x=tryFric(pointing.y,pointing.x);
        frictionx.y=tryFric(pointing.z,pointing.x);
        frictiony.x=tryFric(pointing.x,pointing.y);
        frictiony.y=tryFric(pointing.z,pointing.y);
        frictionz.x=tryFric(pointing.x,pointing.z);
        frictionz.y=tryFric(pointing.y,pointing.z);
    }
    public Vector3 getPointing(Vector3 vec) {
        float[] in=new float[] {vec.x,vec.y,vec.z};
        float[] out=new float[3];
        rotation.conjugate();
        rotation.rotateVector(out, 0, in, 0);
        rotation.conjugate();
        Vector3 p=new Vector3(out[0],out[1],out[2]);
        getFrictions(p);
        return p;
    }
    public void move(float x, float y, float z) {
        position.x+=x;
        position.y+=y;
        position.z+=z;
    }
    public void setPosition(float x, float y, float z) {
        position.x=x;
        position.y=y;
        position.z=z;
    }
    public void moveCenter(float x, float y, float z) {
        center.x+=x;
        center.y+=y;
        center.z+=z;
    }
    public void setCenter(float x, float y, float z) {
        center.x=x;
        center.y=y;
        center.z=z;
    }
    public void scale(float x, float y, float z) {
        scale.x*=x;
        scale.y*=y;
        scale.z*=z;
    }
    public void setScale(float x, float y, float z) {
        scale.x=x;
        scale.y=y;
        scale.z=z;
    }
    public void rotateQuaternion(float angle, float x, float y, float z) {
        Quaternion rotationy=new Quaternion();
        rotationy.rotateByAngleY(angle*y);
        rotation.mult(rotationy);
        Quaternion rotationx=new Quaternion();
        rotationx.rotateByAngleX(angle*x);
        rotation.mult(rotationx);
        Quaternion rotationz=new Quaternion();
        rotationz.rotateByAngleZ(angle*z);
        rotation.mult(rotationz);
        rotation.normalize();
    }
    public void rotateEuler(float angle, float x, float y, float z) {
        rotation.rotateByEuler(angle*x, angle*y, angle*z);
    }
    public Vector3 getPointing() {
        Matrix4 as_matrix=new Matrix4();
        as_matrix.loadIdentity();
        as_matrix.rotate(rotation);
        float[] out=new float[3];
        float[] in=new float[] {0,0,-1};
        as_matrix.multVec(in, out);
        Vector3 pointing=new Vector3(out[0],out[1],out[2]);
        return pointing;
    }
    public Matrix4 getMatrix() {
        Matrix4 rot_as_mat=new Matrix4();
        rot_as_mat.loadIdentity();
        rot_as_mat.translate(center.x, center.y, center.z);
        rot_as_mat.rotate(rotation);
        Matrix4 result=new Matrix4();
        result.loadIdentity();
        result.scale(scale.x, scale.y, scale.z);
        result.multMatrix(rot_as_mat);
        result.translate(position.x,position.y,position.z);
        matrix=result;
        return result;
    }
}

希望对你有帮助!

注意:

  • 您可能需要尝试旋转四元数乘法顺序以获得不同的结果

【讨论】:

  • 我仍然看不出有什么区别。我应该如何将生成的四元数转换为矩阵?
  • @Maineri:看看这个:stackoverflow.com/questions/1556260/…
  • @user7185317 仍然不起作用..我可以只使用 quaternionRotationX.rotateX(xRotInRadians) 等.. 或者我应该如何创建旋转四元数?
  • @Maineri :是的,应该是对的。不幸的是,我使用的是 jogl,但我在帖子中粘贴了相关代码。
  • 我很难理解这一点。摩擦在这意味着什么?以及如何以最简单的方式旋转我的模型矩阵?调用什么函数?像那样旋转欧拉。我应该输入什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
  • 2022-01-24
  • 2017-02-10
  • 2019-10-18
  • 2015-06-15
  • 1970-01-01
相关资源
最近更新 更多