diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs
index d7588cbcf..83dd81993 100644
--- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs
+++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs
@@ -61,7 +61,7 @@ namespace UniGLTF
context.AddObjectToAsset(k.Name, o);
});
var root = loaded.Root;
- GameObject.DestroyImmediate(loaded);
+ DestroyImmediate(loaded);
context.AddObjectToAsset(root.name, root);
context.SetMainObject(root);
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs b/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs
index 79f7d94c1..6f4374687 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs
+++ b/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs
@@ -9,6 +9,10 @@ namespace UniGLTF
/// ImporterContext の Load 結果の GltfModel
///
/// Runtime でモデルを Destory したときに関連リソース(Texture, Material...などの UnityEngine.Object)を自動的に Destroy する。
+ ///
+ /// TODO: Editor Importの場合でも一瞬だけこのクラスのインスタンスが生じるが、すぐDestroyImmediateされるため、それらを区別する用途に使うことができる
+ /// Editorでも利用されている以上、名前・責務が良くないので見直したい。
+ ///
///
public class RuntimeGltfInstance : MonoBehaviour, IResponsibilityForDestroyObjects
{
diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs
index 791397b22..e178df0c5 100644
--- a/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs
+++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionMerger.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -8,7 +9,7 @@ namespace UniVRM10
///
/// ブレンドシェイプを蓄えてまとめて適用するクラス
///
- internal sealed class ExpressionMerger
+ internal sealed class ExpressionMerger : IDisposable
{
///
/// Key から Expression を得る
@@ -24,7 +25,7 @@ namespace UniVRM10
MaterialValueBindingMerger m_materialValueBindingMerger;
- public ExpressionMerger(VRM10ObjectExpression expressions, Transform root)
+ public ExpressionMerger(VRM10ObjectExpression expressions, Transform root, bool isPrefabInstance)
{
m_clipMap = expressions.Clips.ToDictionary(
x => expressions.CreateKey(x.Clip),
@@ -33,7 +34,7 @@ namespace UniVRM10
);
m_valueMap = new Dictionary(ExpressionKey.Comparer);
m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root);
- m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root);
+ m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root, isPrefabInstance);
}
///
@@ -74,5 +75,10 @@ namespace UniVRM10
{
m_materialValueBindingMerger.RestoreMaterialInitialValues();
}
+
+ public void Dispose()
+ {
+ m_materialValueBindingMerger.Dispose();
+ }
}
}
diff --git a/Assets/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs b/Assets/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs
index 495ccfd90..665b2b611 100644
--- a/Assets/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs
+++ b/Assets/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs
@@ -3,13 +3,14 @@ using System.Collections.Generic;
using UniGLTF.Extensions.VRMC_vrm;
using UnityEngine;
using VRM10.MToon10;
+using Object = UnityEngine.Object;
namespace UniVRM10
{
///
/// Base + (A.Target - Base) * A.Weight + (B.Target - Base) * B.Weight ...
///
- internal sealed class MaterialValueBindingMerger
+ internal sealed class MaterialValueBindingMerger : IDisposable
{
private static readonly string COLOR_PROPERTY = MToon10Prop.BaseColorFactor.ToUnityShaderLabName();
private static readonly string EMISSION_COLOR_PROPERTY = MToon10Prop.EmissiveFactor.ToUnityShaderLabName();
@@ -18,6 +19,8 @@ namespace UniVRM10
private static readonly string SHADE_COLOR_PROPERTY = MToon10Prop.ShadeColorFactor.ToUnityShaderLabName();
private static readonly string MATCAP_COLOR_PROPERTY = MToon10Prop.MatcapColorFactor.ToUnityShaderLabName();
+ private readonly HashSet _clonedMaterials = new();
+
public static string GetProperty(MaterialColorType bindType)
{
switch (bindType)
@@ -50,16 +53,44 @@ namespace UniVRM10
///
Dictionary m_materialMap = new Dictionary();
- void InitializeMaterialMap(Dictionary clipMap, Transform root)
+ void InitializeMaterialMap(Dictionary clipMap, Transform root, bool isPrefabInstance)
{
- Dictionary materialNameMap = new Dictionary();
+ var materialNameMap = new Dictionary();
foreach (var renderer in root.GetComponentsInChildren())
{
- foreach (var material in renderer.sharedMaterials)
+ // VFXRendererなど、Materialが設定できないRendererが存在する
+ if (renderer is not SkinnedMeshRenderer && renderer is not MeshRenderer) continue;
+
+ if (isPrefabInstance)
{
- if (material != null && !materialNameMap.ContainsKey(material.name))
+ // EditorImportされたPrefabのInstanceとして生成されている場合、Materialを複製する
+ var sharedMaterials = renderer.sharedMaterials;
+ var materials = renderer.materials;
+ for (var i = 0; i < materials.Length; i++)
{
- materialNameMap.Add(material.name, material);
+ var sharedMaterial = sharedMaterials[i];
+ var material = materials[i];
+
+ if (!sharedMaterial || !material) continue;
+
+ // 複製されたマテリアルはこのクラス内で破棄
+ if (sharedMaterial != material) _clonedMaterials.Add(material);
+
+ // 複製前の名前に揃え、それを記録しておく
+ // なお、Vrm10Runtimeのインスタンスが作られるより先にユーザーによってMaterialが複製されるパターンは想定しない
+ material.name = sharedMaterial.name;
+ materialNameMap.TryAdd(sharedMaterial.name, material);
+ }
+ }
+ else
+ {
+ // PrefabのInstanceでない(RuntimeImportされている)ならMaterialは複製しない
+ foreach (var material in renderer.sharedMaterials)
+ {
+ if (material)
+ {
+ materialNameMap.TryAdd(material.name, material);
+ }
}
}
}
@@ -284,9 +315,18 @@ namespace UniVRM10
}
#endregion
- public MaterialValueBindingMerger(Dictionary clipMap, Transform root)
+ public MaterialValueBindingMerger(Dictionary clipMap, Transform root, bool isPrefabInstance)
{
- InitializeMaterialMap(clipMap, root);
+ InitializeMaterialMap(clipMap, root, isPrefabInstance);
+ }
+
+ public void Dispose()
+ {
+ foreach (var clonedMaterial in _clonedMaterials)
+ {
+ Object.Destroy(clonedMaterial);
+ }
+ _clonedMaterials.Clear();
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs
index f27be9aea..5b4d46531 100644
--- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs
+++ b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs
@@ -141,8 +141,11 @@ namespace UniVRM10
}
var initPose = RuntimeGltfInstance.SafeGetInitialPose(transform);
+
+ // NOTE: RuntimeGltfInstanceがないかどうかでPrefabのインスタンスであるか(EditorImportされているか)が判別できる
+ var isPrefabInstance = !GetComponent();
- return new Vrm10Runtime(this, useControlRig, m_springBoneRuntime, initPose);
+ return new Vrm10Runtime(this, useControlRig, m_springBoneRuntime, initPose, isPrefabInstance);
}
public Vrm10Runtime Runtime
diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs
index c6e8661e2..5a800d2e1 100644
--- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs
+++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs
@@ -52,7 +52,7 @@ namespace UniVRM10
IReadOnlyDictionary _initPose;
public Vrm10Runtime(Vrm10Instance instance, bool useControlRig, IVrm10SpringBoneRuntime springBoneRuntime,
- IReadOnlyDictionary initPose)
+ IReadOnlyDictionary initPose, bool isPrefabInstance)
{
if (!Application.isPlaying)
{
@@ -77,7 +77,7 @@ namespace UniVRM10
}
Constraints = instance.GetComponentsInChildren();
LookAt = new Vrm10RuntimeLookAt(instance, instance.Humanoid, ControlRig);
- Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable);
+ Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance);
SpringBone = springBoneRuntime;
}
diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs
index 1a4f747ce..902654f35 100644
--- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs
+++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs
@@ -23,9 +23,9 @@ 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)
{
- _merger = new ExpressionMerger(target.Vrm.Expression, target.transform);
+ _merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance);
_keys = target.Vrm.Expression.Clips
.Select(x => target.Vrm.Expression.CreateKey(x.Clip))
.ToList();
@@ -56,6 +56,9 @@ namespace UniVRM10
_eyeDirectionApplicable?.Restore();
_eyeDirectionApplicable = null;
+
+ _merger?.Dispose();
+ _merger = null;
}
internal void Process(LookAtEyeDirection inputEyeDirection)