Why won't my Quaternion rotate properly?

左心房为你撑大大i 提交于 2019-12-06 07:10:48

问题


Ok, we are not talking about OpenGL with this question, but this will be used with OpenGL ES 2.0.

Question: How do create and rotate a Quaternion with the following code?

I have been reading up and studying about this and still can't quite gasp the concepts. I thought I understood it, but once I started making some calculations to rotate the quaternion I realized I can't even get back to where I started.

So let us say that we have a cube, and the center of it is at (0, 0, 0). We want to rotate it on the x-axis by 45 degrees. What would I do? (Only the Quaternion)

Assuming success, how would you get the amount of rotation from 'W'? I know that '1' indicates that there is no rotation, but what if it was rotated 173 degrees?

Trying to rotate to a given direction, 45 degrees, and then get that value from W. I feel like I need to convert the angle to rads or something, but not exactly sure. Tutorials online vary from one to the next.

Here is my code:

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));
    }
}

Here is the code for a Quaternion:

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:


I'm still not 100% sure what your question is asking, but I'll give it a shot.

Problem:

Given a quaternion representing a 0 degree rotation about x, y, z, generate a new quaternion representing a 45 degree rotation about the x axis

  • Start with a quaternion representing no rotation, call it 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

So q1 = (1, 0, 0, 0)

  • Generate a new rotation that is 45 degrees (PI/4 radians) about the X axis We need a temporary quaternion to modify q1. Let's call it 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

so q2 = (cos(PI/8), sin(PI/8), 0, 0)

  • Now this last step is important, you modify your original quaternion by a left-hand multiplication of the temporary quaternion

What I mean is this:

q1 = q2 * q1

Your multiplication function is written correctly, so the problem is not there. Remember that quaternion multiplications are not commutative. That is q2 * q1 is NOT the same as q1*q2!

At this point q1 is modified to represent a 45 degree rotation about the X axis.

To print out the angle in degrees, you need to compute 2.0 * acos(q1.w) / PI * 180

Your code is incorrectly computing q1.w/PI * 180 to get the angle in degrees.

More specifically, change

toANGLE(resQuat.getW())

to

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

I haven't looked at your code beyond that, but try applying these concepts and see if that fixes your problem.



来源:https://stackoverflow.com/questions/19570957/why-wont-my-quaternion-rotate-properly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!