From 0c5d6aae17477ef58551020d6af4838678b03a63 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 20:32:06 +0900 Subject: [PATCH 1/9] Restore eye bone when ExpressionController was disposed. --- .../ILookAtEyeDirectionApplicable.cs | 1 + .../Expression/LookAtEyeDirection.cs | 15 +++++++++++++ .../LookAtEyeDirectionApplicableToBone.cs | 22 ++++++++++++++----- ...ookAtEyeDirectionApplicableToExpression.cs | 4 ++++ .../Components/VRM10ControllerExpression.cs | 1 + 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs b/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs index 3c2924369..27d7c7846 100644 --- a/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs +++ b/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs @@ -8,5 +8,6 @@ namespace UniVRM10 internal interface ILookAtEyeDirectionApplicable { IEnumerable> Apply(LookAtEyeDirection eyeDirection); + void Restore(); } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs b/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs index 276ae3149..02ffd9359 100644 --- a/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs +++ b/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs @@ -2,9 +2,24 @@ { public readonly struct LookAtEyeDirection { + /// + /// Yaw of LeftEye + /// public float LeftYaw { get; } + + /// + /// Pitch of LeftEye + /// public float LeftPitch { get; } + + /// + /// Yaw of RightEye + /// public float RightYaw { get; } + + /// + /// Pitch of RightEye + /// public float RightPitch { get; } public LookAtEyeDirection(float leftYaw, float leftPitch, float rightYaw, float rightPitch) diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs index 2eed15cad..0c667cc87 100644 --- a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs @@ -28,6 +28,7 @@ namespace UniVRM10 /// public IEnumerable> Apply(LookAtEyeDirection eyeDirection) { + // FIXME var yaw = eyeDirection.LeftYaw; var pitch = eyeDirection.LeftPitch; @@ -55,14 +56,23 @@ namespace UniVRM10 } // Apply - if (_leftEye != null && _rightEye != null) - { - // 目に値を適用する - _leftEye.localRotation = Matrix4x4.identity.YawPitchRotation(leftYaw, pitch); - _rightEye.localRotation = Matrix4x4.identity.YawPitchRotation(rightYaw, pitch); - } + SetYawPitchToBones(new LookAtEyeDirection(leftYaw, pitch, rightYaw, pitch)); yield break; } + + public void Restore() + { + SetYawPitchToBones(new LookAtEyeDirection(0, 0, 0, 0)); + } + + private void SetYawPitchToBones(LookAtEyeDirection actualEyeDirection) + { + if (_leftEye != null && _rightEye != null) + { + _leftEye.localRotation = Matrix4x4.identity.YawPitchRotation(actualEyeDirection.LeftYaw, actualEyeDirection.LeftPitch); + _rightEye.localRotation = Matrix4x4.identity.YawPitchRotation(actualEyeDirection.RightYaw, actualEyeDirection.RightPitch); + } + } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs index 573494e12..be5589d69 100644 --- a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs @@ -56,5 +56,9 @@ namespace UniVRM10 yield return new KeyValuePair(_lookDownKey, 0); } } + + public void Restore() + { + } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs index b6472d6a9..bbe31c675 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs @@ -34,6 +34,7 @@ namespace UniVRM10 public void Dispose() { _merger?.RestoreMaterialInitialValues(); + _eyeDirectionApplicable?.Restore(); } internal void Setup(Transform transform, ILookAtEyeDirectionProvider eyeDirectionProvider, ILookAtEyeDirectionApplicable eyeDirectionApplicable) From 0341725770cc1e073580a15281e4d607dc1fc445 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 22:29:42 +0900 Subject: [PATCH 2/9] Implements expression overriding https://github.com/vrm-c/vrm-specification/pull/196 --- .../Components/VRM10ControllerEditor.cs | 24 ++++-- .../Expression/DefaultExpressionValidator.cs | 84 ++++++++++++++++--- .../Expression/LookAtEyeDirection.cs | 10 +++ .../Runtime/Components/VRM10Controller.cs | 5 +- .../Components/VRM10ControllerExpression.cs | 27 ++++-- .../Components/VRM10ControllerLookAt.cs | 7 +- 6 files changed, 129 insertions(+), 28 deletions(-) diff --git a/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs b/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs index e77875e49..8e4c425d3 100644 --- a/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs +++ b/Assets/VRM10/Editor/Components/VRM10ControllerEditor.cs @@ -136,6 +136,9 @@ namespace UniVRM10 } serializedObject.Update(); + + // Setup runtime function. + m_target.Setup(); // base.OnInspectorGUI(); switch (_tab) @@ -176,14 +179,6 @@ namespace UniVRM10 void ExpressionGUI() { EditorGUILayout.Space(); - EditorGUILayout.LabelField("Override rates", EditorStyles.boldLabel); - EditorGUI.BeginDisabledGroup(true); - { - EditorGUILayout.Slider("Blink override rate", m_target.Expression.BlinkOverrideRate, 0f, 1f); - EditorGUILayout.Slider("LookAt override rate", m_target.Expression.LookAtOverrideRate, 0f, 1f); - EditorGUILayout.Slider("Mouth override rate", m_target.Expression.MouthOverrideRate, 0f, 1f); - } - EditorGUI.EndDisabledGroup(); if (!Application.isPlaying) { @@ -197,6 +192,9 @@ namespace UniVRM10 if (m_sliders != null) { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Expression Weights", EditorStyles.boldLabel); + var sliders = m_sliders.Select(x => x.Slider()); foreach (var slider in sliders) { @@ -204,6 +202,16 @@ namespace UniVRM10 } m_target.Expression.SetWeights(m_expressionKeyWeights); } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Override rates", EditorStyles.boldLabel); + EditorGUI.BeginDisabledGroup(true); + { + EditorGUILayout.Slider("Blink override rate", m_target.Expression.BlinkOverrideRate, 0f, 1f); + EditorGUILayout.Slider("LookAt override rate", m_target.Expression.LookAtOverrideRate, 0f, 1f); + EditorGUILayout.Slider("Mouth override rate", m_target.Expression.MouthOverrideRate, 0f, 1f); + } + EditorGUI.EndDisabledGroup(); } void OnSceneGUI() diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs index de6aa8de0..e3bdb3a8b 100644 --- a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -1,37 +1,101 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; using VrmLib; namespace UniVRM10 { public sealed class DefaultExpressionValidator : IExpressionValidator { + private readonly Dictionary _expressions; + private DefaultExpressionValidator(VRM10ExpressionAvatar expressionAvatar) { - + _expressions = expressionAvatar.Clips.ToDictionary(ExpressionKey.CreateFromClip, x => x); } public void Validate(IReadOnlyDictionary inputWeights, IDictionary actualWeights, LookAtEyeDirection inputEyeDirection, out LookAtEyeDirection actualEyeDirection, out float blinkOverrideRate, out float lookAtOverrideRate, out float mouthOverrideRate) { - // weights + // override rate + blinkOverrideRate = 0f; + lookAtOverrideRate = 0f; + mouthOverrideRate = 0f; + + // 1. Set weights and Accumulate override rates. foreach (var (key, weight) in inputWeights) { if (!actualWeights.ContainsKey(key)) { actualWeights.Add(key, weight); } - + // Set weight. actualWeights[key] = weight; + + // Get expression. + if (!_expressions.ContainsKey(key)) continue; + var expression = _expressions[key]; + + // Override rate without targeting myself. + if (!key.IsBlink) + { + blinkOverrideRate = Mathf.Max(blinkOverrideRate, GetOverrideRate(expression.OverrideBlink, weight)); + } + if (!key.IsLookAt) + { + lookAtOverrideRate = Mathf.Max(lookAtOverrideRate, GetOverrideRate(expression.OverrideLookAt, weight)); + } + if (!key.IsMouth) + { + mouthOverrideRate = Mathf.Max(mouthOverrideRate, GetOverrideRate(expression.OverrideMouth, weight)); + } } - // eye direction - actualEyeDirection = inputEyeDirection; + // 2. Saturate rate. + blinkOverrideRate = Mathf.Clamp01(blinkOverrideRate); + lookAtOverrideRate = Mathf.Clamp01(lookAtOverrideRate); + mouthOverrideRate = Mathf.Clamp01(mouthOverrideRate); - // override rate - blinkOverrideRate = 0f; - lookAtOverrideRate = 0f; - mouthOverrideRate = 0f; + var blinkMultiplier = 1f - blinkOverrideRate; + var lookAtMultiplier = 1f - lookAtOverrideRate; + var mouthMultiplier = 1f - mouthOverrideRate; + + // 3. Set procedural key's weights. + foreach (var (key, weight) in inputWeights) + { + if (key.IsBlink) + { + actualWeights[key] = weight * blinkMultiplier; + } + else if (key.IsLookAt) + { + actualWeights[key] = weight * lookAtMultiplier; + } + else if (key.IsMouth) + { + actualWeights[key] = weight * mouthMultiplier; + } + } + + // 4. eye direction + actualEyeDirection = LookAtEyeDirection.Multiply(inputEyeDirection, 1f - lookAtOverrideRate); + } + + private float GetOverrideRate(ExpressionOverrideType type, float weight) + { + switch (type) + { + case ExpressionOverrideType.None: + return 0f; + case ExpressionOverrideType.Block: + return 1f; + case ExpressionOverrideType.Blend: + return weight; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } } public sealed class Factory : IExpressionValidatorFactory diff --git a/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs b/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs index 02ffd9359..e3d486f41 100644 --- a/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs +++ b/Assets/VRM10/Runtime/Components/Expression/LookAtEyeDirection.cs @@ -29,5 +29,15 @@ RightYaw = rightYaw; RightPitch = rightPitch; } + + public static LookAtEyeDirection Multiply(LookAtEyeDirection a, float b) + { + return new LookAtEyeDirection( + a.LeftYaw * b, + a.LeftPitch * b, + a.RightYaw * b, + a.RightPitch * b + ); + } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/VRM10Controller.cs b/Assets/VRM10/Runtime/Components/VRM10Controller.cs index 5456ddf0b..1a5dd1781 100644 --- a/Assets/VRM10/Runtime/Components/VRM10Controller.cs +++ b/Assets/VRM10/Runtime/Components/VRM10Controller.cs @@ -52,7 +52,10 @@ namespace UniVRM10 void OnDestroy() { - Expression.Dispose(); + if (Expression != null) + { + Expression.Restore(); + } if (ModelAsset != null) { diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs index bbe31c675..9c3dffe8e 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs @@ -7,7 +7,7 @@ using VrmLib; namespace UniVRM10 { [Serializable] - public sealed class VRM10ControllerExpression : IDisposable + public sealed class VRM10ControllerExpression { public static IExpressionValidatorFactory ExpressionValidatorFactory = new DefaultExpressionValidator.Factory(); @@ -31,12 +31,6 @@ namespace UniVRM10 public float LookAtOverrideRate { get; private set; } public float MouthOverrideRate { get; private set; } - public void Dispose() - { - _merger?.RestoreMaterialInitialValues(); - _eyeDirectionApplicable?.Restore(); - } - internal void Setup(Transform transform, ILookAtEyeDirectionProvider eyeDirectionProvider, ILookAtEyeDirectionApplicable eyeDirectionApplicable) { if (ExpressionAvatar == null) @@ -45,14 +39,31 @@ namespace UniVRM10 return; } + Restore(); + _merger = new ExpressionMerger(ExpressionAvatar.Clips, transform); _keys = ExpressionAvatar.Clips.Select(ExpressionKey.CreateFromClip).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(ExpressionAvatar); _eyeDirectionProvider = eyeDirectionProvider; _eyeDirectionApplicable = eyeDirectionApplicable; } + + internal void Restore() + { + _merger?.RestoreMaterialInitialValues(); + _merger = null; + + _eyeDirectionApplicable?.Restore(); + _eyeDirectionApplicable = null; + } public void Process() { @@ -107,7 +118,7 @@ namespace UniVRM10 private void Apply() { // 1. Get eye direction from provider. - _inputEyeDirection = _eyeDirectionProvider.EyeDirection; + _inputEyeDirection = _eyeDirectionProvider?.EyeDirection ?? default; // 2. Validate user input, and Output as actual weights. _validator.Validate(_inputWeights, _actualWeights, diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs index 16cfd9d95..dff543430 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerLookAt.cs @@ -136,7 +136,12 @@ namespace UniVRM10 m_head = head; m_leftEye = animator.GetBoneTransform(HumanBodyBones.LeftEye); m_rightEye = animator.GetBoneTransform(HumanBodyBones.RightEye); - if (Gaze == null) + + 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__"; From aec86eae4c1ac2f09f4c894a3d8d5ce1e5798de6 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 22:45:50 +0900 Subject: [PATCH 3/9] Remove unused classes. --- .../Expression/ExpressionAccumulator.cs | 150 ------------------ .../Expression/ExpressionAccumulator.cs.meta | 11 -- .../Expression/IExpressionAccumulator.cs | 58 ------- .../Expression/IExpressionAccumulator.cs.meta | 11 -- 4 files changed, 230 deletions(-) delete mode 100644 Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs delete mode 100644 Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs.meta delete mode 100644 Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs delete mode 100644 Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs.meta diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs deleted file mode 100644 index ac798fd6a..000000000 --- a/Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace UniVRM10 -{ - public class DefaultExpressionAccumulator : IExpressionAccumulator - { - Dictionary m_clipMap; - - Dictionary expressionKeyWeights = new Dictionary(); - - public bool IgnoreBlink { get; private set; } - public bool IgnoreLookAt { get; private set; } - public bool IgnoreMouth { get; private set; } - - /// - /// initilaize - /// - /// - public void OnStart(VRM10ExpressionAvatar avatar) - { - m_clipMap = avatar.Clips.ToDictionary(x => ExpressionKey.CreateFromClip(x), x => x); - expressionKeyWeights = m_clipMap.Keys.ToDictionary(x => x, x => 0.0f); - } - - /// - /// each frame - /// - /// - public IEnumerable> FrameExpression() - { - IgnoreBlink = false; - IgnoreLookAt = false; - IgnoreMouth = false; - - // - // except blink, lookat, mouth - // - foreach (var kv in expressionKeyWeights) - { - if (kv.Key.IsProcedual) - { - // 後で - continue; - } - - var expression = m_clipMap[kv.Key]; - - if (expression.OverrideBlink == VrmLib.ExpressionOverrideType.Block && kv.Value > 0) - { - IgnoreBlink = true; - } - if (expression.OverrideLookAt == VrmLib.ExpressionOverrideType.Block && kv.Value > 0) - { - IgnoreLookAt = true; - } - if (expression.OverrideMouth == VrmLib.ExpressionOverrideType.Block && kv.Value > 0) - { - IgnoreMouth = true; - } - - yield return kv; - } - - // - // blink, lookat, mouth - // - foreach (var kv in expressionKeyWeights) - { - if (kv.Key.IsBlink) - { - if (IgnoreBlink) - { - // skip - continue; - } - } - else if (kv.Key.IsLookAt) - { - if (IgnoreLookAt) - { - // skip - continue; - } - } - else if (kv.Key.IsMouth) - { - if (IgnoreMouth) - { - // skip - continue; - } - } - else - { - // already return - continue; - } - - yield return kv; - } - } - - /// - /// Get a expression value - /// - /// - /// - public float GetValue(ExpressionKey key) - { - if (expressionKeyWeights.ContainsKey(key)) - { - return expressionKeyWeights[key]; - } - else - { - return 0.0f; - } - } - - public IEnumerable> GetValues() - { - return expressionKeyWeights.Select(x => new KeyValuePair(x.Key, x.Value)); - } - - /// - /// SetValue - /// - /// - /// - public void SetValue(ExpressionKey key, float value) - { - if (expressionKeyWeights.ContainsKey(key)) - { - expressionKeyWeights[key] = value; - } - } - - public void SetValues(IEnumerable> values) - { - foreach (var keyValue in values) - { - if (expressionKeyWeights.ContainsKey(keyValue.Key)) - { - expressionKeyWeights[keyValue.Key] = keyValue.Value; - } - } - } - } -} diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs.meta b/Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs.meta deleted file mode 100644 index ec83f3fab..000000000 --- a/Assets/VRM10/Runtime/Components/Expression/ExpressionAccumulator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bcb5bbef7ed54854d8041988a84fa827 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs b/Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs deleted file mode 100644 index 49c7301dc..000000000 --- a/Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Collections.Generic; - -namespace UniVRM10 -{ - /// - /// 1フレーム分の Expression を蓄える - /// - public interface IExpressionAccumulator - { - /// - /// 開始時に初期化する - /// - /// - void OnStart(VRM10ExpressionAvatar avatar); - - /// - /// 蓄えて処理(ignoreフラグなど)した結果を得る - /// - /// - IEnumerable> FrameExpression(); - - void SetValue(ExpressionKey key, float value); - void SetValues(IEnumerable> values); - float GetValue(ExpressionKey key); - IEnumerable> GetValues(); - - bool IgnoreBlink { get; } - bool IgnoreLookAt { get; } - bool IgnoreMouth { get; } - } - - public static class ExpressionAccumulatorExtensions - { - public static float GetPresetValue(this IExpressionAccumulator self, VrmLib.ExpressionPreset key) - { - var expressionKey = new ExpressionKey(key); - return self.GetValue(expressionKey); - } - - public static float GetCustomValue(this IExpressionAccumulator self, string key) - { - var expressionKey = ExpressionKey.CreateCustom(key); - return self.GetValue(expressionKey); - } - - public static void SetPresetValue(this IExpressionAccumulator self, VrmLib.ExpressionPreset key, float value) - { - var expressionKey = new ExpressionKey(key); - self.SetValue(expressionKey, value); - } - - public static void SetCustomValue(this IExpressionAccumulator self, string key, float value) - { - var expressionKey = ExpressionKey.CreateCustom(key); - self.SetValue(expressionKey, value); - } - } -} diff --git a/Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs.meta b/Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs.meta deleted file mode 100644 index c855193a0..000000000 --- a/Assets/VRM10/Runtime/Components/Expression/IExpressionAccumulator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fdd7cdf6d59574348bb7336272ef5edf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From 4ebcbb1ab91b0229e723a4cf601d68ebdcc49191 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 22:50:05 +0900 Subject: [PATCH 4/9] Consider block. --- .../Runtime/Components/Expression/DefaultExpressionValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs index e3bdb3a8b..16abb3060 100644 --- a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -90,7 +90,7 @@ namespace UniVRM10 case ExpressionOverrideType.None: return 0f; case ExpressionOverrideType.Block: - return 1f; + return weight > 0f ? 1f : 0f; case ExpressionOverrideType.Blend: return weight; default: From dd34a1e61504c5c0376e4792795ed1d41a1b4965 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 23:17:17 +0900 Subject: [PATCH 5/9] Suppress GC to zero about Expression functions. --- .../Expression/DefaultExpressionValidator.cs | 10 ++++++++-- .../Components/Expression/ExpressionMerger.cs | 9 +++++---- .../ILookAtEyeDirectionApplicable.cs | 2 +- .../LookAtEyeDirectionApplicableToBone.cs | 4 +--- ...LookAtEyeDirectionApplicableToExpression.cs | 18 +++++++++--------- .../Components/VRM10ControllerExpression.cs | 13 +------------ 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs index 16abb3060..3d4e93483 100644 --- a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -8,10 +8,12 @@ namespace UniVRM10 { public sealed class DefaultExpressionValidator : IExpressionValidator { + private readonly ExpressionKey[] _keys; private readonly Dictionary _expressions; private DefaultExpressionValidator(VRM10ExpressionAvatar expressionAvatar) { + _keys = expressionAvatar.Clips.Select(ExpressionKey.CreateFromClip).ToArray(); _expressions = expressionAvatar.Clips.ToDictionary(ExpressionKey.CreateFromClip, x => x); } @@ -25,8 +27,10 @@ namespace UniVRM10 mouthOverrideRate = 0f; // 1. Set weights and Accumulate override rates. - foreach (var (key, weight) in inputWeights) + foreach (var key in _keys) { + var weight = inputWeights[key]; + if (!actualWeights.ContainsKey(key)) { actualWeights.Add(key, weight); @@ -63,8 +67,10 @@ namespace UniVRM10 var mouthMultiplier = 1f - mouthOverrideRate; // 3. Set procedural key's weights. - foreach (var (key, weight) in inputWeights) + foreach (var key in _keys) { + var weight = inputWeights[key]; + if (key.IsBlink) { actualWeights[key] = weight * blinkMultiplier; diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index 2c345b432..3e6b8bfca 100644 --- a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +using VrmLib; namespace UniVRM10 @@ -38,12 +39,12 @@ namespace UniVRM10 /// /// まとめて反映する。1フレームに1回呼び出されることを想定 /// - /// - public void SetValues(IEnumerable> values) + /// + public void SetValues(Dictionary expressionWeights) { - foreach (var kv in values) + foreach (var (key, weight) in expressionWeights) { - AccumulateValue(kv.Key, kv.Value); + AccumulateValue(key, weight); } m_morphTargetBindingMerger.Apply(); diff --git a/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs b/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs index 27d7c7846..77bfcf6f7 100644 --- a/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs +++ b/Assets/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs @@ -7,7 +7,7 @@ namespace UniVRM10 /// internal interface ILookAtEyeDirectionApplicable { - IEnumerable> Apply(LookAtEyeDirection eyeDirection); + void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights); void Restore(); } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs index 0c667cc87..c29c7ea6b 100644 --- a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs @@ -26,7 +26,7 @@ namespace UniVRM10 /// /// LeftEyeボーンとRightEyeボーンに回転を適用する /// - public IEnumerable> Apply(LookAtEyeDirection eyeDirection) + public void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights) { // FIXME var yaw = eyeDirection.LeftYaw; @@ -57,8 +57,6 @@ namespace UniVRM10 // Apply SetYawPitchToBones(new LookAtEyeDirection(leftYaw, pitch, rightYaw, pitch)); - - yield break; } public void Restore() diff --git a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs index be5589d69..d6b27be14 100644 --- a/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs +++ b/Assets/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs @@ -25,7 +25,7 @@ namespace UniVRM10 _verticalUp = verticalUp; } - public IEnumerable> Apply(LookAtEyeDirection eyeDirection) + public void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights) { var yaw = eyeDirection.LeftYaw; var pitch = eyeDirection.LeftPitch; @@ -33,27 +33,27 @@ namespace UniVRM10 if (yaw < 0) { // Left - yield return new KeyValuePair(_lookRightKey, 0); - yield return new KeyValuePair(_lookLeftKey, Mathf.Clamp(_horizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f)); + actualWeights[_lookRightKey] = 0; + actualWeights[_lookLeftKey] = Mathf.Clamp(_horizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f); } else { // Right - yield return new KeyValuePair(_lookRightKey, Mathf.Clamp(_horizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f)); - yield return new KeyValuePair(_lookLeftKey, 0); + actualWeights[_lookRightKey] = Mathf.Clamp(_horizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f); + actualWeights[_lookLeftKey] = 0; } if (pitch < 0) { // Down - yield return new KeyValuePair(_lookUpKey, 0); - yield return new KeyValuePair(_lookDownKey, Mathf.Clamp(_verticalDown.Map(Mathf.Abs(pitch)), 0, 1.0f)); + actualWeights[_lookUpKey] = 0; + actualWeights[_lookDownKey] = Mathf.Clamp(_verticalDown.Map(Mathf.Abs(pitch)), 0, 1.0f); } else { // Up - yield return new KeyValuePair(_lookUpKey, Mathf.Clamp(_verticalUp.Map(Mathf.Abs(pitch)), 0, 1.0f)); - yield return new KeyValuePair(_lookDownKey, 0); + actualWeights[_lookUpKey] = Mathf.Clamp(_verticalUp.Map(Mathf.Abs(pitch)), 0, 1.0f); + actualWeights[_lookDownKey] = 0; } } diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs index 9c3dffe8e..c05bd0909 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs @@ -126,18 +126,7 @@ namespace UniVRM10 out var blink, out var lookAt, out var mouth); // 3. Set eye direction expression weights or any other side-effects (ex. eye bone). - if (_eyeDirectionApplicable != null) - { - foreach (var (expressionKey, weight) in _eyeDirectionApplicable.Apply(_actualEyeDirection)) - { - if (!_actualWeights.ContainsKey(expressionKey)) - { - _actualWeights.Add(expressionKey, 0f); - } - - _actualWeights[expressionKey] = weight; - } - } + _eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights); // 4. Set actual weights to raw blendshapes. _merger.SetValues(_actualWeights); From e8bbbc849d6701905ad64453860887d0b26557c7 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Mon, 1 Feb 2021 23:28:24 +0900 Subject: [PATCH 6/9] ExpressionKey.IsBinary evaluates in ExpressionValidator. --- .../Expression/DefaultExpressionValidator.cs | 15 ++++++--------- .../Components/Expression/ExpressionMerger.cs | 5 ----- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs index 3d4e93483..3825b45bd 100644 --- a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -29,19 +29,16 @@ namespace UniVRM10 // 1. Set weights and Accumulate override rates. foreach (var key in _keys) { - var weight = inputWeights[key]; - - if (!actualWeights.ContainsKey(key)) - { - actualWeights.Add(key, weight); - } - // Set weight. - actualWeights[key] = weight; - // Get expression. if (!_expressions.ContainsKey(key)) continue; var expression = _expressions[key]; + // Get weight with evaluation binary flag. + var weight = expression.IsBinary ? Mathf.Round(inputWeights[key]) : inputWeights[key]; + + // Set weight. + actualWeights[key] = weight; + // Override rate without targeting myself. if (!key.IsBlink) { diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index 3e6b8bfca..b4c337afe 100644 --- a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -61,11 +61,6 @@ namespace UniVRM10 return; } - if (clip.IsBinary) - { - value = Mathf.Round(value); - } - m_morphTargetBindingMerger.AccumulateValue(clip, value); m_materialValueBindingMerger.AccumulateValue(clip, value); } From f36f70674ea79cd77c5dd7cbc4b89aa8cfd83dd8 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Tue, 2 Feb 2021 00:02:08 +0900 Subject: [PATCH 7/9] Follow updates of BlendShapeKey --- .../Components/Expression/ExpressionKey.cs | 80 +++++++------------ 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs index c09cd6b4f..1b0f0a9c2 100644 --- a/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs +++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs @@ -4,28 +4,34 @@ using System.Collections.Generic; namespace UniVRM10 { [Serializable] - public struct ExpressionKey : IEquatable, IComparable + public readonly struct ExpressionKey : IEquatable, IComparable { /// /// Enum.ToString() のGC回避用キャッシュ /// - private static readonly Dictionary m_presetNameDictionary = + private static readonly Dictionary PresetNameDictionary = new Dictionary(); - /// /// ExpressionPreset と同名の名前を持つ独自に追加した Expression を区別するための prefix /// private static readonly string UnknownPresetPrefix = "Unknown_"; - private string m_customName; - - public string Name - { - get { return m_customName.ToUpper(); } - } - - public VrmLib.ExpressionPreset Preset; + /// + /// Preset of this ExpressionKey. + /// + public readonly VrmLib.ExpressionPreset Preset; + + /// + /// Custom Name of this ExpressionKey. + /// This works if Preset was Custom. + /// + public readonly string Name; + + /// + /// Id for comparison of ExpressionKey. + /// + private readonly string _id; public bool IsBlink { @@ -77,61 +83,31 @@ namespace UniVRM10 public bool IsProcedual => IsBlink || IsLookAt || IsMouth; - string m_id; - - string ID - { - get - { - if (string.IsNullOrEmpty(m_id)) - { - // Unknown was deleted - if (Preset != VrmLib.ExpressionPreset.Custom) - { - if (m_presetNameDictionary.ContainsKey(Preset)) - { - m_id = m_presetNameDictionary[Preset]; - } - else - { - m_presetNameDictionary.Add(Preset, Preset.ToString()); - m_id = m_presetNameDictionary[Preset]; - } - } - else - { - m_id = UnknownPresetPrefix + m_customName; - } - } - - return m_id; - } - } - public ExpressionKey(VrmLib.ExpressionPreset preset, string customName = null) { Preset = preset; - m_customName = customName; if (Preset != VrmLib.ExpressionPreset.Custom) { - if (m_presetNameDictionary.ContainsKey((Preset))) + if (PresetNameDictionary.ContainsKey((Preset))) { - m_id = m_presetNameDictionary[Preset]; + _id = Name = PresetNameDictionary[Preset]; } else { - m_presetNameDictionary.Add(Preset, Preset.ToString()); - m_id = m_presetNameDictionary[Preset]; + PresetNameDictionary.Add(Preset, Preset.ToString()); + _id = Name = PresetNameDictionary[Preset]; } } else { - if (string.IsNullOrEmpty(m_customName)) + if (string.IsNullOrEmpty(customName)) { throw new ArgumentException("name is required for VrmLib.ExpressionPreset.Custom"); } - m_id = UnknownPresetPrefix + m_customName; + + _id = $"{UnknownPresetPrefix}{customName}"; + Name = customName; } } @@ -157,12 +133,12 @@ namespace UniVRM10 public override string ToString() { - return ID.Replace(UnknownPresetPrefix, "").ToUpper(); + return _id.Replace(UnknownPresetPrefix, ""); } public bool Equals(ExpressionKey other) { - return ID == other.ID; + return _id == other._id; } public override bool Equals(object obj) @@ -179,7 +155,7 @@ namespace UniVRM10 public override int GetHashCode() { - return ID.GetHashCode(); + return _id.GetHashCode(); } public bool Match(VRM10Expression clip) From ae1bec1e954bafb1c934dd2a58f75fac8f144e28 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Tue, 2 Feb 2021 14:10:12 +0900 Subject: [PATCH 8/9] sum expression override rate method is changed from max to muladd. --- .../Components/Expression/DefaultExpressionValidator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs index 3825b45bd..acd710a53 100644 --- a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -42,15 +42,15 @@ namespace UniVRM10 // Override rate without targeting myself. if (!key.IsBlink) { - blinkOverrideRate = Mathf.Max(blinkOverrideRate, GetOverrideRate(expression.OverrideBlink, weight)); + blinkOverrideRate += GetOverrideRate(expression.OverrideBlink, weight); } if (!key.IsLookAt) { - lookAtOverrideRate = Mathf.Max(lookAtOverrideRate, GetOverrideRate(expression.OverrideLookAt, weight)); + lookAtOverrideRate += GetOverrideRate(expression.OverrideLookAt, weight); } if (!key.IsMouth) { - mouthOverrideRate = Mathf.Max(mouthOverrideRate, GetOverrideRate(expression.OverrideMouth, weight)); + mouthOverrideRate += GetOverrideRate(expression.OverrideMouth, weight); } } From 18850bb04ca98a20178f00706c9d6cbfbbfc9cd7 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Tue, 2 Feb 2021 14:10:35 +0900 Subject: [PATCH 9/9] remove redundant access. --- .../Components/Expression/DefaultExpressionValidator.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs index acd710a53..4f0a9850d 100644 --- a/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs +++ b/Assets/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -66,19 +66,17 @@ namespace UniVRM10 // 3. Set procedural key's weights. foreach (var key in _keys) { - var weight = inputWeights[key]; - if (key.IsBlink) { - actualWeights[key] = weight * blinkMultiplier; + actualWeights[key] = inputWeights[key] * blinkMultiplier; } else if (key.IsLookAt) { - actualWeights[key] = weight * lookAtMultiplier; + actualWeights[key] = inputWeights[key] * lookAtMultiplier; } else if (key.IsMouth) { - actualWeights[key] = weight * mouthMultiplier; + actualWeights[key] = inputWeights[key] * mouthMultiplier; } }