150 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF;
using UnityEngine;
namespace VRM
{
/// <summary>
/// ブレンドシェイプを蓄えてまとめて適用するクラス
/// </summary>
public class BlendShapeMerger
{
/// <summary>
/// Key からBlendShapeClipを得る
/// </summary>
Dictionary<BlendShapeKey, BlendShapeClip> m_clipMap;
/// <summary>
/// BlendShape のWeightを記録する
/// </summary>
Dictionary<BlendShapeKey, float> m_valueMap;
BlendShapeBindingMerger m_blendShapeBindingMerger;
MaterialValueBindingMerger m_materialValueBindingMerger;
public BlendShapeMerger(IEnumerable<BlendShapeClip> clips, Transform root)
{
m_clipMap = clips.ToDictionary(x => BlendShapeKey.CreateFromClip(x), x => x);
m_valueMap = new Dictionary<BlendShapeKey, float>();
m_blendShapeBindingMerger = new BlendShapeBindingMerger(m_clipMap, root);
m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root);
}
/*
public void Clear()
{
foreach (var kv in m_valueMap.ToArray())
{
SetValue(kv.Key, kv.Value, false);
}
Apply();
}
*/
/// <summary>
/// 蓄積した値を適用する
/// </summary>
public void Apply()
{
m_blendShapeBindingMerger.Apply();
m_materialValueBindingMerger.Apply();
}
/// <summary>
/// まとめて反映する。1フレームに1回呼び出されることを想定
/// </summary>
/// <param name="values"></param>
public void SetValues(IEnumerable<KeyValuePair<BlendShapeKey, float>> values)
{
foreach (var kv in values)
{
AccumulateValue(kv.Key, kv.Value);
}
Apply();
}
/// <summary>
/// 即時に反映しない。後にApplyによって反映する
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void AccumulateValue(BlendShapeKey key, float value)
{
m_valueMap[key] = value;
BlendShapeClip clip;
if (!m_clipMap.TryGetValue(key, out clip))
{
return;
}
if (clip.IsBinary)
{
value = Mathf.Round(value);
}
m_blendShapeBindingMerger.AccumulateValue(clip, value);
m_materialValueBindingMerger.AccumulateValue(clip, value);
}
/// <summary>
/// 即時に反映する
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void ImmediatelySetValue(BlendShapeKey key, float value)
{
m_valueMap[key] = value;
BlendShapeClip clip;
if (!m_clipMap.TryGetValue(key, out clip))
{
return;
}
if (clip.IsBinary)
{
value = Mathf.Round(value);
}
m_blendShapeBindingMerger.ImmediatelySetValue(clip, value);
m_materialValueBindingMerger.ImmediatelySetValue(clip, value);
}
public void SetValue(BlendShapeKey key, float value, bool immediately)
{
if (immediately)
{
ImmediatelySetValue(key, value);
}
else
{
AccumulateValue(key, value);
}
}
public float GetValue(BlendShapeKey key)
{
float value;
if (!m_valueMap.TryGetValue(key, out value))
{
return 0;
}
return value;
}
public void RestoreMaterialInitialValues(IEnumerable<BlendShapeClip> clips)
{
m_materialValueBindingMerger.RestoreMaterialInitialValues(clips);
}
}
}