From 01394bbde75a2d8a4f020dc9862a699129edff13 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Tue, 15 Aug 2023 16:38:27 +0900 Subject: [PATCH] Speed up ExpressionKey comparison. --- .../Components/Expression/ExpressionKey.cs | 53 +++++++++++++------ .../Components/Expression/ExpressionMerger.cs | 10 ++-- .../Vrm10Runtime/Vrm10RuntimeExpression.cs | 16 ++++-- 3 files changed, 56 insertions(+), 23 deletions(-) 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;