Unity-Technologies / Unity.Mathematics

The C# math library used in Unity providing vector types and math functions with a shader like syntax
Other
1.38k stars 156 forks source link

Dose math.mul(quaternion,quaternion) return value needs to be normalized? #171

Open lieene opened 3 years ago

lieene commented 3 years ago

I my project. rotation.Value = math.normalize(math.mul(deltaRot, rotation.Value)); works fine. but rotation.Value = math.mul(deltaRot, rotation.Value); Is not always working as expected. In what condition should we normalize a quaternion?

unpacklo commented 3 years ago

Due to rounding errors, multiplications by some delta will cause drift and your unit length quaternion may turn into a non unit length quaternion, especially if you repeatedly multiply and accumulate rotations.

Generally, you should normalize just before some other computation that requires the quaternion to be unit length. For example, if you knew that you had to multiply the quaternion several times but you only require unit length quaternions after the last multiplication, you can do this:

a = math.mul(delta, a);
a = math.mul(delta2, a);
a = math.normalize(math.mul(delta3, a));
lieene commented 3 years ago

In Unity.Entity.Transforms

    public struct LocalToWorld : IComponentData
    {
        public float4x4 Value;
        public float3 Right => new float3(Value.c0.x, Value.c0.y, Value.c0.z);
        public float3 Up => new float3(Value.c1.x, Value.c1.y, Value.c1.z);
        public float3 Forward => new float3(Value.c2.x, Value.c2.y, Value.c2.z);
        public float3 Position => new float3(Value.c3.x, Value.c3.y, Value.c3.z);
        public quaternion Rotation => new quaternion(Value);
    }

new quaternion(float4x4 ) is used directly. But It looks like that function is not expecting and scale in the matrix, even uniform scale. So when the matrix has scale the return quaternion would be wrong. from my tests. I tried with my own decompose Shear Scale Rotation function and the return quaternion is right. Is this an intentional optimization when L2W is not expected to have scale. Or is this a bug? P.S. the float4x4 I tested is an orthonormal transform not even sheared just uniformly scaled, with none-burst version new quaternion(float4x4 ).

also Right/Up/Forward are all not normalized. but that's fine.

lieene commented 3 years ago

Due to rounding errors, multiplications by some delta will cause drift and your unit length quaternion may turn into a non unit length quaternion, especially if you repeatedly multiply and accumulate rotations.

Generally, you should normalize just before some other computation that requires the quaternion to be unit length. For example, if you knew that you had to multiply the quaternion several times but you only require unit length quaternions after the last multiplication, you can do this:

a = math.mul(delta, a);
a = math.mul(delta2, a);
a = math.normalize(math.mul(delta3, a));

drifted away in 4d space ; ) Thanks, that's the same as my expectation.