From a3afd483d04b0e85fbbc5b5180b0bce7b0e5472d Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 15:54:13 +0900 Subject: [PATCH] Define ExpressionValidator instead of ExpressionAccumulator --- .../Components/VRM10ControllerEditor.cs | 14 +-- .../Expression/DefaultExpressionValidator.cs | 34 +++++++ .../DefaultExpressionValidator.cs.meta | 3 + .../Expression/IExpressionValidator.cs | 15 +++ .../Expression/IExpressionValidator.cs.meta | 3 + .../Expression/IExpressionValidatorFactory.cs | 7 ++ .../IExpressionValidatorFactory.cs.meta | 3 + .../SpringBone/VRM10SpringBoneManager.cs | 2 +- .../Runtime/Components/VRM10Controller.cs | 12 +-- .../Components/VRM10ControllerExpression.cs | 94 ++++++++++++++----- .../Components/VRM10ControllerLookAt.cs | 36 +++---- 11 files changed, 170 insertions(+), 53 deletions(-) create mode 100644 Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs create mode 100644 Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta create mode 100644 Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs create mode 100644 Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta create mode 100644 Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs create mode 100644 Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta diff --git a/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs b/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs index 57d3fd57b..5190aca3a 100644 --- a/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs +++ b/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs @@ -2,7 +2,7 @@ using UnityEditor; using UnityEngine; using System.Linq; -using System; +using VrmLib; namespace UniVRM10 { @@ -176,11 +176,13 @@ namespace UniVRM10 void ExpressionGUI() { EditorGUILayout.Space(); - EditorGUILayout.LabelField("IgnoreStatus", EditorStyles.boldLabel); + EditorGUILayout.LabelField("Override weights", EditorStyles.boldLabel); EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.Toggle("Ignore Blink", m_target.Expression.Accumulator.IgnoreBlink); - EditorGUILayout.Toggle("Ignore Look At", m_target.Expression.Accumulator.IgnoreLookAt); - EditorGUILayout.Toggle("Ignore Mouth", m_target.Expression.Accumulator.IgnoreMouth); + { + EditorGUILayout.Slider("Blink override weight", m_target.Expression.OverrideBlinkWeight, 0f, 1f); + EditorGUILayout.Slider("LookAt override weight", m_target.Expression.OverrideLookAtWeight, 0f, 1f); + EditorGUILayout.Slider("Mouth override weight", m_target.Expression.OverrideMouthWeight, 0f, 1f); + } EditorGUI.EndDisabledGroup(); if (!Application.isPlaying) @@ -200,7 +202,7 @@ namespace UniVRM10 { m_expressionKeyWeights[slider.Key] = slider.Value; } - m_target.Expression.Accumulator.SetValues(m_expressionKeyWeights.Select(x => new KeyValuePair(x.Key, x.Value))); + m_target.Expression.SetWeights(m_expressionKeyWeights); } } diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs new file mode 100644 index 000000000..e06fb2381 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using VrmLib; + +namespace UniVRM10 +{ + public sealed class DefaultExpressionValidator : IExpressionValidator + { + private DefaultExpressionValidator(VRM10ExpressionAvatar expressionAvatar) + { + + } + + public void Validate(IReadOnlyDictionary inputWeights, IDictionary actualWeights) + { + foreach (var (key, weight) in inputWeights) + { + if (!actualWeights.ContainsKey(key)) + { + actualWeights.Add(key, weight); + } + + actualWeights[key] = weight; + } + } + + public sealed class Factory : IExpressionValidatorFactory + { + public IExpressionValidator Create(VRM10ExpressionAvatar expressionAvatar) + { + return new DefaultExpressionValidator(expressionAvatar); + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta new file mode 100644 index 000000000..0e09d4c4c --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 50fc6f6edac946548edb751de64c1cb1 +timeCreated: 1611916405 \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs new file mode 100644 index 000000000..8f6aad267 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace UniVRM10 +{ + /// + /// Validate Expression constraints (ex. overrideBlink) + /// + public interface IExpressionValidator + { + /// + /// Validate input weights with Expression constraints. + /// + void Validate(IReadOnlyDictionary inputWeights, IDictionary actualWeights); + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta new file mode 100644 index 000000000..aa7e7bed7 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1de32ec5101c48298bb78d6835b5d4e2 +timeCreated: 1611916321 \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs new file mode 100644 index 000000000..2f4a523cc --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs @@ -0,0 +1,7 @@ +namespace UniVRM10 +{ + public interface IExpressionValidatorFactory + { + IExpressionValidator Create(VRM10ExpressionAvatar expressionAvatar); + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta new file mode 100644 index 000000000..6e71a2826 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a46e9573ca04d098b71780a849cd30e +timeCreated: 1611916369 \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneManager.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneManager.cs index 1eea53e46..527778f37 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneManager.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneManager.cs @@ -25,7 +25,7 @@ namespace UniVRM10 /// /// 1フレームに一回呼び出す(VRM10Controllerの仕事) /// - public void Process() + internal void Process() { foreach (var spring in Springs) { diff --git a/Assets/VRM10/Runtime/Components/VRM10Controller.cs b/Assets/VRM10/Runtime/Components/VRM10Controller.cs index a08fb544e..973dfa3b2 100644 --- a/Assets/VRM10/Runtime/Components/VRM10Controller.cs +++ b/Assets/VRM10/Runtime/Components/VRM10Controller.cs @@ -98,7 +98,7 @@ namespace UniVRM10 private void Start() { - Expression.OnStart(transform); + Expression.Setup(transform); // get lookat origin var animator = GetComponent(); @@ -118,7 +118,7 @@ namespace UniVRM10 /// * Expression /// /// - public void Apply() + public void Process() { // // constraint @@ -140,19 +140,19 @@ namespace UniVRM10 // // gaze control // - LookAt.Process(Head, Expression.Accumulator.SetPresetValue); + LookAt.Process(Head, Expression.SetWeights); // // expression // - Expression.Apply(); + Expression.Process(); } private void Update() { if (Controller.UpdateType == VRM10ControllerImpl.UpdateTypes.Update) { - Apply(); + Process(); } } @@ -160,7 +160,7 @@ namespace UniVRM10 { if (Controller.UpdateType == VRM10ControllerImpl.UpdateTypes.LateUpdate) { - Apply(); + Process(); } } diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs index 94b0beece..d4ecfd489 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs @@ -1,54 +1,100 @@ using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; +using VrmLib; namespace UniVRM10 { [Serializable] - public class VRM10ControllerExpression : IDisposable + public sealed class VRM10ControllerExpression : IDisposable { + public static IExpressionValidatorFactory ExpressionValidatorFactory = new DefaultExpressionValidator.Factory(); + [SerializeField] public VRM10ExpressionAvatar ExpressionAvatar; - ExpressionMerger m_merger; + private List _keys = new List(); + private Dictionary _inputWeights = new Dictionary(); + private Dictionary _actualWeights = new Dictionary(); + private ExpressionMerger _merger; + private IExpressionValidator _validator; + public IReadOnlyList ExpressionKeys => _keys; + public IReadOnlyDictionary ActualWeights => _actualWeights; + + public float OverrideBlinkWeight { get; private set; } + public float OverrideLookAtWeight { get; private set; } + public float OverrideMouthWeight { get; private set; } + public void Dispose() { - if (m_merger != null) - { - m_merger.RestoreMaterialInitialValues(); - } + _merger?.RestoreMaterialInitialValues(); } - IExpressionAccumulator m_accumulator; - - public IExpressionAccumulator Accumulator + internal void Setup(Transform transform) { - get + if (ExpressionAvatar == null) { - if (m_accumulator == null) + Debug.LogError($"{nameof(VRM10ControllerExpression)}.{nameof(ExpressionAvatar)} is null."); + return; + } + + _merger = new ExpressionMerger(ExpressionAvatar.Clips, transform); + _keys = ExpressionAvatar.Clips.Select(ExpressionKey.CreateFromClip).ToList(); + _inputWeights = _keys.ToDictionary(x => x, x => 0f); + _actualWeights = _keys.ToDictionary(x => x, x => 0f); + _validator = ExpressionValidatorFactory.Create(ExpressionAvatar); + } + + internal void Process() + { + + } + + public IDictionary GetWeights() + { + return _inputWeights; + } + + public float GetWeight(ExpressionKey expressionKey) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + return _inputWeights[expressionKey]; + } + + return 0f; + } + + public void SetWeights(IEnumerable> weights) + { + foreach (var (expressionKey, weight) in weights) + { + if (_inputWeights.ContainsKey(expressionKey)) { - m_accumulator = new DefaultExpressionAccumulator(); + _inputWeights[expressionKey] = weight; } - return m_accumulator; } + Apply(); } - public void OnStart(Transform transform) + public void SetWeight(ExpressionKey expressionKey, float weight) { - if (ExpressionAvatar != null) + if (_inputWeights.ContainsKey(expressionKey)) { - if (m_merger == null) - { - m_merger = new ExpressionMerger(ExpressionAvatar.Clips, transform); - } - - Accumulator.OnStart(ExpressionAvatar); + _inputWeights[expressionKey] = weight; } + Apply(); } - - public void Apply() + + /// + /// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。 + /// + private void Apply() { - m_merger.SetValues(m_accumulator.FrameExpression()); + _validator.Validate(_inputWeights, _actualWeights); + _merger.SetValues(_actualWeights); } } } diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs index dda4df4c5..6baa9eba6 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using UnityEngine; +using VrmLib; #if UNITY_EDITOR using UnityEditor; #endif @@ -49,6 +51,10 @@ namespace UniVRM10 OffsetOnTransform m_leftEye; OffsetOnTransform m_rightEye; + ExpressionKey m_lookRightKey = ExpressionKey.CreateFromPreset(ExpressionPreset.LookRight); + ExpressionKey m_lookLeftKey = ExpressionKey.CreateFromPreset(ExpressionPreset.LookLeft); + ExpressionKey m_lookUpKey = ExpressionKey.CreateFromPreset(ExpressionPreset.LookUp); + ExpressionKey m_lookDownKey = ExpressionKey.CreateFromPreset(ExpressionPreset.LookDown); #region LookAtTargetTypes.CalcYawPitchToGaze /// @@ -160,43 +166,41 @@ namespace UniVRM10 } } - public delegate void SetPresetValue(VrmLib.ExpressionPreset preset, float weight); + public delegate void SetExpressionWeights(IEnumerable> weights); /// - /// Expression による LookAt を処理する(関連する Expression の Weight を変更する) + /// Expression による LookAt の Weight を計算する /// - /// - /// - void LookAtExpression(float yaw, float pitch, SetPresetValue SetPresetValue) + private IEnumerable> GetLookAtExpressionEnumerable(float yaw, float pitch) { if (yaw < 0) { // Left - SetPresetValue(VrmLib.ExpressionPreset.LookRight, 0); // clear first - SetPresetValue(VrmLib.ExpressionPreset.LookLeft, Mathf.Clamp(HorizontalOuter.Map(-yaw), 0, 1.0f)); + yield return new KeyValuePair(m_lookRightKey, 0); + yield return new KeyValuePair(m_lookLeftKey, Mathf.Clamp(HorizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f)); } else { // Right - SetPresetValue(VrmLib.ExpressionPreset.LookLeft, 0); // clear first - SetPresetValue(VrmLib.ExpressionPreset.LookRight, Mathf.Clamp(HorizontalOuter.Map(yaw), 0, 1.0f)); + yield return new KeyValuePair(m_lookRightKey, Mathf.Clamp(HorizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f)); + yield return new KeyValuePair(m_lookLeftKey, 0); } if (pitch < 0) { // Down - SetPresetValue(VrmLib.ExpressionPreset.LookUp, 0); // clear first - SetPresetValue(VrmLib.ExpressionPreset.LookDown, Mathf.Clamp(VerticalDown.Map(-pitch), 0, 1.0f)); + yield return new KeyValuePair(m_lookUpKey, 0); + yield return new KeyValuePair(m_lookDownKey, Mathf.Clamp(VerticalDown.Map(Mathf.Abs(pitch)), 0, 1.0f)); } else { // Up - SetPresetValue(VrmLib.ExpressionPreset.LookDown, 0); // clear first - SetPresetValue(VrmLib.ExpressionPreset.LookUp, Mathf.Clamp(VerticalUp.Map(pitch), 0, 1.0f)); + yield return new KeyValuePair(m_lookUpKey, Mathf.Clamp(VerticalUp.Map(Mathf.Abs(pitch)), 0, 1.0f)); + yield return new KeyValuePair(m_lookDownKey, 0); } } - public void Setup(Animator animator, Transform head) + internal void Setup(Animator animator, Transform head) { m_leftEye = OffsetOnTransform.Create(animator.GetBoneTransform(HumanBodyBones.LeftEye)); m_rightEye = OffsetOnTransform.Create(animator.GetBoneTransform(HumanBodyBones.RightEye)); @@ -209,7 +213,7 @@ namespace UniVRM10 } } - public void Process(Transform head, SetPresetValue setPresetValue) + internal void Process(Transform head, SetExpressionWeights setExpressionWeights) { var (yaw, pitch) = GetLookAtYawPitch(head); @@ -220,7 +224,7 @@ namespace UniVRM10 break; case LookAtTypes.Expression: - LookAtExpression(yaw, pitch, setPresetValue); + setExpressionWeights(GetLookAtExpressionEnumerable(yaw, pitch)); break; } }