diff --git a/Assets/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs b/Assets/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs index 21b3a0178..7787dd1ef 100644 --- a/Assets/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs +++ b/Assets/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs @@ -48,16 +48,16 @@ namespace UniVRM10 { m_expressionKeyWeights[slider.Key] = slider.Value; } - m_target.Vrm.Expression.SetWeights(m_expressionKeyWeights); + m_target.Runtime.Expression.SetWeights(m_expressionKeyWeights); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Override rates", EditorStyles.boldLabel); EditorGUI.BeginDisabledGroup(true); { - EditorGUILayout.Slider("Blink override rate", m_target.Vrm.Expression.BlinkOverrideRate, 0f, 1f); - EditorGUILayout.Slider("LookAt override rate", m_target.Vrm.Expression.LookAtOverrideRate, 0f, 1f); - EditorGUILayout.Slider("Mouth override rate", m_target.Vrm.Expression.MouthOverrideRate, 0f, 1f); + EditorGUILayout.Slider("Blink override rate", m_target.Runtime.Expression.BlinkOverrideRate, 0f, 1f); + EditorGUILayout.Slider("LookAt override rate", m_target.Runtime.Expression.LookAtOverrideRate, 0f, 1f); + EditorGUILayout.Slider("Mouth override rate", m_target.Runtime.Expression.MouthOverrideRate, 0f, 1f); } EditorGUI.EndDisabledGroup(); } diff --git a/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs b/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs index 2a9cba1e5..ad15a88fe 100644 --- a/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs +++ b/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using UnityEditor; using UnityEditor.EditorTools; @@ -60,7 +59,7 @@ namespace UniVRM10 Handles.BeginGUI(); if (Application.isPlaying) { - ExpressionPreviewInPlay(root?.Vrm?.Expression); + ExpressionPreviewInPlay(root?.Vrm?.Expression, root?.Runtime.Expression); } else { @@ -69,7 +68,7 @@ namespace UniVRM10 Handles.EndGUI(); } - void ExpressionPreviewInPlay(VRM10ObjectExpression expression) + void ExpressionPreviewInPlay(VRM10ObjectExpression expression, Vrm10RuntimeExpression runtime) { if (expression == null) { @@ -87,7 +86,7 @@ namespace UniVRM10 GUILayout.FlexibleSpace(); m_map.Clear(); - foreach (var kv in expression.GetWeights()) + foreach (var kv in runtime.GetWeights()) { var key = kv.Key; if (kv.Key.Preset != ExpressionPreset.custom) @@ -98,7 +97,7 @@ namespace UniVRM10 } GUILayout.FlexibleSpace(); - expression.SetWeights(m_map); + runtime.SetWeights(m_map); } EditorGUILayout.EndVertical(); } diff --git a/Assets/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs b/Assets/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs index 854f6845b..596bbb4f5 100644 --- a/Assets/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs +++ b/Assets/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs @@ -82,7 +82,7 @@ namespace UniVRM10 if (Application.isPlaying) { - OnSceneGUILookAt(root.Vrm.LookAt, head, root.LookAtTargetType, root.Gaze); + OnSceneGUILookAt(root.Vrm.LookAt, root.Runtime.LookAt, head, root.LookAtTargetType, root.Gaze); } else { @@ -121,7 +121,7 @@ namespace UniVRM10 const float RADIUS = 0.5f; - static void OnSceneGUILookAt(VRM10ObjectLookAt lookAt, Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze) + static void OnSceneGUILookAt(VRM10ObjectLookAt lookAt, Vrm10RuntimeLookAt runtime, Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze) { if (head == null) return; @@ -138,11 +138,11 @@ namespace UniVRM10 } Handles.color = new Color(1, 1, 1, 0.6f); - Handles.DrawDottedLine(lookAt.GetLookAtOrigin(head).position, gaze.position, 4.0f); + Handles.DrawDottedLine(runtime.GetLookAtOrigin(head).position, gaze.position, 4.0f); } - var (yaw, pitch) = lookAt.GetLookAtYawPitch(head, lookAtTargetType, gaze); - var lookAtOriginMatrix = lookAt.GetLookAtOrigin(head).localToWorldMatrix; + var (yaw, pitch) = runtime.GetLookAtYawPitch(head, lookAtTargetType, gaze); + var lookAtOriginMatrix = runtime.GetLookAtOrigin(head).localToWorldMatrix; Handles.matrix = lookAtOriginMatrix; var p = lookAt.OffsetFromHead; Handles.Label(Vector3.zero, diff --git a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs index e9a99e213..81e6d81c4 100644 --- a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs +++ b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs @@ -265,124 +265,7 @@ namespace UniVRM10 // } // } - public static IExpressionValidatorFactory ExpressionValidatorFactory = new DefaultExpressionValidator.Factory(); - private List _keys = new List(); - private Dictionary _inputWeights = new Dictionary(); - private Dictionary _actualWeights = new Dictionary(); - private ExpressionMerger _merger; - private IExpressionValidator _validator; - private LookAtEyeDirection _inputEyeDirection; - private LookAtEyeDirection _actualEyeDirection; - private ILookAtEyeDirectionProvider _eyeDirectionProvider; - private ILookAtEyeDirectionApplicable _eyeDirectionApplicable; - public IReadOnlyList ExpressionKeys => _keys; - public IReadOnlyDictionary ActualWeights => _actualWeights; - public LookAtEyeDirection ActualEyeDirection => _actualEyeDirection; - public float BlinkOverrideRate { get; private set; } - public float LookAtOverrideRate { get; private set; } - public float MouthOverrideRate { get; private set; } - - int m_debugCount; - - internal void Setup(Vrm10Instance target, ILookAtEyeDirectionProvider eyeDirectionProvider, ILookAtEyeDirectionApplicable eyeDirectionApplicable) - { - Restore(); - - _merger = new ExpressionMerger(this, target.transform); - _keys = Clips.Select(x => CreateKey(x.Clip)).ToList(); - var oldInputWeights = _inputWeights; - _inputWeights = _keys.ToDictionary(x => x, x => 0f); - foreach (var key in _keys) - { - // remain user input weights. - if (oldInputWeights.ContainsKey(key)) _inputWeights[key] = oldInputWeights[key]; - } - _actualWeights = _keys.ToDictionary(x => x, x => 0f); - _validator = ExpressionValidatorFactory.Create(this); - _eyeDirectionProvider = eyeDirectionProvider; - _eyeDirectionApplicable = eyeDirectionApplicable; - } - - internal void Restore() - { - _merger?.RestoreMaterialInitialValues(); - _merger = null; - - _eyeDirectionApplicable?.Restore(); - _eyeDirectionApplicable = null; - } - - public void Process() - { - Apply(); - } - - public IDictionary GetWeights() - { - return _inputWeights; - } - - public float GetWeight(ExpressionKey expressionKey) - { - if (_inputWeights.ContainsKey(expressionKey)) - { - return _inputWeights[expressionKey]; - } - - return 0f; - } - - public LookAtEyeDirection GetEyeDirection() - { - return _inputEyeDirection; - } - - public void SetWeights(IEnumerable> weights) - { - foreach (var (expressionKey, weight) in weights.Select(kv => (kv.Key, kv.Value))) - { - if (_inputWeights.ContainsKey(expressionKey)) - { - _inputWeights[expressionKey] = weight; - } - } - Apply(); - } - - public void SetWeight(ExpressionKey expressionKey, float weight) - { - if (_inputWeights.ContainsKey(expressionKey)) - { - _inputWeights[expressionKey] = weight; - } - Apply(); - } - - /// - /// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。 - /// この際、LookAt の情報を pull してそれも適用する。 - /// - private void Apply() - { - // 1. Get eye direction from provider. - _inputEyeDirection = _eyeDirectionProvider?.EyeDirection ?? default; - - // 2. Validate user input, and Output as actual weights. - _validator.Validate(_inputWeights, _actualWeights, - _inputEyeDirection, out _actualEyeDirection, - out var blink, out var lookAt, out var mouth); - - // 3. Set eye direction expression weights or any other side-effects (ex. eye bone). - _eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights); - - // 4. Set actual weights to raw blendshapes. - _merger.SetValues(_actualWeights); - - BlinkOverrideRate = blink; - LookAtOverrideRate = lookAt; - MouthOverrideRate = mouth; - } } } diff --git a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs index 0c3682256..1077211b1 100644 --- a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs +++ b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs @@ -8,7 +8,7 @@ using UnityEditor; namespace UniVRM10 { [Serializable] - public class VRM10ObjectLookAt : ILookAtEyeDirectionProvider + public class VRM10ObjectLookAt { public enum LookAtTargetTypes { @@ -33,117 +33,5 @@ namespace UniVRM10 [SerializeField] public CurveMapper VerticalUp = new CurveMapper(90.0f, 10.0f); - - private Transform m_head; - private Transform m_leftEye; - private Transform m_rightEye; - private ILookAtEyeDirectionApplicable _eyeDirectionApplicable; - - internal ILookAtEyeDirectionApplicable EyeDirectionApplicable => _eyeDirectionApplicable; - - public LookAtEyeDirection EyeDirection { get; private set; } - - #region LookAtTargetTypes.CalcYawPitchToGaze - // 座標計算用のempty - Transform m_lookAtOrigin; - public Transform GetLookAtOrigin(Transform head) - { - if (!Application.isPlaying) - { - return null; - } - if (m_lookAtOrigin == null) - { - m_lookAtOrigin = new GameObject("_lookat_origin_").transform; - m_lookAtOrigin.SetParent(head); - } - return m_lookAtOrigin; - } - - /// - /// Headローカルの注視点からYaw, Pitch角を計算する - /// - (float, float) CalcLookAtYawPitch(Vector3 targetWorldPosition, Transform head) - { - GetLookAtOrigin(head).localPosition = OffsetFromHead; - - var localPosition = m_lookAtOrigin.worldToLocalMatrix.MultiplyPoint(targetWorldPosition); - float yaw, pitch; - Matrix4x4.identity.CalcYawPitch(localPosition, out yaw, out pitch); - return (yaw, pitch); - } - #endregion - - #region LookAtTargetTypes.SetYawPitch - float m_yaw; - float m_pitch; - - /// - /// LookAtTargetTypes.SetYawPitch時の視線の角度を指定する - /// - /// Headボーンのforwardに対するyaw角(度) - /// Headボーンのforwardに対するpitch角(度) - public void SetLookAtYawPitch(float yaw, float pitch) - { - m_yaw = yaw; - m_pitch = pitch; - } - #endregion - - /// - /// LookAtTargetType に応じた yaw, pitch を得る - /// - /// Headボーンのforwardに対するyaw角(度), pitch角(度) - public (float, float) GetLookAtYawPitch(Transform head, LookAtTargetTypes lookAtTargetType, Transform gaze) - { - switch (lookAtTargetType) - { - case LookAtTargetTypes.CalcYawPitchToGaze: - // Gaze(Transform)のワールド位置に対して計算する - return CalcLookAtYawPitch(gaze.position, head); - - case LookAtTargetTypes.SetYawPitch: - // 事前にSetYawPitchした値を使う - return (m_yaw, m_pitch); - } - - throw new NotImplementedException(); - } - - internal void Setup(Animator animator, Transform head, LookAtTargetTypes lookAtTargetType, Transform gaze) - { - m_head = head; - m_leftEye = animator.GetBoneTransform(HumanBodyBones.LeftEye); - m_rightEye = animator.GetBoneTransform(HumanBodyBones.RightEye); - - var isRuntimeAsset = true; -#if UNITY_EDITOR - isRuntimeAsset = Application.isPlaying && !PrefabUtility.IsPartOfAnyPrefab(m_head); -#endif - if (isRuntimeAsset && lookAtTargetType == LookAtTargetTypes.CalcYawPitchToGaze && gaze == null) - { - gaze = new GameObject().transform; - gaze.name = "__LOOKAT_GAZE__"; - gaze.SetParent(m_head); - gaze.localPosition = Vector3.forward; - } - switch (LookAtType) - { - case LookAtType.bone: - _eyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(m_leftEye, m_rightEye, HorizontalOuter, HorizontalInner, VerticalDown, VerticalUp); - break; - case LookAtType.expression: - _eyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(HorizontalOuter, HorizontalInner, VerticalDown, VerticalUp); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - public void Process(LookAtTargetTypes lookAtTargetType, Transform gaze) - { - var (yaw, pitch) = GetLookAtYawPitch(m_head, lookAtTargetType, gaze); - EyeDirection = new LookAtEyeDirection(yaw, pitch, 0, 0); - } } } diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs index 5d0e7d7b9..71cde0211 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs @@ -1,21 +1,12 @@ -using System; -using UnityEngine; +using UnityEngine; namespace UniVRM10 { /// - /// VRM全体を制御するコンポーネント。 + /// VRM全体を制御するRoot /// - /// 各フレームのHumanoidへのモーション適用後に任意のタイミングで - /// Applyを呼び出してください。 - /// - /// ヒエラルキー内への参照のシリアライズ - /// - /// * Humanoid(VRM必須) - /// * SpringBone の MonoBehaviour でない部分 - /// * ColliderGroup - /// * Springs + /// Importer(scripted importer) -> Prefab(editor/asset) -> Instance(scene/MonoBehavior) -> Runtime(play時) /// /// * DefaultExecutionOrder(11000) means calculate springbone after FinalIK( VRIK ) /// @@ -24,9 +15,16 @@ namespace UniVRM10 [DefaultExecutionOrder(11000)] public class Vrm10Instance : MonoBehaviour { + /// + /// シリアライズ情報 + /// [SerializeField, Header("VRM1")] public VRM10Object Vrm; + /// + /// SpringBone のシリアライズ情報 + /// + /// [SerializeField] public Vrm10InstanceSpringBone SpringBone = new Vrm10InstanceSpringBone(); @@ -55,18 +53,18 @@ namespace UniVRM10 [SerializeField] public VRM10ObjectLookAt.LookAtTargetTypes LookAtTargetType; - Vrm10InstanceRuntime m_runtime; + Vrm10Runtime m_runtime; /// - /// ランタイム実行時に生成されるインスタンス + /// ランタイム情報 /// - public Vrm10InstanceRuntime Runtime + public Vrm10Runtime Runtime { get { if (m_runtime == null) { - m_runtime = new Vrm10InstanceRuntime(this); + m_runtime = new Vrm10Runtime(this); } return m_runtime; } diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime.meta b/Assets/VRM10/Runtime/Components/Vrm10Runtime.meta new file mode 100644 index 000000000..075e4e2b7 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea81ef4ff96a05a4f8d4f0eefc8bd2fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceRuntime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs similarity index 87% rename from Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceRuntime.cs rename to Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index 7fad226ad..7bcad98b1 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceRuntime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -9,7 +9,7 @@ namespace UniVRM10 /// /// Play時 と Editorからの参照情報置き場 /// - public class Vrm10InstanceRuntime : IDisposable + public class Vrm10Runtime : IDisposable { private readonly Vrm10Instance m_target; private readonly VRM10Constraint[] m_constraints; @@ -18,7 +18,13 @@ namespace UniVRM10 private FastSpringBoneBuffer m_fastSpringBoneBuffer; - public Vrm10InstanceRuntime(Vrm10Instance target) + private Vrm10RuntimeExpression m_expression; + public Vrm10RuntimeExpression Expression => m_expression; + + private Vrm10RuntimeLookAt m_lookat; + public Vrm10RuntimeLookAt LookAt => m_lookat; + + public Vrm10Runtime(Vrm10Instance target) { m_target = target; var animator = target.GetComponent(); @@ -28,8 +34,8 @@ namespace UniVRM10 } m_head = animator.GetBoneTransform(HumanBodyBones.Head); - target.Vrm.LookAt.Setup(animator, m_head, target.LookAtTargetType, target.Gaze); - target.Vrm.Expression.Setup(target, target.Vrm.LookAt, target.Vrm.LookAt.EyeDirectionApplicable); + m_lookat = new Vrm10RuntimeLookAt(target.Vrm.LookAt, animator, m_head, target.LookAtTargetType, target.Gaze); + m_expression = new Vrm10RuntimeExpression(target, m_lookat, m_lookat.EyeDirectionApplicable); if (m_constraints == null) { @@ -131,12 +137,12 @@ namespace UniVRM10 // // gaze control // - m_target.Vrm.LookAt.Process(m_target.LookAtTargetType, m_target.Gaze); + m_target.Runtime.LookAt.Process(m_target.LookAtTargetType, m_target.Gaze); // // expression // - m_target.Vrm.Expression.Process(); + m_target.Runtime.Expression.Process(); } public void Dispose() diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceRuntime.cs.meta b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs.meta similarity index 83% rename from Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceRuntime.cs.meta rename to Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs.meta index 707b1f095..9d78fc946 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceRuntime.cs.meta +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 56e3778fb3288a54d8f898a458e81a23 +guid: f690a05022c98184bacf46b6675f5bc8 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs new file mode 100644 index 000000000..35fc6d959 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs @@ -0,0 +1,128 @@ +using System.Collections.Generic; +using System.Linq; + +namespace UniVRM10 +{ + public class Vrm10RuntimeExpression + { + public static IExpressionValidatorFactory ExpressionValidatorFactory = new DefaultExpressionValidator.Factory(); + + private List _keys = new List(); + private Dictionary _inputWeights = new Dictionary(); + private Dictionary _actualWeights = new Dictionary(); + private ExpressionMerger _merger; + private IExpressionValidator _validator; + private LookAtEyeDirection _inputEyeDirection; + private LookAtEyeDirection _actualEyeDirection; + private ILookAtEyeDirectionProvider _eyeDirectionProvider; + private ILookAtEyeDirectionApplicable _eyeDirectionApplicable; + + public IReadOnlyList ExpressionKeys => _keys; + public IReadOnlyDictionary ActualWeights => _actualWeights; + public LookAtEyeDirection ActualEyeDirection => _actualEyeDirection; + public float BlinkOverrideRate { get; private set; } + public float LookAtOverrideRate { get; private set; } + public float MouthOverrideRate { get; private set; } + + int m_debugCount; + + internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionProvider eyeDirectionProvider, ILookAtEyeDirectionApplicable eyeDirectionApplicable) + { + Restore(); + + _merger = new ExpressionMerger(target.Vrm.Expression, target.transform); + _keys = target.Vrm.Expression.Clips.Select(x => target.Vrm.Expression.CreateKey(x.Clip)).ToList(); + var oldInputWeights = _inputWeights; + _inputWeights = _keys.ToDictionary(x => x, x => 0f); + foreach (var key in _keys) + { + // remain user input weights. + if (oldInputWeights.ContainsKey(key)) _inputWeights[key] = oldInputWeights[key]; + } + _actualWeights = _keys.ToDictionary(x => x, x => 0f); + _validator = ExpressionValidatorFactory.Create(target.Vrm.Expression); + _eyeDirectionProvider = eyeDirectionProvider; + _eyeDirectionApplicable = eyeDirectionApplicable; + } + + internal void Restore() + { + _merger?.RestoreMaterialInitialValues(); + _merger = null; + + _eyeDirectionApplicable?.Restore(); + _eyeDirectionApplicable = null; + } + + public void Process() + { + Apply(); + } + + public IDictionary GetWeights() + { + return _inputWeights; + } + + public float GetWeight(ExpressionKey expressionKey) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + return _inputWeights[expressionKey]; + } + + return 0f; + } + + public LookAtEyeDirection GetEyeDirection() + { + return _inputEyeDirection; + } + + public void SetWeights(IEnumerable> weights) + { + foreach (var (expressionKey, weight) in weights.Select(kv => (kv.Key, kv.Value))) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + _inputWeights[expressionKey] = weight; + } + } + Apply(); + } + + public void SetWeight(ExpressionKey expressionKey, float weight) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + _inputWeights[expressionKey] = weight; + } + Apply(); + } + + /// + /// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。 + /// この際、LookAt の情報を pull してそれも適用する。 + /// + private void Apply() + { + // 1. Get eye direction from provider. + _inputEyeDirection = _eyeDirectionProvider?.EyeDirection ?? default; + + // 2. Validate user input, and Output as actual weights. + _validator.Validate(_inputWeights, _actualWeights, + _inputEyeDirection, out _actualEyeDirection, + out var blink, out var lookAt, out var mouth); + + // 3. Set eye direction expression weights or any other side-effects (ex. eye bone). + _eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights); + + // 4. Set actual weights to raw blendshapes. + _merger.SetValues(_actualWeights); + + BlinkOverrideRate = blink; + LookAtOverrideRate = lookAt; + MouthOverrideRate = mouth; + } + } +} diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs.meta b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs.meta new file mode 100644 index 000000000..ac7366f41 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c644583b448f6e743a6d2a55d1d617bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs new file mode 100644 index 000000000..c23e9d14b --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs @@ -0,0 +1,127 @@ +using System; +using UniGLTF.Extensions.VRMC_vrm; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + public class Vrm10RuntimeLookAt: ILookAtEyeDirectionProvider + { + VRM10ObjectLookAt m_lookat; + + private Transform m_head; + private Transform m_leftEye; + private Transform m_rightEye; + private ILookAtEyeDirectionApplicable _eyeDirectionApplicable; + + internal ILookAtEyeDirectionApplicable EyeDirectionApplicable => _eyeDirectionApplicable; + + public LookAtEyeDirection EyeDirection { get; private set; } + + #region LookAtTargetTypes.CalcYawPitchToGaze + // 座標計算用のempty + Transform m_lookAtOrigin; + public Transform GetLookAtOrigin(Transform head) + { + if (!Application.isPlaying) + { + return null; + } + if (m_lookAtOrigin == null) + { + m_lookAtOrigin = new GameObject("_lookat_origin_").transform; + m_lookAtOrigin.SetParent(head); + } + return m_lookAtOrigin; + } + + /// + /// Headローカルの注視点からYaw, Pitch角を計算する + /// + (float, float) CalcLookAtYawPitch(Vector3 targetWorldPosition, Transform head) + { + GetLookAtOrigin(head).localPosition = m_lookat.OffsetFromHead; + + var localPosition = m_lookAtOrigin.worldToLocalMatrix.MultiplyPoint(targetWorldPosition); + float yaw, pitch; + Matrix4x4.identity.CalcYawPitch(localPosition, out yaw, out pitch); + return (yaw, pitch); + } + #endregion + + #region LookAtTargetTypes.SetYawPitch + float m_yaw; + float m_pitch; + + /// + /// LookAtTargetTypes.SetYawPitch時の視線の角度を指定する + /// + /// Headボーンのforwardに対するyaw角(度) + /// Headボーンのforwardに対するpitch角(度) + public void SetLookAtYawPitch(float yaw, float pitch) + { + m_yaw = yaw; + m_pitch = pitch; + } + #endregion + + /// + /// LookAtTargetType に応じた yaw, pitch を得る + /// + /// Headボーンのforwardに対するyaw角(度), pitch角(度) + public (float, float) GetLookAtYawPitch(Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze) + { + switch (lookAtTargetType) + { + case VRM10ObjectLookAt.LookAtTargetTypes.CalcYawPitchToGaze: + // Gaze(Transform)のワールド位置に対して計算する + return CalcLookAtYawPitch(gaze.position, head); + + case VRM10ObjectLookAt.LookAtTargetTypes.SetYawPitch: + // 事前にSetYawPitchした値を使う + return (m_yaw, m_pitch); + } + + throw new NotImplementedException(); + } + + internal Vrm10RuntimeLookAt(VRM10ObjectLookAt lookat, Animator animator, Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze) + { + m_lookat = lookat; + + m_head = head; + m_leftEye = animator.GetBoneTransform(HumanBodyBones.LeftEye); + m_rightEye = animator.GetBoneTransform(HumanBodyBones.RightEye); + + var isRuntimeAsset = true; +#if UNITY_EDITOR + isRuntimeAsset = Application.isPlaying && !PrefabUtility.IsPartOfAnyPrefab(m_head); +#endif + if (isRuntimeAsset && lookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.CalcYawPitchToGaze && gaze == null) + { + gaze = new GameObject().transform; + gaze.name = "__LOOKAT_GAZE__"; + gaze.SetParent(m_head); + gaze.localPosition = Vector3.forward; + } + switch (m_lookat.LookAtType) + { + case LookAtType.bone: + _eyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(m_leftEye, m_rightEye, m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp); + break; + case LookAtType.expression: + _eyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void Process(VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze) + { + var (yaw, pitch) = GetLookAtYawPitch(m_head, lookAtTargetType, gaze); + EyeDirection = new LookAtEyeDirection(yaw, pitch, 0, 0); + } + + } +} diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs.meta b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs.meta new file mode 100644 index 000000000..2a02c607a --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08fd3fec20846764dbb598cf75b13356 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Tests/ExpressionTests.cs b/Assets/VRM10/Tests/ExpressionTests.cs index 73d754d85..d176cb3e9 100644 --- a/Assets/VRM10/Tests/ExpressionTests.cs +++ b/Assets/VRM10/Tests/ExpressionTests.cs @@ -32,7 +32,7 @@ namespace UniVRM10.Test controller.Vrm.Expression.Aa.MaterialColorBindings = src.ToArray(); // ok if no exception - var r = new Vrm10InstanceRuntime(controller); + var r = new Vrm10Runtime(controller); } [Test] @@ -56,7 +56,7 @@ namespace UniVRM10.Test controller.Vrm.Expression.Aa.MaterialUVBindings = src.ToArray(); // ok if no exception - var r = new Vrm10InstanceRuntime(controller); + var r = new Vrm10Runtime(controller); } } } diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10AIUEO.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10AIUEO.cs index b4739145d..95f003ef3 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10AIUEO.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10AIUEO.cs @@ -30,17 +30,17 @@ namespace UniVRM10.VRM10Viewer { for (var value = 0.0f; value <= 1.0f; value += velocity) { - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); yield return null; } - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 1.0f); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 1.0f); yield return new WaitForSeconds(wait); for (var value = 1.0f; value >= 0; value -= velocity) { - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); yield return null; } - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 0); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 0); yield return new WaitForSeconds(wait * 2); } diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10AutoExpression.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10AutoExpression.cs index 7a70f4f6c..c798d7d13 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10AutoExpression.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10AutoExpression.cs @@ -33,17 +33,17 @@ namespace UniVRM10.VRM10Viewer { for (var value = 0.0f; value <= 1.0f; value += velocity) { - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); yield return null; } - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 1.0f); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 1.0f); yield return new WaitForSeconds(wait); for (var value = 1.0f; value >= 0; value -= velocity) { - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value); yield return null; } - Controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 0); + Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 0); yield return new WaitForSeconds(wait * 2); } diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10Blinker.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10Blinker.cs index b1f51b32d..6e36913ac 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10Blinker.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10Blinker.cs @@ -72,10 +72,10 @@ namespace UniVRM10.VRM10Viewer break; } - m_controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), value); + m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), value); yield return null; } - m_controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), 1.0f); + m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), 1.0f); // wait... yield return new WaitForSeconds(ClosingTime); @@ -91,10 +91,10 @@ namespace UniVRM10.VRM10Viewer break; } - m_controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), value); + m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), value); yield return null; } - m_controller.Vrm.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), 0); + m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), 0); } } diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs index 8a8ca682a..7b56b4676 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs @@ -450,6 +450,9 @@ namespace UniVRM10.VRM10Viewer ct: cancellationToken); if (vrm10Instance != null) { + // test. error にならなければよい + vrm10Instance.Runtime.Expression.SetWeight(ExpressionKey.Aa, 0); + if (cancellationToken.IsCancellationRequested) { UnityObjectDestoyer.DestroyRuntimeOrEditor(vrm10Instance.gameObject);