6

My problem is I want to be able to rotate a cylinder 9 times. 360/9 is 40 so I all I should need to do is rotate by 40 degrees 9 times. This doesn’t work however as when I rotate the cylinder for the first time instead of by 40 degrees it rotates by 39.99 degrees. This happens at other rotations as well.

I’m rotating by doing this.

if(Input.GetKeyUp("i"))
      transform.GetChild(m_Section).Rotate(0,40.0f,0);

I have unity version 3.4 it is not pro and I’m coding in C#.

Any help appreciated as I have just started trying to learn unity.

2 Answers 2

1

Unity3D stores rotations in a pretty abstract mathematical representation called quaternion. Tranformation from and to Euler angles (what you see in Unity editor) involves a cascade of trigonometric functions and thus is prone to rounding errors especially for the simple float type.

To get around this problem in your case I recommend storing the initial Quaternion object before starting to rotate and set it at the end of the process. Some pseudo-code:

public class RotationController : MonoBehaviour {
    Quaternion rotationAtStart;
    int numOfRotations = 0;

    void rotate () {
        numOfRotations++;
        if (numOfRotations == 1) {
            rotationAtStart = transform.rotation;
        } else if (numOfRotations < 9) {
            transform.Rotate (new Vector3 (0,40.0f,0));
        } else if (numOfRotations == 9) {
            transform.rotation = rotationAtStart;
        }
    }
    void Update () {
        if (numOfRotations < 9) {
            rotate ();
        }
    }
 }   

The special situation of 360° makes this approach stable. For less than 360° you have to live with small rounding errors. For this case I would recommend calculating the target quaternion Quaternion.RotateTowards and set it in the last step analog to the 360 case.

Another useful thing for you are Animations. You can define an animation as smooth or in discrete steps and just call GameObject.animation.Play("MyRotation") if "i" is pressed. Use an AnimationEvent at the end to get informed when the animation is terminated.

And at last Mathf contains a function Approximately that deals with the problem of floating point imprecision.

Sign up to request clarification or add additional context in comments.

3 Comments

If I used an animation like you suggested would that change the objects local axis or would it only rotate the object?
You animate members of the game object's transform. transform.rotation is in Euler angles
Thanks for your help. It's more of a way of side stepping the problem than a fix though. I wouldn't be able to say if(transform.eulerAngles.y == 40.0f) because even though rotate towards gives a more accurate result there are still errors. I haven't tried the animation suggestion yet but I will give it a go just now.
0

Have a look at the answer of Kungfooman in this post, he descripes the problem with the rotation over 90 degree or at 90 degree as well as 270 degree. He provides an Extension which will always calculate the correct pendant of the Quaternion for the value you want to set. Have a look here:

using UnityEngine;
using System.Collections;

public class ExtensionVector3 : MonoBehaviour {

    public static float CalculateEulerSafeX(float x){
        if( x > -90 && x <= 90 ){
            return x;
        }

        if( x > 0 ){
            x -= 180;
        } else {
            x += 180;
        }
        return x;
    }

    public static Vector3 EulerSafeX(Vector3 eulerAngles){
        eulerAngles.x = CalculateEulerSafeX(eulerAngles.x);
        return eulerAngles;
    }
}

And I used it like this:

Quaternion newQuat = m_directionalLight.transform.rotation;
Vector3 nL = new Vector3(ExtensionVector3.CalculateEulerSafeX(xNewValueLight), 
                         0, 
                         0);
newQuat.eulerAngles = nL;

m_directionalLight.transform.rotation = 
     Quaternion.Lerp(m_directionalLight.transform.rotation, 
                     newQuat, 
                     Time.deltaTime);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.