mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-28 05:44:48 -05:00
Define ExpressionValidator instead of ExpressionAccumulator
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50fc6f6edac946548edb751de64c1cb1
|
||||
timeCreated: 1611916405
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1de32ec5101c48298bb78d6835b5d4e2
|
||||
timeCreated: 1611916321
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace UniVRM10
|
||||
{
|
||||
public interface IExpressionValidatorFactory
|
||||
{
|
||||
IExpressionValidator Create(VRM10ExpressionAvatar expressionAvatar);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a46e9573ca04d098b71780a849cd30e
|
||||
timeCreated: 1611916369
|
||||
@@ -25,7 +25,7 @@ namespace UniVRM10
|
||||
/// <summary>
|
||||
/// 1フレームに一回呼び出す(VRM10Controllerの仕事)
|
||||
/// </summary>
|
||||
public void Process()
|
||||
internal void Process()
|
||||
{
|
||||
foreach (var spring in Springs)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user