// SPDX-FileCopyrightText: 2023 Unity Technologies and the glTFast authors // SPDX-License-Identifier: Apache-2.0 using System; using UnityEngine; using static Unity.Mathematics.math; namespace GLTFast { using Unity.Mathematics; /// /// Mathematics helper methods /// public static class Mathematics { /// /// Decomposes a 4x4 TRS matrix into separate transforms (translation * rotation * scale) /// Matrix may not contain skew /// /// Input matrix /// Translation /// Rotation /// Scale public static void Decompose( this Matrix4x4 m, out Vector3 translation, out Quaternion rotation, out Vector3 scale ) { translation = new Vector3(m.m03, m.m13, m.m23); var mRotScale = new float3x3( m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, m.m21, m.m22 ); mRotScale.Decompose(out var mRotation, out var mScale); rotation = mRotation; scale = new Vector3(mScale.x, mScale.y, mScale.z); } /// /// Decomposes a 4x4 TRS matrix into separate transforms (translation * rotation * scale) /// Matrix may not contain skew /// /// Input matrix /// Translation /// Rotation /// Scale public static void Decompose( this float4x4 m, out float3 translation, out quaternion rotation, out float3 scale ) { var mRotScale = new float3x3( m.c0.xyz, m.c1.xyz, m.c2.xyz ); mRotScale.Decompose(out rotation, out scale); translation = m.c3.xyz; } /// /// Decomposes a 3x3 matrix into rotation and scale /// /// Input matrix /// Rotation quaternion values /// Scale static void Decompose(this float3x3 m, out quaternion rotation, out float3 scale) { var lenC0 = length(m.c0); var lenC1 = length(m.c1); var lenC2 = length(m.c2); float3x3 rotationMatrix; rotationMatrix.c0 = m.c0 / lenC0; rotationMatrix.c1 = m.c1 / lenC1; rotationMatrix.c2 = m.c2 / lenC2; scale.x = lenC0; scale.y = lenC1; scale.z = lenC2; if (rotationMatrix.IsNegative()) { rotationMatrix *= -1f; scale *= -1f; } // Inlined normalize(rotationMatrix) rotationMatrix.c0 = math.normalize(rotationMatrix.c0); rotationMatrix.c1 = math.normalize(rotationMatrix.c1); rotationMatrix.c2 = math.normalize(rotationMatrix.c2); rotation = new quaternion(rotationMatrix); } static bool IsNegative(this float3x3 m) { var cross = math.cross(m.c0, m.c1); return math.dot(cross, m.c2) < 0f; } /// /// Normalizes a vector /// /// Input vector /// Normalized output vector /// Length/magnitude of input vector public static float Normalize(float2 input, out float2 output) { var len = math.length(input); output = input / len; return len; } /// [Obsolete("Use Decompose overload with rotation parameter of type quaternion.")] public static void Decompose( this float4x4 m, out float3 translation, out float4 rotation, out float3 scale ) { m.Decompose(out translation, out quaternion rotationQuaternion, out scale); rotation = rotationQuaternion.value; } } }