Rotations are driving me NUTS!!!

I’m just going crazy…

Here’s a very simple test script. Please make a cube, attach the script to the camera, assign the cube to the variable and try it.

var MyCube : GameObject;

function OnGUI () {
	if (GUI.Button (Rect (10,10,150,100), "Rotate me")) {
	MyCube.transform.Rotate (0, 90 ,0, Space.World);
	MyCube.transform.Rotate (90, 0 ,0, Space.World);
	MyCube.transform.Rotate (0, 0 , 90, Space.World);

        print ("EulerAngles = " + MyCube.transform.eulerAngles);
	
	 if ((MyCube.transform.eulerAngles.x == 270)  (MyCube.transform.eulerAngles.y == 180)  (MyCube.transform.eulerAngles.z ==0)){
 	print("Yeah! it works!");
 }
 	
 	else{
 		print("Another mystery");
 	}
		

	}
}

Why my “if” statement doesn’t work? I just printed the eulerAngles number to make sure and they match the if condition. It should print “Yeah! it works!”

It’s driving me insane! This is just a test script to explain my problem. Actually in my real script I get even weirder stuff. The EulerAngles prints are ok but the inspector gives me numbers like 5.00342, 90.00001, -3.345345 but on the screen the cube look perfectly aligned. If I just rotate 90 degrees in one axis, why are the two other axis values changing to these weird numbers? Comment the first two rotations and you will see that the inspector gives you 90.0001 in Z instead of 90.

HELP!!! It’s the only thing left for me to do to finish the scripting of my game.

EDIT: removed parts that had to do with Quaternion stuff.

Robert

The problem was that even if the print gives me a value of lets say 90, the real value is 90.00001 and that’s why the If didn’t work. Now why does it give me 90.0001 instead of 90 is still a mystery.

Here’s the test code N.2:

var MyCube : GameObject;

function OnGUI () {
	if (GUI.Button (Rect (10,10,150,100), "Rotate me")) {
		MyCube.transform.eulerAngles.y = MyCube.transform.eulerAngles.y + 90;

        print ("EulerAngles = " + MyCube.transform.eulerAngles);
 
 	 if ((MyCube.transform.eulerAngles.x ==0)  (MyCube.transform.eulerAngles.y ==90.00001)  (MyCube.transform.eulerAngles.z ==0)){
 	print("Yeah! it works!");
 }
 	
 	else{
 		print("Another mystery");
 	}
		

	}
}

So I found the problem but not the solution because if I combine all axis and I do a lot of rotations in all axis these decimals keeps adding and adding and that’s why I get into problems.

Just click multiple time on the button and you’ll see that you’ll get 90.00001 then 180 then 270 and finally it goes to 1.001791e-05 instead of 0. And that’s only on one axis…

So, how can I make sure that when I tell my cube to rotate 90 degrees it will actually rotate 90 degrees and not anything else? That’s the real issue.

Robert

The strange numbers you are getting are due to floating point inaccuracies. I recently put up a post on it here. It’s quite a common thing in computing, and something to be aware of. Your result of 1.001791e-05 actually equates to a tiny tiny tiny number very close to zero, and for the same reasons listed above.

An easy way to get around the problem is to define a small range, so rather than check for exactly 180, check x >= 179.5 x <= 180.5. You can bring the numbers closer if you find this isn’t accurate enough for you.

Here is one of my favourite computer calculation fails. :slight_smile:

Even google isn’t perfect.

1 Like

Hi Murcho,

I know floating points can be an issue but this is clearly a bug in the way Unity calculates the rotations and here’s why.

  1. Add this to the script and try it again:
MyCube.transform.position.y = MyCube.transform.position.y + 90;
MyCube.transform.localScale.y = MyCube.transform.localScale.y + 90

;

It works perfectly for the translation and scale. I’m doing the same thing, just adding 90.

  1. I’ve been doing 3D for 14 years… I never, ever saw a 3D package that cannot accurately calculate 0 + 90 in rotations…

  2. If I was calculating the trajectory of a spaceship toward Pluto I could expect my ship to deviate after such a long run but come on, 0 + 90 = 90.0001???

  3. The strangest part is that sometimes I get an inaccuracy of more then 8 degrees after making a lot of rotations. 8! Not 0.8, 8.577766e-05!! But the cube doesn’t look like it’s not perfectly rotated and if I go in the inspector and manually change the number to 0 while the game is playing the cube doesn’t move at all. That’s another reason that makes me believe it’s a bug because the display is ok but the numbers are wrong.

