'Determining if quarternion rotation is clockwise or counter clockwise

I am using the following code to handle rotating my player model to the position of my mouse.

void Update() {
    // Generate a plane that intersects the transform's position with an upwards normal.
    Plane playerPlane = new Plane(Vector3.up, transform.position);

    // Generate a ray from the cursor position
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

    // Determine the point where the cursor ray intersects the plane.
    // This will be the point that the object must look towards to be looking at the mouse.
    // Raycasting to a Plane object only gives us a distance, so we'll have to take the distance,
    // then find the point along that ray that meets that distance. This will be the point
    // to look at.
    float hitdist = 0f;
    // If the ray is parallel to the plane, Raycast will return false.
    if (playerPlane.Raycast(ray, out hitdist)) {
        // Get the point along the ray that hits the calculated distance.
        var targetPoint = ray.GetPoint(hitdist);

        // Determine the target rotation. This is the rotation if the transform looks at the target point.
        Quaternion targetRotation = Quaternion.LookRotation(targetPoint - transform.position);


        // Smoothly rotate towards the target point.
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime); // WITH SPEED
        //transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 1); // WITHOUT SPEED!!!
    }

I would like to be able to determine if the rotation is clockwise or counter-clockwise for animation purposes. What would be the best way of handling this? I'm fairly unfamiliar with quaternions so I'm not really sure how to approach this.



Solution 1:[1]

Angles between quaternions are unsigned. You will always get the shortest distance, and there's no way of defining "counter-clockwise" or "clockwise" unless you actively specify an axis (a point of view).

What you CAN do, however, is to take the axis that you're interested in (I assume it's the normal to your base plane.. perhaps the vertical of your world?) and take the flat 2D components of your quaternions, map them there and compute a simple 2D angle between those.

Quaternion A; //first Quaternion - this is your desired rotation Quaternion B; //second Quaternion - this is your current rotation

// define an axis, usually just up Vector3 axis = new Vector3(0.0f, 1.0f, 0.0f);

// mock rotate the axis with each quaternion Vector3 vecA = A * axis; Vector3 vecB = B * axis;

// now we need to compute the actual 2D rotation projections on the base plane float angleA = Mathf.Atan2(vecA.x, vecA.z) * Mathf.Rad2Deg; float angleB = Mathf.Atan2(vecB.x, vecB.z) * Mathf.Rad2Deg;

// get the signed difference in these angles var angleDiff = Mathf.DeltaAngle( angleA, angleB );

This should be it. I never had to do it myself and the code above is not tested. Similar to: http://answers.unity3d.com/questions/26783/how-to-get-the-signed-angle-between-two-quaternion.html

This should work even if A or B are not Quaternions, but one of them is an euler-angle rotation.

Solution 2:[2]

Two dimensional quaternions (complex numbers) have a signed angle. But, the more correct way to think about complex numbers is with an unsigned angle which is relative to either the XY oriented plane or the YX oriented plane. I.E. a combination of an unsigned angle an an oriented plane of rotation.

In 2D there are only two oriented planes of rotation so the idea of a "signed angle" is really just a trick to get both the unsigned angle and the oriented plane of rotation packed into a single number.

For a quaternion the "signed angle" trick cannot be used because in 3D you have an infinite number of oriented planes you can rotate in, so a single signed angle cannot encode all the rotation information like it can in the 2D case.

The only way for a signed angle to make sense in 3D is with reference to a particular oriented plane, such as the XY oriented plane.

-- UPDATE --

This is pretty easy to solve as a method on a quaternion class. If all you want to know is "is this counter clockwise", then since we know the rotation angle is from 0 to 180, a positive dot product between the quat's axis of rotation and the surface normal should indicate that we're rotating counter clockwise from the perspective of that surface. And a negative dot product indicates the opposite. Ignoring the zero case, this should do the trick with much less work:

public bool IsCounterClockwise( in Vector3 normal ) => I*normal.X + J*normal.Y + K*normal.Z >= 0;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2