Define ExpressionValidator instead of ExpressionAccumulator

This commit is contained in:
Masataka SUMI
2021-02-01 15:54:13 +09:00
parent 5241f79927
commit a3afd483d0
11 changed files with 170 additions and 53 deletions

View File

@@ -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<ExpressionKey, float>(x.Key, x.Value)));
m_target.Expression.SetWeights(m_expressionKeyWeights);
}
}

View File

@@ -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<ExpressionKey, float> inputWeights, IDictionary<ExpressionKey, float> 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);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 50fc6f6edac946548edb751de64c1cb1
timeCreated: 1611916405

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace UniVRM10
{
/// <summary>
/// Validate Expression constraints (ex. overrideBlink)
/// </summary>
public interface IExpressionValidator
{
/// <summary>
/// Validate input weights with Expression constraints.
/// </summary>
void Validate(IReadOnlyDictionary<ExpressionKey, float> inputWeights, IDictionary<ExpressionKey, float> actualWeights);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1de32ec5101c48298bb78d6835b5d4e2
timeCreated: 1611916321

View File

@@ -0,0 +1,7 @@
namespace UniVRM10
{
public interface IExpressionValidatorFactory
{
IExpressionValidator Create(VRM10ExpressionAvatar expressionAvatar);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5a46e9573ca04d098b71780a849cd30e
timeCreated: 1611916369

View File

@@ -25,7 +25,7 @@ namespace UniVRM10
/// <summary>
/// 1フレームに一回呼び出す(VRM10Controllerの仕事)
/// </summary>
public void Process()
internal void Process()
{
foreach (var spring in Springs)
{

View File

@@ -98,7 +98,7 @@ namespace UniVRM10
private void Start()
{
Expression.OnStart(transform);
Expression.Setup(transform);
// get lookat origin
var animator = GetComponent<Animator>();
@@ -118,7 +118,7 @@ namespace UniVRM10
/// * Expression
///
/// </summary>
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();
}
}

View File

@@ -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<ExpressionKey> _keys = new List<ExpressionKey>();
private Dictionary<ExpressionKey, float> _inputWeights = new Dictionary<ExpressionKey, float>();
private Dictionary<ExpressionKey, float> _actualWeights = new Dictionary<ExpressionKey, float>();
private ExpressionMerger _merger;
private IExpressionValidator _validator;
public IReadOnlyList<ExpressionKey> ExpressionKeys => _keys;
public IReadOnlyDictionary<ExpressionKey, float> 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<ExpressionKey, float> GetWeights()
{
return _inputWeights;
}
public float GetWeight(ExpressionKey expressionKey)
{
if (_inputWeights.ContainsKey(expressionKey))
{
return _inputWeights[expressionKey];
}
return 0f;
}
public void SetWeights(IEnumerable<KeyValuePair<ExpressionKey, float>> 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()
/// <summary>
/// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。
/// </summary>
private void Apply()
{
m_merger.SetValues(m_accumulator.FrameExpression());
_validator.Validate(_inputWeights, _actualWeights);
_merger.SetValues(_actualWeights);
}
}
}

View File

@@ -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
/// <summay>
@@ -160,43 +166,41 @@ namespace UniVRM10
}
}
public delegate void SetPresetValue(VrmLib.ExpressionPreset preset, float weight);
public delegate void SetExpressionWeights(IEnumerable<KeyValuePair<ExpressionKey, float>> weights);
/// <summary>
/// Expression による LookAt を処理する(関連する Expression の Weight を変更する)
/// Expression による LookAt の Weight を計算する
/// </summary>
/// <param name="yaw"></param>
/// <param name="pitch"></param>
void LookAtExpression(float yaw, float pitch, SetPresetValue SetPresetValue)
private IEnumerable<KeyValuePair<ExpressionKey, float>> 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<ExpressionKey, float>(m_lookRightKey, 0);
yield return new KeyValuePair<ExpressionKey, float>(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<ExpressionKey, float>(m_lookRightKey, Mathf.Clamp(HorizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f));
yield return new KeyValuePair<ExpressionKey, float>(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<ExpressionKey, float>(m_lookUpKey, 0);
yield return new KeyValuePair<ExpressionKey, float>(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<ExpressionKey, float>(m_lookUpKey, Mathf.Clamp(VerticalUp.Map(Mathf.Abs(pitch)), 0, 1.0f));
yield return new KeyValuePair<ExpressionKey, float>(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;
}
}