- Home /
The question is answered, right answer was accepted
Longest distance rotation problem: From -175 to 175 via 0 using Quaternion.RotateTowards stops at 5, why?
I want to rotate object from 175 to -175 along y-axis via 0 (longest path)
The documentation says "The from quaternion is rotated towards to by an angular step of maxDegreesDelta (but note that the rotation will not overshoot). Negative values of maxDegreesDelta will move away from to until the rotation is exactly the opposite direction."
But I just couldn't make it to do what the documentation says about rotating in opposite direction.
I have this test:
using UnityEngine;
using System.Collections;
// test of Quaternion.RotateTowards from 175 to -175 via 0 along y-axis
public class TestRotateTowards : MonoBehaviour
{
public float speed = -10;
void Start ()
{
// set the object at y = 175
transform.Rotate (Vector3.up * 175);
}
void Update ()
{
// then rotate towards -175 via 0 using -speed.
float step = speed * Time.deltaTime;
transform.rotation = Quaternion.RotateTowards (transform.rotation, Quaternion.AngleAxis (-175.0f, Vector3.up), step);
}
}
But the cube jitters when y rotation value is 5 and simply stops there. It never reaches -175, from 175, as I asked it to. Can someone, a quaternion master possibly, shed a light on this?
RotateTowards() and Slerp take the shortest path between two rotations. In general if you want a rotation of more than 180 degrees, you have to go to something like Vector3.RotateTowards().
Answer by Scribe · May 01, 2014 at 01:34 PM
Hi there,
It does seem to be a bug with the function, from what I have tested I'm going to make a guess that unity finds the axis that needs to be rotated around using the cross product of the two direction it can get from the Quaternions you supply, however when the quaternions are the inverse of each other, the vectors they represent are on the same line as one another and so the cross product returns a zero vector rather than one perpendicular to the 2 axses.
The way to fix this therefore is have an alternative way of getting the axis it should be rotating around, unfortunately this means supplying an extra parameter, either then axis to rotate around itself or, as I have done below, required the rotation at the begining. Obviously this will therefore still break if the starting rotation is exactly opposite the end rotation so for this eventuality I have simply assumed you want to rotate around the y axis.
Anyway, this code should work if used on its own, I doubt it will work if other rotations are being applied during its progress:
public float speed = -10;
Quaternion startRotation;
Quaternion targetRotation;
float step;
void Start (){
// set the object at y = 175
transform.rotation = Quaternion.Euler(Vector3.up * 175);
startRotation = transform.rotation;
targetRotation = Quaternion.AngleAxis(-175.0f, Vector3.up);
}
Quaternion RotateTowards(Quaternion currRot, Quaternion startRot, Quaternion targetRot, float step){
Vector3 axis = Vector3.zero;
float angle = 0;
(Quaternion.Inverse(currRot)*targetRot).ToAngleAxis(out angle, out axis);
axis = Vector3.Cross((startRot*Vector3.forward), (targetRot*Vector3.forward)).normalized;
if(axis == Vector3.zero){
axis = Vector3.up;
}
angle = Mathf.Sign(step)*(360-angle);
angle = angle < 0 ? angle+360 : angle;
angle %= 360;
if(angle <= Mathf.Abs(step)){
currRot = targetRot;
return currRot;
}
currRot *= Quaternion.AngleAxis(step, axis);
return currRot;
}
void Update (){
step = speed * Time.deltaTime;
transform.rotation = RotateTowards(transform.rotation, startRotation, targetRotation, step);
}
Hope that helps,
Scribe
Accepted as an answer for your clear insight (educated guess and tested it) into the problem.
Answer by ikelaiah · May 01, 2014 at 10:44 PM
Well, I come up with a rather primitive solution but works. Perhaps someone else have thought of it, but I called it "Aim Half-Way" approach (just invented this a few mins ago). If someone already solved something like this before, please let me know, I'll put a credit here.
The algorithm is like this.
Begin
Find the difference = target angle - target angle.
If the difference > 180, then enter aim half-way mode
Aim Half-way mode:
**Calculate half-way distance = (current + target) 0.5f*
Rotate angle to half-way distance
If the difference of step 2 is still greater than 180, do step 4
Go to final angle destination
End
Follow this Question
Related Questions
Quaternion.RotateTowards is inconsistent 0 Answers
Problem finding relative rotation from one quaternion to another 4 Answers
How can I get the rotation between two objects 1 Answer
Rotate object following mouse movement. Object jumps/ flips 1 Answer
How to make a plane face a static but rotating camera? 3 Answers