Почему мой кватернион не вращается должным образом?

Хорошо, мы не говорим об OpenGL с этим вопросом, но это будет использоваться с OpenGL ES 2.0.

Вопрос: Как создать и повернуть кватернион с помощью следующего кода?

Я читал и изучал об этом и до сих пор не могу задохнуться от концепций. Я думал, что понял это, но как только я начал делать некоторые вычисления, чтобы повернуть кватернион, я понял, что даже не могу вернуться к тому, с чего начал.

Итак, допустим, что у нас есть куб, и его центр находится в точке (0, 0, 0). Мы хотим повернуть его по оси X на 45 градусов. Что бы я сделал? (Только кватернион)

В случае успеха, как бы вы получили количество вращения от "W"? Я знаю, что "1" означает, что вращения нет, но что, если он повернулся на 173 градуса?

Пытаясь повернуть в заданном направлении, 45 градусов, а затем получить это значение от W. Я чувствую, что мне нужно преобразовать угол в радиусы или что-то, но не совсем уверен. Уроки онлайн варьируются от одного к другому.

Вот мой код:

import java.util.Scanner;
import Quaternion;

public class Main {

    public static void main(String[] args) {
        Quaternion q1 = new Quaternion(0, 0, 0, 1);
        Quaternion q2 = new Quaternion(0, 0, 0, (float) Math.cos(toRAD(45.0f) / 2));

        q1 = q2.mul(q1);

        System.out.println("q1: " + q1.getX() + ", " + q1.getY() + ", " + q1.getZ() + " with " + toANGLE(2.0f * Math.acos(q1.getW())));
    }

    private static double toRAD(float angle) {
        return angle * (Math.PI / 180.0f);
    }

    private static float toANGLE(double rad) {
        return (float) (rad * (180.0f / Math.PI));
    }
}

Вот код для кватерниона:

public class Quaternion  // Credit goes to 'thebennybox' (http://www.youtube.com/user/thebennybox)
{
        private float x;
        private float y;
        private float z;
        private float w;

        public Quaternion(float x, float y, float z, float w)
        {
                this.x = x;
                this.y = y;
                this.z = z;
                this.w = w;
        }

        public float length()
        {
                return (float)Math.sqrt(x * x + y * y + z * z + w * w);
        }

        public Quaternion normalize()
        {
                float length = length();

                return new Quaternion(x / length, y / length, z / length, w / length);
        }

        public Quaternion conjugate()
        {
                return new Quaternion(-x, -y, -z, w);
        }

        public Quaternion mul(Quaternion r)
        {
                float w_ = w * r.getW() - x * r.getX() - y * r.getY() - z * r.getZ();
                float x_ = x * r.getW() + w * r.getX() + y * r.getZ() - z * r.getY();
                float y_ = y * r.getW() + w * r.getY() + z * r.getX() - x * r.getZ();
                float z_ = z * r.getW() + w * r.getZ() + x * r.getY() - y * r.getX();

                return new Quaternion(x_, y_, z_, w_);
        }

        public Quaternion mul(Vector3f r)
        {
                float w_ = -x * r.getX() - y * r.getY() - z * r.getZ();
                float x_ =  w * r.getX() + y * r.getZ() - z * r.getY();
                float y_ =  w * r.getY() + z * r.getX() - x * r.getZ();
                float z_ =  w * r.getZ() + x * r.getY() - y * r.getX();

                return new Quaternion(x_, y_, z_, w_);
        }

        public float getX()
        {
                return x;
        }

        public void setX(float x)
        {
                this.x = x;
        }

        public float getY()
        {
                return y;
        }

        public void setY(float y)
        {
                this.y = y;
        }

        public float getZ()
        {
                return z;
        }

        public void setZ(float z)
        {
                this.z = z;
        }

        public float getW()
        {
                return w;
        }

        public void setW(float w)
        {
                this.w = w;
        }
}

1 ответ

Решение

Я все еще не уверен на 100%, что задает твой вопрос, но я попробую.

Проблема:

Для заданного кватерниона, представляющего поворот на 0 градусов вокруг x, y, z, создайте новый кватернион, представляющий поворот на 45 градусов вокруг оси x

  • Начните с кватерниона, представляющего отсутствие вращения, назовите его q1

q1 = (w1, x1, y1, z1)

q1.w1 = cos (0/2) = 1

q1.x1 = 0 * sin (0/2) = 0

q1.y1 = 0 * sin (0/2) = 0

q1.z1 = 0 * sin (0/2) = 0

Так что q1 = (1, 0, 0, 0)

  • Создайте новый поворот на 45 градусов (PI/4 радиана) вокруг оси X. Нам нужен временный кватернион, чтобы изменить q1. Давайте назовем это q2.

q2 = (w2, x2, y2, z2)

q2.w2 = cos (PI/4/2) = cos (PI / 8)

q2.x2 = 1,0 * sin(PI/4 / 2) = 1,0 * sin (PI / 8) = sin (PI / 8)

q2.y2 = 0.0 * sin (PI/4/2) = 0.0

q2.z2 = 0.0 * sin (PI/4/2) = 0.0

поэтому q2 = (cos(PI/8), sin(PI/8), 0, 0)

  • Теперь этот последний шаг важен, вы модифицируете свой исходный кватернион путем левого умножения временного кватерниона.

Я имею в виду следующее:

q1 = q2 * q1

Ваша функция умножения написана правильно, поэтому проблема не в этом. Помните, что кватернионные умножения не являются коммутативными. То есть q2 * q1 - это НЕ то же самое, что q1*q2!

В этот момент q1 изменяется для представления поворота на 45 градусов вокруг оси X.

Чтобы распечатать угол в градусах, нужно вычислить 2.0 * acos(q1.w) / PI * 180

Ваш код неправильно вычисляется q1.w/PI * 180 чтобы получить угол в градусах.

Более конкретно, изменить

toANGLE(resQuat.getW())

в

toANGLE(2.0f * Math.acos(resQuat.getW()))

Я не рассматривал ваш код за пределами этого, но попробуйте применить эти концепции и посмотреть, решит ли это вашу проблему.

Другие вопросы по тегам