当前位置: 首页 > 知识库问答 >
问题:

来自4x4变换矩阵的意外旋转角度(libgdx)

祁晟
2023-03-14

这是它的要点,你可以看到旋转角度从0-236然后跳119-0,很奇怪。

我想得到一个模型相对于其y轴的角度,单位为度(0-360)。然而,到目前为止,使用libgdx,我无法使用以下方法获得预期结果:

angle = modelInstance.transform.getRotation(new Quaternion()).getAxisAngle(Vector3.Zero)

假设我只围绕y轴旋转,这是从libgdx中的变换矩阵中获取旋转角度的正确方法吗?

我已经包含了一个完整的示例类来证明我从以这种方式获得旋转中获得的角度不是预期的,而不是0-360的完整旋转,我得到类似0-117然后跳到243。

public class RotateExperiment extends InputAdapter implements ApplicationListener {

    private Environment environment;
    private ModelBatch modelBatch;
    private Camera camera;
    private ModelInstance player;

    @Override
    public void create() {
        this.player = new ModelInstance(new ModelBuilder().createCone(10, 10,10, 10, new Material(ColorAttribute.createDiffuse(Color.GRAY)), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal));

        int w = Gdx.graphics.getWidth();
        int h = Gdx.graphics.getHeight();

        modelBatch = new ModelBatch();
        camera = new PerspectiveCamera(67, w, h);
        camera.position.set(10f, 10f, 10f);
        camera.lookAt(0,0,0);
        camera.near = 0.1f;
        camera.far = 300f;
        camera.update();

        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
        environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
    }

    @Override
    public void dispose() {}

    private void updateModel(){
        Vector3 directionVector = new Vector3(0,0,0);
        if(Gdx.input.isKeyPressed(Input.Keys.S)){
            directionVector.z = -1;
        }
        if(Gdx.input.isKeyPressed(Input.Keys.W)){
            directionVector.z = 1;
        }
        if(Gdx.input.isKeyPressed(Input.Keys.A)){
            if(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)){
                directionVector.y = 1;
            } else {
                player.transform.rotate(Vector3.Y, 90 * Gdx.graphics.getDeltaTime());
            }
        }
        if(Gdx.input.isKeyPressed(Input.Keys.D)){
            if(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)){
                directionVector.y = -1;
            } else {
                player.transform.rotate(Vector3.Y, -90 * Gdx.graphics.getDeltaTime());
            }
        }
        if(directionVector.z != 0 || directionVector.y != 0){
            player.transform.translate(directionVector.nor().scl(20 * Gdx.graphics.getDeltaTime()));
        }
    }

    public void update() {
        if(player != null){
            updateModel();
            //update angle text -> actual test code
            outputText.setText(String.valueOf(player.transform.getRotation(new Quaternion()).getAxisAngle(Vector3.Zero)));
        }
    }

    @Override
    public void render() {
        update();
        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        modelBatch.begin(camera);
        modelBatch.render(player, environment);
        modelBatch.end();
    }

    @Override
    public void resize(int width, int height) {
        Gdx.gl.glViewport(0, 0, width, height);
    }

    @Override
    public void pause() {}

    @Override
    public void resume() {}

    private final static JLabel outputText = new JLabel("test");

    public static void main(String[] args) {
        LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
        cfg.title = "TestRotation";
        cfg.useGL20 = true;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        cfg.width = screenSize.width;
        cfg.height = screenSize.height;

        new LwjglApplication(new RotateExperiment(), cfg);

        JFrame outputWindow = new JFrame();
        JPanel outputPanel = new JPanel();

        outputPanel.add(outputText);
        outputWindow.add(outputPanel);
        outputWindow.setAlwaysOnTop(true);
        outputWindow.setVisible(true);
        outputWindow.pack();
        outputWindow.toFront();
    }
}

如果正在运行示例,请在加载libgdx渲染窗口后单击该窗口,可以使用“A”和“D”控制模型旋转。使用上述方法得到的旋转也在单独的JFrame中输出。

编辑:我认为可疑代码可能在libgdx方法中,用于将4x4转换矩阵转换为四元数:Quaternion.setFromAx。当您调用transform.getRotation()时,它会调用setFromAx并传入矩阵轴。我已经看到了悬而未决的问题,但是正如您在示例中看到的,我的立方体模型没有缩放,所以这不可能是正在发生的事情。setFromAx代码如下:

            // the trace is the sum of the diagonal elements; see
    // http://mathworld.wolfram.com/MatrixTrace.html
    final float m00 = xx, m01 = xy, m02 = xz;
    final float m10 = yx, m11 = yy, m12 = yz;
    final float m20 = zx, m21 = zy, m22 = zz;
    final float t = m00 + m11 + m22;

    // we protect the division by s by ensuring that s>=1
    double x, y, z, w;
    if (t >= 0) { // |w| >= .5
        double s = Math.sqrt(t + 1); // |s|>=1 ...
        w = 0.5 * s;
        s = 0.5 / s; // so this division isn't bad
        x = (m21 - m12) * s;
        y = (m02 - m20) * s;
        z = (m10 - m01) * s;
    } else if ((m00 > m11) && (m00 > m22)) {
        double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1
        x = s * 0.5; // |x| >= .5
        s = 0.5 / s;
        y = (m10 + m01) * s;
        z = (m02 + m20) * s;
        w = (m21 - m12) * s;
    } else if (m11 > m22) {
        double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1
        y = s * 0.5; // |y| >= .5
        s = 0.5 / s;
        x = (m10 + m01) * s;
        z = (m21 + m12) * s;
        w = (m02 - m20) * s;
    } else {
        double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1
        z = s * 0.5; // |z| >= .5
        s = 0.5 / s;
        x = (m02 + m20) * s;
        y = (m21 + m12) * s;
        w = (m10 - m01) * s;
    }

    return set((float)x, (float)y, (float)z, (float)w);

