diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs
index a79b69279..c329bee70 100644
--- a/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs
+++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using UniGLTF;
using VRMShaders;
namespace UniVRM10
@@ -31,9 +30,9 @@ namespace UniVRM10
public readonly string Name;
///
- /// Id for comparison of ExpressionKey.
+ /// Key's hashcode for comparison.
///
- private readonly string _id;
+ private readonly int _hashCode;
public bool IsBlink
{
@@ -93,12 +92,14 @@ namespace UniVRM10
{
if (PresetNameDictionary.ContainsKey((Preset)))
{
- _id = Name = PresetNameDictionary[Preset];
+ Name = PresetNameDictionary[Preset];
+ _hashCode = Name.GetHashCode();
}
else
{
PresetNameDictionary.Add(Preset, Preset.ToString());
- _id = Name = PresetNameDictionary[Preset];
+ Name = PresetNameDictionary[Preset];
+ _hashCode = Name.GetHashCode();
}
}
else
@@ -108,8 +109,8 @@ namespace UniVRM10
throw new ArgumentException("name is required for ExpressionPreset.Custom");
}
- _id = $"{UnknownPresetPrefix}{customName}";
Name = customName;
+ _hashCode = $"{UnknownPresetPrefix}{customName}".GetHashCode();
}
}
@@ -145,19 +146,24 @@ namespace UniVRM10
public override string ToString()
{
- return _id.Replace(UnknownPresetPrefix, "");
+ return Name;
}
public bool Equals(ExpressionKey other)
{
- return _id == other._id;
+ // Early pruning
+ if (_hashCode != other._hashCode) return false;
+
+ if (Preset != other.Preset) return false;
+ if (Preset != ExpressionPreset.custom) return true;
+ return Name == other.Name;
}
public override bool Equals(object obj)
{
- if (obj is ExpressionKey)
+ if (obj is ExpressionKey key)
{
- return Equals((ExpressionKey)obj);
+ return Equals(key);
}
else
{
@@ -167,14 +173,9 @@ namespace UniVRM10
public override int GetHashCode()
{
- return _id.GetHashCode();
+ return _hashCode;
}
- // public bool Match(VRM10Expression clip)
- // {
- // return this.Equals(CreateFromClip(clip));
- // }
-
public int CompareTo(ExpressionKey other)
{
if (Preset != other.Preset)
@@ -192,5 +193,25 @@ namespace UniVRM10
return new SubAssetKey(typeof(VRM10Expression), this.ToString());
}
}
+
+ public static EqualityComparer Comparer { get; } = new();
+
+ public sealed class EqualityComparer : IEqualityComparer
+ {
+ internal EqualityComparer()
+ {
+
+ }
+
+ public bool Equals(ExpressionKey x, ExpressionKey y)
+ {
+ return x.Equals(y);
+ }
+
+ public int GetHashCode(ExpressionKey obj)
+ {
+ return obj.GetHashCode();
+ }
+ }
}
}
diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs
index b8ec76ec4..64fb82b0d 100644
--- a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs
+++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs
@@ -28,10 +28,12 @@ namespace UniVRM10
public ExpressionMerger(VRM10ObjectExpression expressions, Transform root)
{
- m_clipMap = expressions.Clips.ToDictionary(x => expressions.CreateKey(x.Clip), x => x.Clip);
-
- m_valueMap = new Dictionary();
-
+ m_clipMap = expressions.Clips.ToDictionary(
+ x => expressions.CreateKey(x.Clip),
+ x => x.Clip,
+ ExpressionKey.Comparer
+ );
+ m_valueMap = new Dictionary(ExpressionKey.Comparer);
m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root);
m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root);
}
diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs
index da3bc541f..4082f8b89 100644
--- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs
+++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs
@@ -31,15 +31,25 @@ namespace UniVRM10
Restore();
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform);
- _keys = target.Vrm.Expression.Clips.Select(x => target.Vrm.Expression.CreateKey(x.Clip)).ToList();
+ _keys = target.Vrm.Expression.Clips
+ .Select(x => target.Vrm.Expression.CreateKey(x.Clip))
+ .ToList();
var oldInputWeights = _inputWeights;
- _inputWeights = _keys.ToDictionary(x => x, x => 0f);
+ _inputWeights = _keys.ToDictionary(
+ x => x,
+ x => 0f,
+ ExpressionKey.Comparer
+ );
foreach (var key in _keys)
{
// remain user input weights.
if (oldInputWeights.ContainsKey(key)) _inputWeights[key] = oldInputWeights[key];
}
- _actualWeights = _keys.ToDictionary(x => x, x => 0f);
+ _actualWeights = _keys.ToDictionary(
+ x => x,
+ x => 0f,
+ ExpressionKey.Comparer
+ );
_validator = ExpressionValidatorFactory.Create(target.Vrm.Expression);
_eyeDirectionProvider = eyeDirectionProvider;
_eyeDirectionApplicable = eyeDirectionApplicable;