diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs index ac9897aaf..ec13afd46 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs @@ -51,6 +51,8 @@ namespace UniGLTF // Root GameObject is main object context.SetMainObject(loaded.Root); } + + return true; }); } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 653bbfa3a..991ce537c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -206,6 +206,14 @@ namespace UniGLTF } } } + void RemoveMesh(Mesh mesh) + { + var index = Meshes.FindIndex(x => x.Mesh == mesh); + if (index >= 0) + { + Meshes.RemoveAt(index); + } + } public void EnableUpdateWhenOffscreen() { @@ -266,27 +274,44 @@ namespace UniGLTF /// Root ヒエラルキーで使っているリソース /// /// - public virtual void TransferOwnership(Action add) + public virtual void TransferOwnership(TakeOwnershipFunc take) { + var list = new List(); foreach (var mesh in Meshes) { - add(mesh.Mesh); + if (take(mesh.Mesh)) + { + list.Add(mesh.Mesh); + } + } + foreach (var x in list) + { + RemoveMesh(x as Mesh); } - Meshes.Clear(); - TextureFactory.TransferOwnership(add); - MaterialFactory.TransferOwnership(add); + TextureFactory.TransferOwnership(take); + MaterialFactory.TransferOwnership(take); + list.Clear(); foreach (var animation in AnimationClips) { - add(animation); + if (take(animation)) + { + list.Add(animation); + } + } + foreach (var x in list) + { + AnimationClips.Remove(x as AnimationClip); } - AnimationClips.Clear(); if (m_ownRoot && Root != null) { - add(Root); - m_ownRoot = false; + if (take(Root)) + { + // 所有権(Dispose権) + m_ownRoot = false; + } } } @@ -302,7 +327,11 @@ namespace UniGLTF public UnityResourceDestroyer DisposeOnGameObjectDestroyed() { var destroyer = Root.AddComponent(); - TransferOwnership(destroyer.Resources.Add); + TransferOwnership(o => + { + destroyer.Resources.Add(o); + return true; + }); return destroyer; } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs index 57cd2e7d7..b36126eba 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs @@ -75,6 +75,15 @@ namespace UniGLTF List m_materials = new List(); public IReadOnlyList Materials => m_materials; + void Remove(Material material) + { + var index = m_materials.FindIndex(x => x.Asset == material); + if (index >= 0) + { + m_materials.RemoveAt(index); + + } + } public void Dispose() { @@ -82,6 +91,7 @@ namespace UniGLTF { if (!x.UseExternal) { + // 外部の '.asset' からロードしていない #if VRM_DEVELOP Debug.Log($"Destroy {x.Asset}"); #endif @@ -90,16 +100,28 @@ namespace UniGLTF } } - public void TransferOwnership(Action add) + /// + /// 所有権(Dispose権)を移譲する + /// + /// + public void TransferOwnership(TakeOwnershipFunc take) { + var list = new List(); foreach (var x in m_materials) { if (!x.UseExternal) { - add(x.Asset); + // 外部の '.asset' からロードしていない + if (take(x.Asset)) + { + list.Add(x.Asset); + } } } - m_materials.Clear(); + foreach (var x in list) + { + Remove(x); + } } public Material GetMaterial(int index) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs new file mode 100644 index 000000000..4cb91856c --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs @@ -0,0 +1,13 @@ +namespace UniGLTF +{ + /// + /// 所有権を移動する関数。 + /// + /// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる + /// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる + /// + /// + /// 対象のオブジェクト + /// 所有権が移動したらtrue + public delegate bool TakeOwnershipFunc(UnityEngine.Object o); +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta new file mode 100644 index 000000000..0b34ae7e0 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab2b998b9235dc94a90ccaf2e40a50a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs index 155f4a670..c89cde2ae 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs @@ -98,15 +98,23 @@ namespace UniGLTF m_textureCache.Clear(); } - public void TransferOwnership(Action add) + /// + /// 所有権(Dispose権)を移譲する + /// + /// + public void TransferOwnership(TakeOwnershipFunc take) { var keys = new List(); foreach (var x in m_textureCache) { if (x.Value.IsUsed && !x.Value.IsExternal) { - keys.Add(x.Key); - add(x.Value.Texture); + // マテリアルから参照されていて + // 外部のAssetからロードしていない。 + if (take(x.Value.Texture)) + { + keys.Add(x.Key); + } } } foreach (var x in keys) diff --git a/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs b/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs index e258c33fd..54b40740a 100644 --- a/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs +++ b/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs @@ -10,10 +10,14 @@ namespace VRM public class VRMEditorImporterContext { VRMImporterContext m_context; + UnityPath m_prefabPath; + List m_paths = new List(); - public VRMEditorImporterContext(VRMImporterContext context) + + public VRMEditorImporterContext(VRMImporterContext context, UnityPath prefabPath) { m_context = context; + m_prefabPath = prefabPath; } public bool AvoidOverwriteAndLoad(UnityPath assetPath, UnityEngine.Object o) @@ -57,7 +61,7 @@ namespace VRM return false; } - public UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o, bool meshAsSubAsset) + public UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o) { if (o is BlendShapeAvatar || o is BlendShapeClip) @@ -96,7 +100,7 @@ namespace VRM var texturePath = textureDir.Child(o.name.EscapeFilePath() + ".asset"); return texturePath; } - else if (o is Mesh && !meshAsSubAsset) + else if (o is Mesh) { var meshDir = prefabPath.GetAssetFolder(".Meshes"); var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset"); @@ -146,85 +150,64 @@ namespace VRM TextureExtractor.ExtractTextures(assetPath.Value, subAssets, _ => { }, onTextureReloaded); } - public void SaveAsAsset(UnityPath prefabPath, bool meshAsSubAsset = false) + bool SaveAsAsset(UnityEngine.Object o) { - m_context.ShowMeshes(); - - //var prefabPath = PrefabPath; - if (prefabPath.IsFileExists) + if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))) { - // clear SubAssets - foreach (var x in prefabPath.GetSubAssets().Where(x => !(x is GameObject) && !(x is Component))) + // already exists. not dispose + return true; + } + + var assetPath = GetAssetPath(m_prefabPath, o); + if (assetPath.IsNull) + { + return false; + } + + if (assetPath.IsFileExists) + { + if (AvoidOverwriteAndLoad(assetPath, o)) { - GameObject.DestroyImmediate(x, true); + // 上書きせずに既存のアセットからロードして置き換えた + return true; } } + // アセットとして書き込む + assetPath.Parent.EnsureFolder(); + assetPath.CreateAsset(o); + m_paths.Add(assetPath); + + // 所有権が移動 + return true; + } + + public void SaveAsAsset() + { + m_context.ShowMeshes(); + // // save sub assets // - var paths = new List(){ - prefabPath - }; - - // backup - var root = m_context.Root; - - m_context.TransferOwnership(o => - { - - if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))) - { - // already exists - return; - } - - var assetPath = GetAssetPath(prefabPath, o, meshAsSubAsset); - if (!assetPath.IsNull) - { - if (assetPath.IsFileExists) - { - if (AvoidOverwriteAndLoad(assetPath, o)) - { - // 上書きせずに既存のアセットからロードして置き換えた - return; - } - } - - // アセットとして書き込む - assetPath.Parent.EnsureFolder(); - assetPath.CreateAsset(o); - paths.Add(assetPath); - } - else - { - // save as subasset - if (o is GameObject) - { - - } - else - { - prefabPath.AddObjectToAsset(o); - } - } - - }); + m_paths.Clear(); + m_paths.Add(m_prefabPath); + m_context.TransferOwnership(SaveAsAsset); // Create or update Main Asset - if (prefabPath.IsFileExists) + if (m_prefabPath.IsFileExists) { - Debug.LogFormat("replace prefab: {0}", prefabPath); - var prefab = prefabPath.LoadAsset(); - PrefabUtility.SaveAsPrefabAssetAndConnect(root, prefabPath.Value, InteractionMode.AutomatedAction); + Debug.LogFormat("replace prefab: {0}", m_prefabPath); + var prefab = m_prefabPath.LoadAsset(); + PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction); } else { - Debug.LogFormat("create prefab: {0}", prefabPath); - PrefabUtility.SaveAsPrefabAssetAndConnect(root, prefabPath.Value, InteractionMode.AutomatedAction); + Debug.LogFormat("create prefab: {0}", m_prefabPath); + PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction); } - foreach (var x in paths) + + foreach (var x in m_paths) { x.ImportAsset(); } diff --git a/Assets/VRM/Editor/Format/VRMImporterMenu.cs b/Assets/VRM/Editor/Format/VRMImporterMenu.cs index f99e8dda3..88879c266 100644 --- a/Assets/VRM/Editor/Format/VRMImporterMenu.cs +++ b/Assets/VRM/Editor/Format/VRMImporterMenu.cs @@ -64,15 +64,15 @@ namespace VRM // using (var context = new VRMImporterContext(parser)) { - var editor = new VRMEditorImporterContext(context); + var editor = new VRMEditorImporterContext(context, prefabPath); context.Load(); - editor.SaveAsAsset(prefabPath); + editor.SaveAsAsset(); } }; using (var context = new VRMImporterContext(parser)) { - var editor = new VRMEditorImporterContext(context); + var editor = new VRMEditorImporterContext(context, prefabPath); editor.ConvertAndExtractImages(UnityPath.FromFullpath(path), onCompleted); } } diff --git a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs index daab9d98f..be8655a4b 100644 --- a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs +++ b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using UniGLTF; using UnityEditor; using UnityEngine; @@ -38,16 +36,7 @@ namespace VRM } var parser = new GltfParser(); - try - { - parser.ParseGlb(File.ReadAllBytes(path.FullPath)); - } - catch (KeyNotFoundException) - { - // invalid VRM-0.X. - // maybe VRM-1.0.do nothing - return; - } + parser.ParseGlb(File.ReadAllBytes(path.FullPath)); var prefabPath = path.Parent.Child(path.FileNameWithoutExtension + ".prefab"); @@ -55,15 +44,15 @@ namespace VRM { using (var context = new VRMImporterContext(parser)) { - var editor = new VRMEditorImporterContext(context); + var editor = new VRMEditorImporterContext(context, prefabPath); context.Load(); - editor.SaveAsAsset(prefabPath); + editor.SaveAsAsset(); } }; using (var context = new VRMImporterContext(parser)) { - var editor = new VRMEditorImporterContext(context); + var editor = new VRMEditorImporterContext(context, prefabPath); editor.ConvertAndExtractImages(path, onCompleted); } } diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index 795cfdf13..5bbba0780 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -304,28 +304,44 @@ namespace VRM return meta; } - public override void TransferOwnership(Action add) + public override void TransferOwnership(TakeOwnershipFunc take) { // VRM 固有のリソース(ScriptableObject) - add(HumanoidAvatar); - HumanoidAvatar = null; + if (take(HumanoidAvatar)) + { + HumanoidAvatar = null; + } - add(Meta); - Meta = null; + if (take(Meta)) + { + Meta = null; + } - add(AvatarDescription); - AvatarDescription = null; + if (take(AvatarDescription)) + { + AvatarDescription = null; + } + var list = new List(); foreach (var x in BlendShapeAvatar.Clips) { - add(x); + if (take(x)) + { + list.Add(x); + } + } + foreach (var x in list) + { + BlendShapeAvatar.Clips.Remove(x); } - BlendShapeAvatar.Clips.Clear(); - add(BlendShapeAvatar); - BlendShapeAvatar = null; + if (take(BlendShapeAvatar)) + { + BlendShapeAvatar = null; + } - base.TransferOwnership(add); + // GLTF のリソース + base.TransferOwnership(take); } } }