Maybe it’s because of the way they calculate the rotations with quaternion. I have no idea what quaternion is so I don’t know if that’s the cause but definitively it’s a Unity bug for me.

Anyway it’s a nightmare for me because I need to compare 2 cubes to see if the rotations are the same and it’s driving me nuts.

Robert

1 Like
  1. If i get a result of -5.008956e-06 (and the cube looks perfectly aligned) and I manually change the number to -5 the cube rotates.

  2. Try my script with the rotation in X instead of Y. You’ll get the following results:

First click: 90, 0 ,0
Second click: -5.008956e-06, 180 , 180
Third: 90, -1.941256e-19, 0
then it loops between the results of the second and third click.

So it’s clear now. -5.008956e-06 is not a floating point inaccuracy. It’s way too big for that.

It’s 6:21 am now… time to go to sleep…

Look at the numbers you get. There’s an e in there and that e is important! It’s called scientific notation and means that the number is rised to the power of what follows after the e.

i.e. 8.577766e-05 == 8.577766^-05 == .00008577766

The error is not 8.5 but 8.5 one-hundred-thousandth.

And yes, it’s also related to quaternions because that’s what Unity uses internally and whenever you set/get euler angles Unity is doing a conversion for you, which also result in additional small inaccuracies.

Though small errors like this are to be expected from floating point numbers and nothing that should get in your way. To make things easier, Unity includes a method in Mathf to compare floats that will take those small inaccuracies into account:

1 Like

Hummm… yeah… at 6 am, I missed that little “e-”… my bad… needed some sleep…

I will try the mathF. I’m sure it’s going to work. Problem fixed. Thanks!

Robert

The inaccuracies, if not dealt with early on, will accumulate into something quite large over time.

If exact results are very important, you might need another class setup to monitor these issues you’re having.

E.g. If the object is at 90.00001 and you need it to rotate to 180, check it’s current rotation, and then only rotate by 89.99999. This will help stop the accumulation of these errors.

Most internal rotation values are in radians or quaternions (which are truly weird), so when you see “degrees” you’re actually seeing a calculated value derived from an internally stored value that is in different units in which 90° (say) is not a nice, round number but π/2 radians, which is a distinctly non-round number, which is why you will often find it difficult to set exact values.

So yes – you need to stop worrying and learn to love approximate values

I ran into this problem today. It doesnt coz problems on my Mac However
When I run it on unity iPhone my player hangs when its at 1.001791e-05. ALWAYS.

Cant seem to find a solution -.-"

iTween

Or, simply use the power of math. Mathf.Round()

var MyCube : GameObject;

function Start(){
	MyCube = gameObject;
}

function OnGUI () {
	if (GUI.Button (Rect (10,10,150,100), "Rotate me")) {
		MyCube.transform.Rotate (0, 90 ,0, Space.World);
		MyCube.transform.Rotate (90, 0 ,0, Space.World);
		MyCube.transform.Rotate (0, 0 , 90, Space.World);
		
		var euler = MyCube.transform.eulerAngles;
		euler.x = Mathf.Round(euler.x / 90) * 90;
		euler.y = Mathf.Round(euler.y / 90) * 90;
		euler.z = Mathf.Round(euler.z / 90) * 90;
		print ("EulerAngles = " + euler);
		if ((euler.x == 270)  (euler.y == 180)  (euler.z ==0)){
			print("Yeah! it works!");
		}else{
			print("Another mystery");
		}
	}
}

This is kind of what epsilon is for when refering to floating point numbers.

Mathf.Epsilon

incase your too lazy to click epsilon above and…

which is referenced on that page which also sounds like what your looking for any way.

Prior to coming to unity, i used to define a FLOAT_EPSILON at 0.0001f
being that anything after that number in the floating value i couldn’t care any more about.

OH i wanted to mention also. It sounds like the modulus operator would be more useful to you when debuggin.
So some angel % 360 will give you the remainder of dividing by 360.

http://itween.pixelplacement.com/documentation.php

floating point errors. deal with it.

Mathf.Approximately