From 9ae4761d6e6824e591993e4a5ca41b51db4aa79a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 21 Jul 2026 11:09:05 +0900 Subject: [PATCH] add Vrm10RuntimeExpression.Reload --- .../Components/Expression/ExpressionMerger.cs | 15 ++++++++- .../Vrm10Runtime/Vrm10RuntimeExpression.cs | 33 +++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index de9a6a55f..6d658a03d 100644 --- a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -32,6 +32,16 @@ namespace UniVRM10 bool isPrefabInstance, IReadOnlyDictionary initPose) { + InitializeOrReload(expressions, root, isPrefabInstance, initPose); + } + + internal void InitializeOrReload(VRM10ObjectExpression expressions, + Transform root, + bool isPrefabInstance, + IReadOnlyDictionary initPose) + { + Dispose(); + m_clipMap = expressions.Clips.ToDictionary( x => expressions.CreateKey(x.Clip), x => x.Clip, @@ -79,9 +89,12 @@ namespace UniVRM10 m_boneTransformBindingMerger.AccumulateValue(key, value); } + /// + /// 未初期化呼び出し及び再呼び出しで正常に動くように注意 ! + /// public void Dispose() { - m_materialValueBindingMerger.Dispose(); + m_materialValueBindingMerger?.Dispose(); } } } diff --git a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs index 3c13e449f..b28e9741f 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs @@ -10,6 +10,7 @@ namespace UniVRM10 { public static IExpressionValidatorFactory ExpressionValidatorFactory = new DefaultExpressionValidator.Factory(); + private bool _isPrefabInstance; private List _keys = new List(); private Dictionary _inputWeights = new Dictionary(); private Dictionary _actualWeights = new Dictionary(); @@ -25,12 +26,13 @@ namespace UniVRM10 public float LookAtOverrideRate { get; private set; } public float MouthOverrideRate { get; private set; } - internal Vrm10RuntimeExpression(Vrm10Instance target, - ILookAtEyeDirectionApplicable eyeDirectionApplicable, + internal Vrm10RuntimeExpression(Vrm10Instance target, + ILookAtEyeDirectionApplicable eyeDirectionApplicable, bool isPrefabInstance, IReadOnlyDictionary initPose ) { + _isPrefabInstance = isPrefabInstance; _merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance, initPose); _keys = target.Vrm.Expression.Clips .Select(x => target.Vrm.Expression.CreateKey(x.Clip)) @@ -55,6 +57,33 @@ namespace UniVRM10 _eyeDirectionApplicable = eyeDirectionApplicable; } + /// + /// target.Vrm.Expression に基づいて再初期化する。 + /// + /// https://github.com/vrm-c/UniVRM/issues/2802 + /// + /// ex. + /// vrmInstance.Vrm.Expression.AddClip(ExpressionPreset.custom, myCustomExpression); + /// vrmInstance.Runtime.Expression.Reload(vrmInstance); + /// + /// + public void Reload(Vrm10Instance target) + { + // 最新の表情定義に基づいて再生成 + _merger.InitializeOrReload(target.Vrm.Expression, target.transform, _isPrefabInstance, target.Runtime.InitPose); + _keys = target.Vrm.Expression.Clips.Select(x => target.Vrm.Expression.CreateKey(x.Clip)).ToList(); + + // リロード時の一瞬の表情カクつきを防ぐため、既に設定されていたウェイトを引き継ぐ + var oldInputWeights = _inputWeights; + _inputWeights = _keys.ToDictionary(x => x, x => 0f); + foreach (var key in _keys) + { + if (oldInputWeights.ContainsKey(key)) _inputWeights[key] = oldInputWeights[key]; + } + _actualWeights = _keys.ToDictionary(x => x, x => 0f); + _validator = ExpressionValidatorFactory.Create(target.Vrm.Expression); + } + public void Dispose() { _merger?.Dispose();