共有1个答案

聂溪叠
2023-03-14

因此,假设您有一个非比例模型,并且仅围绕y轴执行旋转,以下代码将仅从libgdx中模型的变换矩阵中获得角度0-360

        Vector3 axisVec = new Vector3();
        int angle = (int) (player.transform.getRotation(new Quaternion()).getAxisAngle(axisVec) * axisVec.nor().y);
        angle = angle < 0 ? angle + 360 : angle; //convert <0 values

如果您有一个缩放模型,根据公开问题,当前的解决方案是规范化setFromAxes代码中的轴,我已将我的setFromAxes替换为以下内容,直到更新为止:

private Quaternion setFromAxes(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz){

    //normalise axis
    Vector3 xAxis = new Vector3(xx, xy, xz).nor();
    Vector3 yAxis = new Vector3(yx, yy, yz).nor();
    Vector3 zAxis = new Vector3(zx, zy, zz).nor();

    xx = xAxis.x;
    xy = xAxis.y;
    xz = xAxis.z;

    yx = yAxis.x;
    yy = yAxis.y;
    yz = yAxis.z;

    zx = zAxis.x;
    zy = zAxis.y;
    zz = zAxis.z;

    // the trace is the sum of the diagonal elements; see
    // http://mathworld.wolfram.com/MatrixTrace.html
    final float m00 = xx, m01 = xy, m02 = xz;
    final float m10 = yx, m11 = yy, m12 = yz;
    final float m20 = zx, m21 = zy, m22 = zz;
    final float t = m00 + m11 + m22;

    // we protect the division by s by ensuring that s>=1
    double x, y, z, w;
    if (t >= 0) { // |w| >= .5
        double s = Math.sqrt(t + 1); // |s|>=1 ...
        w = 0.5 * s;
        s = 0.5 / s; // so this division isn't bad
        x = (m21 - m12) * s;
        y = (m02 - m20) * s;
        z = (m10 - m01) * s;
    } else if ((m00 > m11) && (m00 > m22)) {
        double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1
        x = s * 0.5; // |x| >= .5
        s = 0.5 / s;
        y = (m10 + m01) * s;
        z = (m02 + m20) * s;
        w = (m21 - m12) * s;
    } else if (m11 > m22) {
        double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1
        y = s * 0.5; // |y| >= .5
        s = 0.5 / s;
        x = (m10 + m01) * s;
        z = (m21 + m12) * s;
        w = (m02 - m20) * s;
    } else {
        double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1
        z = s * 0.5; // |z| >= .5
        s = 0.5 / s;
        x = (m02 + m20) * s;
        y = (m21 + m12) * s;
        w = (m10 - m01) * s;
    }

    return new Quaternion((float)x, (float)y, (float)z, (float)w);

}
 类似资料:
  • 问题内容: 我有一个具有这样的值的变换矩阵。 分别转换:xx,xy,yx,yy,tx和ty。 如何从上述给定值集中找到角度。 问题答案: 如果仅关于旋转,则可以使用给定的矩阵对向量(1,0)进行变换,并计算所得向量与x轴之间的角度,如原始问题的注释中已经提到的那样。

  • 假设我使用大小为8的字符数组来表示图像的碰撞掩码。字符的每一位代表一个像素。实际上,对于64x64矩阵,我将使用长[64]阵列。 因此,框将显示为: 45度的示例输出应该是这样的,尽管旋转可以是任何角度。这个形状对于45度旋转可能不准确,因为我是用手做的。 另一个例子是向右旋转10度?这些值可能是错误的,因为从数学上讲,我不知道它将如何精确旋转,但我认为可以安全地假设,如果每个位的覆盖率超过旧形状

  • 变换矩阵 之前三节所说的坐标变换的三种方式——平移translate(),缩放scale(),以及旋转rotate()都可以通过transform()做到。 在介绍矩阵变换transform()前,我们来说一说什么是变换矩阵。 以上是Canvas中transform()方法所对应的变换矩阵。而此方法正是传入图中所示的六个参数,具体为context.transform(a,b,c,d,e,f)。 各

  • 我试图使用霍夫变换找到图像的旋转角度。首先,我使用精明的边缘检测器检测边缘,然后我应用霍夫变换。之后,对于每个θ,我对θ上的线条长度进行求和,并找到theta.then的直方图,我将其“旋转”并找到匹配项。例如,如果我需要移动5次,原始图像和旋转图像相差5度。问题是,例如,这种方法在180和0之间没有差异。然而,这是合乎逻辑的,因为霍夫给出的θ仅在-90和90之间。现在我如何识别旋转角度是0还是1

  • 我正在尝试使用Surfaceview和canvas drawing在Android中创建自定义组件。这些组件可以通过触摸来调整大小和旋转。考虑创建一个图像视图,它的上、右、下和左边缘可通过触摸和拖动所需的边缘来缩放。我使用< code>RectF来保持组件的边界,对于旋转,我使用< code>canvas.rotate(angle,bounds.centerX()、bounds.centerY()

  • 我刚开始使用JavaFX,有一个问题。在我的项目中,我想使用旋转矩形。但矩形只围绕其中心旋转,我希望它围绕其左上角旋转。 就像这张照片(从这里开始): 下面是我的项目中的一些代码: 在这种情况下,如果按下箭头键,矩形会旋转。