代码之家  ›  专栏  ›  技术社区  ›  Kris Rice

两个方向的3D旋转?

  •  6
  • Kris Rice  · 技术社区  · 6 年前

    背景

    getTransformationMatrix() 返回一个 Matrix4f ,然后将其传递到实体着色器中。

    问题

    模型需要指向摄影机的方向,并围绕摄影机旋转,使其始终位于前方。这种情况下的物体是手持枪的手,如下图所示。

    enter image description here

    我知道基本的三角学,所以我让物体分别正确地旋转俯仰和偏航。这是我当前的实现:

    偏航

    @Override
    public Matrix4f getTransformationMatrix() {
        modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
        modelZ = getPosition().z + (radius * (float)Math.cos(Math.toRadians(getYaw())));
    
        return Transform.createTransformationMatrix(new Vector3f(modelX, getPosition().y - 5, modelZ), new Vector3f(0, getYaw(), 0), getScale());
    }
    

    @Override
    public Matrix4f getTransformationMatrix() {
        modelZ = getPosition().z + (radius * (float)Math.sin(Math.toRadians(getPitch())));
        modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
    
        return Transform.createTransformationMatrix(new Vector3f(getPosition().x, modelY, modelZ), new Vector3f(getPitch(), 0, 0), getScale());
    }
    

    我做了一些研究,但我担心我在这方面停留太久了,需要一些新的眼光。当我尝试结合这两种计算时,当查看除0以外的任何偏航角时,模型似乎以图形的形式移动。以下是我尝试将这些结合起来:

    @Override
    public Matrix4f getTransformationMatrix() {
        float zAxis = (radius * (float)Math.sin(Math.toRadians(getPitch())));
        modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
        modelZ = getPosition().z + (zAxis * (float)Math.cos(Math.toRadians(getYaw())));
        modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
    
        return Transform.createTransformationMatrix(new Vector3f(modelX, modelY, modelZ), new Vector3f(getPitch(), getYaw(), 0), getScale());
    }
    

    这个 Transform.createTransformationMatrix() 如下所示:

    public static Matrix4f createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale) {
        transform3d = new Matrix4f();
        transform3d.setIdentity();
        Matrix4f.translate(translation, transform3d, transform3d);
        Matrix4f.rotate((float) Math.toRadians(rotation.x), new Vector3f(1, 0, 0), transform3d, transform3d);
        Matrix4f.rotate((float) Math.toRadians(rotation.y), new Vector3f(0, 1, 0), transform3d, transform3d);
        Matrix4f.rotate((float) Math.toRadians(rotation.z), new Vector3f(0, 0, 1), transform3d, transform3d);
        Matrix4f.scale(scale, transform3d, transform3d);
        return transform3d;
    }
    

    一位朋友建议创建一个指向上方向的单位向量。 new Vector3f(0, 1, 0) )通过俯仰和偏航旋转矢量,然后将矢量乘以半径并将其添加到相机的位置。我试过了,但我不知道如何将向量旋转一个角度,而且似乎没有 Vector3f.rotate()

    1 回复  |  直到 6 年前
        1
  •  3
  •   Coronel Kittycannon    6 年前

    我们通常做的是,是的,取一个单位长度的向量,并用它作为我们的“轴”。在2D旋转中,我们始终使用一个轴——Z轴。

    3D rotation

    2D rotation

    因此,要在3D中旋转点,可以使用矩阵或向量。我建议首先使用矢量,这样您就可以了解3D旋转的工作原理。这让你大吃一惊!

    我将从BennyBox中的Vector3f类中删除代码。如果你对这门数学感兴趣,可以在Youtube上查看BennyBox。

        public Vector3F rotate(float angle, Vector3F axis) {
        double a = Math.toRadians(angle / 2f);
        float hs = (float) Math.sin(a);
        float hc = (float) Math.cos(a);
        Vector4F r = new Vector4F(axis.getX() * hs, axis.getY() * hs, axis.getZ() * hs, hc);
        Vector4F rc = r.conjugate();
        r = r.multiplyAsQuat(this).multiplyAsQuat(rc);
    
        return new Vector3F(r.getX(), r.getY(), r.getZ());
        }
    

    向量4f

        public Vector4F multiplyAsQuat(Vector3F v) {
        float o = -x * v.getX() - y * v.getY() - z * v.getZ();
        float a = w * v.getX() + y * v.getZ() - z * v.getY();
        float b = w * v.getY() + z * v.getX() - x * v.getZ();
        float c = w * v.getZ() + x * v.getY() - y * v.getX();
    
        return new Vector4F(a, b, c, o);
    }
    
        public Vector4F conjugate() {
        return new Vector4F(-x, -y, -z, w);
    }
    
        public Vector4F multiplyAsQuat(Vector4F qt) {
    
        float o = w * qt.getW() - x * qt.getX() - y * qt.getY() - z * qt.getZ();
        float a = x * qt.getW() + w * qt.getX() + y * qt.getZ() - z * qt.getY();
        float b = y * qt.getW() + w * qt.getY() + z * qt.getX() - x * qt.getZ();
        float c = z * qt.getW() + w * qt.getZ() + x * qt.getY() - y * qt.getX();
    
        return new Vector4F(a, b, c, o);
    }