diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs index f4d9db503c..2f36fe60b1 100644 --- a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs @@ -2,43 +2,24 @@ { public readonly struct LookAtEyeDirection { - /// - /// Yaw of LeftEye - /// - public float LeftYaw { get; } - + public float Yaw { get; } + /// /// Pitch of LeftEye /// - public float LeftPitch { get; } - - /// - /// NOTE: 何故か使われていない - /// Yaw of RightEye - /// - public float RightYaw { get; } - - /// - /// NOTE: 何故か使われていない - /// Pitch of RightEye - /// - public float RightPitch { get; } + public float Pitch { get; } - public LookAtEyeDirection(float leftYaw, float leftPitch, float rightYaw, float rightPitch) + public LookAtEyeDirection(float yaw, float pitch) { - LeftYaw = leftYaw; - LeftPitch = leftPitch; - RightYaw = rightYaw; - RightPitch = rightPitch; + Yaw = yaw; + Pitch = pitch; } public static LookAtEyeDirection Multiply(LookAtEyeDirection a, float b) { return new LookAtEyeDirection( - a.LeftYaw * b, - a.LeftPitch * b, - a.RightYaw * b, - a.RightPitch * b + a.Yaw * b, + a.Pitch * b ); } } diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs index bf4dda2741..89e483c670 100644 --- a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs @@ -20,7 +20,7 @@ public LookAtEyeDirectionApplicableToBone(Transform leftEye, Transform rightEye, CurveMapper horizontalOuter, CurveMapper horizontalInner, CurveMapper verticalDown, CurveMapper verticalUp) { _leftEye = leftEye; - _leftInit= Matrix4x4.Rotate(leftEye.localRotation); + _leftInit = Matrix4x4.Rotate(leftEye.localRotation); _rightEye = rightEye; _rightInit = Matrix4x4.Rotate(rightEye.localRotation); _horizontalOuter = horizontalOuter; @@ -35,9 +35,9 @@ public LookAtEyeDirectionApplicableToBone(Transform leftEye, Transform rightEye, public void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights) { // FIXME - var yaw = eyeDirection.LeftYaw; - var pitch = eyeDirection.LeftPitch; - + var yaw = eyeDirection.Yaw; + var pitch = eyeDirection.Pitch; + // horizontal float leftYaw, rightYaw; if (yaw < 0) @@ -62,20 +62,23 @@ public void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights) { - var yaw = eyeDirection.LeftYaw; - var pitch = eyeDirection.LeftPitch; + var yaw = eyeDirection.Yaw; + var pitch = eyeDirection.Pitch; if (yaw < 0) { diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtInput.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtInput.cs new file mode 100644 index 0000000000..10a26e95b8 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtInput.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// LookAt を具体的な値に解決する前の入力値 + /// この値を元に LookAtEyeDirection を生成し、 + /// LookAtEyeDirection を Bone もしくは MorphTarget に対して適用する。 + /// + public struct LookAtInput + { + public LookAtEyeDirection? YawPitch; + public Vector3? WorldPosition; + } +} diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtInput.cs.meta b/Assets/VRM10/Runtime/Components/LookAt/LookAtInput.cs.meta new file mode 100644 index 0000000000..71262e0613 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtInput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f7a52869fd45b2439bce28499c3f8dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index 459ca42667..8a40ad9e57 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -21,7 +21,7 @@ namespace UniVRM10 /// public class Vrm10Runtime : IDisposable { - private readonly Vrm10Instance m_target; + private readonly Vrm10Instance m_instance; private readonly Transform m_head; private readonly FastSpringBoneService m_fastSpringBoneService; private readonly IReadOnlyDictionary m_defaultTransformStates; @@ -51,38 +51,38 @@ public Vector3 ExternalForce } } - public Vrm10Runtime(Vrm10Instance target, bool useControlRig) + public Vrm10Runtime(Vrm10Instance instance, bool useControlRig) { if (!Application.isPlaying) { Debug.LogWarning($"{nameof(Vrm10Runtime)} expects runtime behaviour."); } - m_target = target; + m_instance = instance; - if (!target.TryGetBoneTransform(HumanBodyBones.Head, out m_head)) + if (!instance.TryGetBoneTransform(HumanBodyBones.Head, out m_head)) { throw new Exception(); } if (useControlRig) { - ControlRig = new Vrm10RuntimeControlRig(target.Humanoid, m_target.transform); + ControlRig = new Vrm10RuntimeControlRig(instance.Humanoid, m_instance.transform); } - Constraints = target.GetComponentsInChildren(); - LookAt = new Vrm10RuntimeLookAt(target.Vrm.LookAt, target.Humanoid, ControlRig); - Expression = new Vrm10RuntimeExpression(target, LookAt.EyeDirectionApplicable); + Constraints = instance.GetComponentsInChildren(); + LookAt = new Vrm10RuntimeLookAt(instance.Vrm.LookAt, instance.Humanoid, ControlRig); + Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable); - var instance = target.GetComponent(); - if (instance != null) + var gltfInstance = instance.GetComponent(); + if (gltfInstance != null) { // ランタイムインポートならここに到達してゼロコストになる - m_defaultTransformStates = instance.InitialTransformStates; + m_defaultTransformStates = gltfInstance.InitialTransformStates; } else { // エディタでプレハブ配置してる奴ならこっちに到達して収集する - m_defaultTransformStates = target.GetComponentsInChildren() + m_defaultTransformStates = instance.GetComponentsInChildren() .ToDictionary(tf => tf, tf => new TransformState(tf)); } @@ -90,7 +90,7 @@ public Vrm10Runtime(Vrm10Instance target, bool useControlRig) if (Application.isPlaying) { m_fastSpringBoneService = FastSpringBoneService.Instance; - m_fastSpringBoneBuffer = CreateFastSpringBoneBuffer(m_target.SpringBone); + m_fastSpringBoneBuffer = CreateFastSpringBoneBuffer(m_instance.SpringBone); m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer); } } @@ -111,7 +111,7 @@ public void ReconstructSpringBone() m_fastSpringBoneService.BufferCombiner.Unregister(m_fastSpringBoneBuffer); m_fastSpringBoneBuffer.Dispose(); - m_fastSpringBoneBuffer = CreateFastSpringBoneBuffer(m_target.SpringBone); + m_fastSpringBoneBuffer = CreateFastSpringBoneBuffer(m_instance.SpringBone); m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer); } @@ -203,20 +203,11 @@ public void Process() Expression.SetWeight(k, v()); } - // TODO: look at target - // - // この Frame の LookAt 値をアップデート - // - // struct LookAtValue - // { - // LookAtTargetTypes; - // - // (float, float) YawPitch; // 一番明確 - // Vector3 GazePosition; // 座標系? - // Transform GazeTarget; // 解決順のため遅延させる意図があるか - // } - // - // あとで、LookAt.Process の引き数にわたす + // look at + if (VrmAnimation.LookAt.HasValue) + { + LookAt.LookAtInput = VrmAnimation.LookAt.Value; + } } // 2. Control Rig @@ -228,11 +219,20 @@ public void Process() constraint.Process(); } + if (m_instance.LookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform + && m_instance.LookAtTarget != null) + { + // Transform 追跡で視線を生成する。 + // 値を上書きします。 + LookAt.LookAtInput = new LookAtInput { WorldPosition = m_instance.LookAtTarget.position }; + } + // 4. Gaze control - LookAt.Process(m_target.LookAtTargetType, m_target.LookAtTarget); + var eyeDirection = LookAt.Process(); // 5. Apply Expression - Expression.Process(LookAt.EyeDirection); + // LookAt の角度制限などはこちらで処理されます。 + Expression.Process(eyeDirection); } } } diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs index d72ecf54b6..c7b3d0c1df 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs @@ -13,9 +13,17 @@ public sealed class Vrm10RuntimeLookAt : ILookAtEyeDirectionProvider internal ILookAtEyeDirectionApplicable EyeDirectionApplicable { get; } - public float Yaw { get; private set; } - public float Pitch { get; private set; } + /// + /// 入力値。適宜更新可。 + /// + public LookAtInput LookAtInput { get; set; } + + /// + /// 出力値。Process() のみが更新する + /// public LookAtEyeDirection EyeDirection { get; private set; } + public float Yaw => EyeDirection.Yaw; + public float Pitch => EyeDirection.Pitch; /// /// Transform that indicates the position center of eyes. @@ -52,39 +60,33 @@ internal Vrm10RuntimeLookAt(VRM10ObjectLookAt lookAt, UniHumanoid.Humanoid human } } - internal void Process(VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform lookAtTarget) + internal LookAtEyeDirection Process() { LookAtOriginTransform.localPosition = _lookAtOriginTransformLocalPosition; LookAtOriginTransform.localRotation = _lookAtOriginTransformLocalRotation; - switch (lookAtTargetType) + if (LookAtInput.YawPitch is LookAtEyeDirection dir) { - case VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform: - // NOTE: 指定された Transform の位置を向くように Yaw/Pitch を計算して適用する - if (lookAtTarget != null) - { - var value = CalculateYawPitchFromLookAtPosition(lookAtTarget.position); - SetYawPitchManually(value.Yaw, value.Pitch); - } - break; - case VRM10ObjectLookAt.LookAtTargetTypes.YawPitchValue: - // NOTE: 直接 Set された Yaw/Pitch を使って計算する - break; + EyeDirection = dir; } - - EyeDirection = new LookAtEyeDirection(Yaw, Pitch, 0, 0); + else if (LookAtInput.WorldPosition is Vector3 worldPosition) + { + // NOTE: 指定された Transform の位置を向くように Yaw/Pitch を計算して適用する + var (yaw, pitch) = CalculateYawPitchFromLookAtPosition(worldPosition); + EyeDirection = new LookAtEyeDirection(yaw, pitch); + } + return EyeDirection; } /// /// Yaw/Pitch 値を直接設定します。 - /// LookAtTargetTypes が SpecifiedTransform の場合、ここで設定しても値は上書きされます。 + /// Vrm10Instance.LookAtTargetTypes が SpecifiedTransform の場合、ここで設定しても値は上書きされます。 /// /// Headボーンのforwardに対するyaw角(度) /// Headボーンのforwardに対するpitch角(度) public void SetYawPitchManually(float yaw, float pitch) { - Yaw = yaw; - Pitch = pitch; + LookAtInput = new LookAtInput { YawPitch = new LookAtEyeDirection(yaw, pitch) }; } public (float Yaw, float Pitch) CalculateYawPitchFromLookAtPosition(Vector3 lookAtWorldPosition) @@ -105,7 +107,7 @@ private static Transform InitializeLookAtOriginTransform(Transform rawHead, Tran return lookAtOrigin; } -#region Obsolete + #region Obsolete [Obsolete("Use " + nameof(LookAtOriginTransform))] public Transform GetLookAtOrigin(Transform head) { @@ -134,6 +136,6 @@ public void SetLookAtYawPitch(float yaw, float pitch) throw new ArgumentOutOfRangeException(nameof(lookAtTargetType), lookAtTargetType, null); } } -#endregion + #endregion } } diff --git a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs index 7242e5b1f2..6936ab7a31 100644 --- a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs +++ b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using UnityEngine; namespace UniVRM10 { @@ -8,5 +9,6 @@ public interface IVrm10Animation : IDisposable (INormalizedPoseProvider, ITPoseProvider) ControlRig { get; } IReadOnlyDictionary> ExpressionMap { get; } public void ShowBoxMan(bool enable); + LookAtInput? LookAt { get; } } } diff --git a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs index fd0beccefe..4cbb3b861a 100644 --- a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs +++ b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs @@ -33,6 +33,8 @@ public void Dispose() readonly Dictionary> _ExpressionSetterMap = new(); public IReadOnlyDictionary> ExpressionSetterMap => _ExpressionSetterMap; + public LookAtInput? LookAt { get; set; } + void InitializeExpression(ExpressionKey key, Func getter, Action setter) { _ExpressionGetterMap.Add(key, getter); diff --git a/Assets/VRM10_Samples/VRM10Viewer/Motions/BvhMotion.cs b/Assets/VRM10_Samples/VRM10Viewer/Motions/BvhMotion.cs index ffebf9cabc..ffb925bb97 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/Motions/BvhMotion.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/Motions/BvhMotion.cs @@ -17,6 +17,8 @@ public class BvhMotion : IVrm10Animation IDictionary> _ExpressionMap = new Dictionary>(); public IReadOnlyDictionary> ExpressionMap => (IReadOnlyDictionary>)_ExpressionMap; + public LookAtInput? LookAt { get; set; } + public BvhMotion(UniHumanoid.BvhImporterContext context) { m_context = context;