Applying rotation to transform does not have the same outcome

I’ve come across some behaviour with applying a rotation to a transform that I don’t really understand.

What happens is: when I apply a rotation to a transform, the resulting rotation of this transform will sometimes not be the same that I applied.

e.g.:

var rotation = Random.rotation;
transform.rotation = rotation;
bool equals = transform.rotation.Equals(rotation);

I noticed that when I normalize the rotation before setting it, it is equal more often (1/10 chance of it being not equal).
My current guess is that Unity normalizes the Rotation every time it is set and with some Quaternions normalizing a normalized Quaternion will not give the same result?

What I want to achieve is to take the rotation from an object, save it and later apply this rotation to the same object again so it is exactly the same.
e.g.:

var rotation = Random.rotation;

transform.rotation = rotation;
rotation = transform.rotation;
transform.rotation = rotation;

bool equals = transform.rotation.Equals(rotation); //should be equal, but it's not

We’re developing a game with cloning and we got deterministic physics somewhat figured out, except for this rotation thing that happens sometimes.

Does anybody know what the cause of this is or how we could work around it?

The cause of this problem is that transform.rotation is a calculated value. Every time you store it and recalculate it it is subject to floating point precision errors. The true rotation value of the Transform is stored in transform.localRotation. Try storing and restoring that instead. (naturally its global orientation is then also subject to the orientation of its parent.)

That being said, simply storing and restoring the rotation should be very close to what it was previously and probably good enough for most use cases.

Thank you, that makes sense.

Sadly when I get and set localRotation instead of rotation it is also not equal every time.

Even the 1f == 10f / 10f doesn’t resolve to true every time…

Try Mathf.Approximately. Floating point errors accumulate and they will be ever so slightly different. Approximately takes this into account, so they will be deemed equal if the difference is or less than EPSILON.

https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html