using System; using UnityEngine; namespace UniVRM10 { public static class Matrix4x4Extensions { /// /// from AimConstraint /// /// /// /// /// public static (float Yaw, float Pitch) CalcYawPitch(this Matrix4x4 m, Vector3 target) { var localPosition = m.inverse.MultiplyPoint(target); var zaxis = Vector3.Project(localPosition, Vector3.forward); var yaxis = Vector3.Project(localPosition, Vector3.up); var xaxis = Vector3.Project(localPosition, Vector3.right); var xDot = Vector3.Dot(xaxis, Vector3.right) > 0; var yDot = Vector3.Dot(yaxis, Vector3.up) > 0; var zDot = Vector3.Dot(zaxis, Vector3.forward) > 0; // x z plane var yaw = (float)Math.Atan2(xaxis.magnitude, zaxis.magnitude) * Mathf.Rad2Deg; if (xDot && zDot) { // 1st(0-90) } else if (xDot && !zDot) { // 2nd(90-180) yaw = 180 - yaw; } else if (!xDot && !zDot) { // 3rd yaw = -180 + yaw; } else if (!xDot && zDot) { // 4th yaw = -yaw; } else { throw new NotImplementedException(); } // x+y z plane var pitch = (float)Math.Atan2(yaxis.magnitude, (xaxis + zaxis).magnitude) * Mathf.Rad2Deg; if (yDot) { pitch = -pitch; } return (yaw, pitch); } /// /// yaw: 右が+ /// pitch: 上が+ /// という仕様。vrm-0.x から据え置き /// public static void CalcYawPitch(this Matrix4x4 m, Vector3 target, out float yaw, out float pitch) { var z = Vector3.Dot(target, m.GetColumn(2)); var x = Vector3.Dot(target, m.GetColumn(0)); yaw = Mathf.Atan2(x, z) * Mathf.Rad2Deg; // x+y z plane var xz = Mathf.Sqrt(x * x + z * z); var y = Vector3.Dot(target, m.GetColumn(1)); pitch = Mathf.Atan2(y, xz) * Mathf.Rad2Deg; } /// /// yaw: 右が+ /// pitch: 上が+ /// という仕様。vrm-0.x から据え置き /// public static Quaternion YawPitchRotation(this Matrix4x4 m, float yaw, float pitch) { return Quaternion.AngleAxis(yaw, m.GetColumn(1)) * Quaternion.AngleAxis(-pitch, m.GetColumn(0)); } public static Matrix4x4 RotationToWorldAxis(this Matrix4x4 m) { return UnityExtensions.Matrix4x4FromColumns( m.MultiplyVector(Vector3.right), m.MultiplyVector(Vector3.up), m.MultiplyVector(Vector3.forward), new Vector4(0, 0, 0, 1) ); } } }