Search code examples
javarotationlwjglquaternionsjoml

What is the correct way to rotate a quaternion from its current rotation a certain angle?


I am trying to use quaternion rotation using the quaternion from JOML: https://github.com/JOML-CI/JOML/blob/main/src/org/joml/Quaternionf.java.

I can get objects to rotate but they get stuck and are unable to complete a full rotation. The object is being updated every frame.

Edit: Removed all euler related code and am simply trying to get the object to rotate on a single axis based on a certain angle.

Edit 2: Am trying to use the conjugate and multiplying the quaternions together like I have seen in some videos. I'm not quite there though as the model spins itself off the screen for some reason.

Edit 3: Normalizing the quaternion fixed the disappearing behaviour. The issue seems to be that there's no simple way to rotate a certain amount without either having a timer to lerp over which will not work in my case as I am trying to rotate an object an arbitrary amount with no set beginning and end.

Rotation function

public void rotate(float angle, float x, float y, float z) {
    Quaternionf rot = new Quaternionf();
    rot.rotateAxis((float) Math.toRadians(angle), x, y, z);

    Quaternionf conjugate = rot.conjugate();

    rotation = rot.mul(rotation).mul(conjugate);
}

Calling the rotation function

entity.transform.rotate( 1,0,1, 0);

Solution

  • I believe I have figured it out.

    1. You need to create a quaternion and rotate it to your delta values, do not manipulate quaternion values directly (e.g. use rotationX function instead).

    2. To add quaternions together you multiply them.

    3. Finally you need to use the equation:

      delta quaternion * quaternion to rotate * inverse of delta quaternion

    Code:

        public void rotate(float x, float y, float z) {
            //Use modulus to fix values to below 360 then convert values to radians
            float newX = (float) Math.toRadians(x % 360);
            float newY = (float) Math.toRadians(y % 360);
            float newZ = (float) Math.toRadians(z % 360);
    
            //Create a quaternion with the delta rotation values
            Quaternionf rotationDelta = new Quaternionf();
            rotationDelta.rotationXYZ(newX, newY, newZ);
    
            //Calculate the inverse of the delta quaternion
            Quaternionf conjugate = rotationDelta.conjugate();
    
            //Multiply this transform by the rotation delta quaternion and its inverse
            rotation.mul(rotationDelta).mul(conjugate);
        }