diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorAnimation.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorAnimation.cs index b177064771..632b65ccb4 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorAnimation.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorAnimation.cs @@ -21,7 +21,7 @@ public static void OnGUIAnimation(ScriptedImporter importer, GltfParser parser) } } - importer.DrawRemapGUI(parser.GLTF.animations.Select(x => new SubAssetKey(typeof(AnimationClip), x.name))); + importer.DrawRemapGUI(AnimationImporterUtil.EnumerateSubAssetKeys(parser.GLTF)); if (GUILayout.Button("Clear")) { diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs index 5d0f12d611..335dd3ef0b 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterImpl.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; using System.Linq; -using UnityEditor; using UnityEngine; using VRMShaders; #if UNITY_2020_2_OR_NEWER @@ -50,20 +48,18 @@ public static void Import(ScriptedImporter scriptedImporter, AssetImportContext } loader.InvertAxis = reverseAxis; - loader.Load(); - loader.ShowMeshes(); + var loaded = loader.Load(); + loaded.ShowMeshes(); - loader.TransferOwnership(o => + loaded.TransferOwnership((k, o) => { - context.AddObjectToAsset(o.name, o); - if (o is GameObject) - { - // Root GameObject is main object - context.SetMainObject(loader.Root); - } - - return true; + context.AddObjectToAsset(k.Name, o); }); + var root = loaded.Root; + GameObject.DestroyImmediate(loaded); + + context.AddObjectToAsset(root.name, root); + context.SetMainObject(root); } } } diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs index bc19ccd19b..f633ab6247 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs @@ -107,13 +107,4 @@ public static void ExtractTextures(GltfParser parser, UnityPath textureDirectory }; } } - - public static class KeyValuePariExtensions - { - public static void Deconstruct(this KeyValuePair pair, out T key, out U value) - { - key = pair.Key; - value = pair.Value; - } - } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs index dc561cbcf6..5914212b6d 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs @@ -312,5 +312,13 @@ public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animat } return clip; } + + public static IEnumerable EnumerateSubAssetKeys(glTF gltf) + { + foreach (var gltfAnimation in gltf.animations) + { + yield return new VRMShaders.SubAssetKey(typeof(AnimationClip), gltfAnimation.name); + } + } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 616afcda2c..9b72a96036 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -10,7 +10,7 @@ namespace UniGLTF /// /// GLTF importer /// - public class ImporterContext : IDisposable + public class ImporterContext : IResponsibilityForDestroyObjects { public ITextureDescriptorGenerator TextureDescriptorGenerator { get; protected set; } public IMaterialDescriptorGenerator MaterialDescriptorGenerator { get; protected set; } @@ -61,7 +61,7 @@ public ImporterContext( }; #region Load. Build unity objects - public virtual async Task LoadAsync(IAwaitCaller awaitCaller = null, Func MeasureTime = null) + public virtual async Task LoadAsync(IAwaitCaller awaitCaller = null, Func MeasureTime = null) { if (awaitCaller == null) { @@ -108,6 +108,8 @@ public virtual async Task LoadAsync(IAwaitCaller awaitCaller = null, Func @@ -119,18 +121,17 @@ protected virtual async Task LoadAnimationAsync(IAwaitCaller awaitCaller) { if (GLTF.animations != null && GLTF.animations.Any()) { - for (int i = 0; i < GLTF.animations.Count; ++i) + foreach (var (key, gltfAnimation) in Enumerable.Zip(AnimationImporterUtil.EnumerateSubAssetKeys(GLTF), GLTF.animations, (x, y) => (x, y))) { - var gltfAnimation = GLTF.animations[i]; AnimationClip clip = default; - if (_externalObjectMap.TryGetValue(new SubAssetKey(typeof(AnimationClip), gltfAnimation.name), out UnityEngine.Object value)) + if (_externalObjectMap.TryGetValue(key, out UnityEngine.Object value)) { clip = value as AnimationClip; } else { - clip = AnimationImporterUtil.ConvertAnimationClip(GLTF, GLTF.animations[i], InvertAxis.Create()); - AnimationClips.Add(clip); + clip = AnimationImporterUtil.ConvertAnimationClip(GLTF, gltfAnimation, InvertAxis.Create()); + AnimationClips.Add((key, clip)); } } @@ -150,7 +151,7 @@ protected virtual async Task SetupAnimationsAsync(IAwaitCaller awaitCaller) var animation = Root.AddComponent(); for (int i = 0; i < AnimationClips.Count; ++i) { - var clip = AnimationClips[i]; + var (_, clip) = AnimationClips[i]; animation.AddClip(clip, clip.name); if (i == 0) { @@ -275,46 +276,12 @@ async Task BuildMeshAsync(IAwaitCaller awaitCaller, Func Nodes = new List(); public List Meshes = new List(); - public void ShowMeshes() - { - foreach (var x in Meshes) - { - foreach (var y in x.Renderers) - { - y.enabled = true; - } - } - } - void RemoveMesh(Mesh mesh) - { - var index = Meshes.FindIndex(x => x.Mesh == mesh); - if (index >= 0) - { - Meshes.RemoveAt(index); - } - } - public void EnableUpdateWhenOffscreen() - { - foreach (var x in Meshes) - { - foreach (var r in x.Renderers) - { - var skinnedMeshRenderer = r as SkinnedMeshRenderer; - if (skinnedMeshRenderer != null) - { - skinnedMeshRenderer.updateWhenOffscreen = true; - } - } - } - } - - public List AnimationClips = new List(); + public List<(SubAssetKey, AnimationClip)> AnimationClips = new List<(SubAssetKey, AnimationClip)>(); #endregion /// @@ -322,101 +289,42 @@ public void EnableUpdateWhenOffscreen() /// public virtual void Dispose() { - Action destroy = UnityResourceDestroyer.DestroyResource(); - - foreach (var x in AnimationClips) + foreach (var (k, x) in AnimationClips) { -#if VRM_DEVELOP - // Debug.Log($"Destroy {x}"); -#endif - destroy(x); + UnityObjectDestoyer.DestroyRuntimeOrEditor(x); } AnimationClips.Clear(); foreach (var x in Meshes) { -#if VRM_DEVELOP - // Debug.Log($"Destroy {x.Mesh}"); -#endif - destroy(x.Mesh); + UnityObjectDestoyer.DestroyRuntimeOrEditor(x.Mesh); } Meshes.Clear(); MaterialFactory?.Dispose(); TextureFactory?.Dispose(); - - if (m_ownRoot && Root != null) - { -#if VRM_DEVELOP - // Debug.Log($"Destroy {Root}"); -#endif - destroy(Root); - } } /// /// Root ヒエラルキーで使っているリソース /// /// - public virtual void TransferOwnership(Func take) + public virtual void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) { - var list = new List(); - foreach (var mesh in Meshes) - { - if (take(mesh.Mesh)) - { - list.Add(mesh.Mesh); - } - } - foreach (var x in list) + foreach (var mesh in Meshes.ToArray()) { - RemoveMesh(x as Mesh); + take(SubAssetKey.Create(mesh.Mesh), mesh.Mesh); + Meshes.Remove(mesh); } TextureFactory.TransferOwnership(take); MaterialFactory.TransferOwnership(take); - list.Clear(); - foreach (var animation in AnimationClips) - { - if (take(animation)) - { - list.Add(animation); - } - } - foreach (var x in list) + foreach (var (key, animation) in AnimationClips.ToArray()) { - AnimationClips.Remove(x as AnimationClip); + take(key, animation); + AnimationClips.Remove((key, animation)); } - - if (m_ownRoot && Root != null) - { - if (take(Root)) - { - // 所有権(Dispose権) - m_ownRoot = false; - } - } - } - - /// - /// RootにUnityResourceDestroyerをアタッチして、 - /// RootをUnityEngine.Object.Destroyしたときに、 - /// 関連するUnityEngine.Objectを破棄するようにする。 - /// Mesh, Material, Texture, AnimationClip, GameObject の所有者が - /// ImporterContext から UnityResourceDestroyer に移動する。 - /// ImporterContext.Dispose の対象から外れる。 - /// - /// - public UnityResourceDestroyer DisposeOnGameObjectDestroyed() - { - var destroyer = Root.AddComponent(); - TransferOwnership(o => - { - destroyer.Resources.Add(o); - return true; - }); - return destroyer; } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs index 900440fe3d..180a91d840 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs @@ -8,7 +8,7 @@ public static class ImporterContextExtensions /// /// Build unity objects from parsed gltf /// - public static void Load(this ImporterContext self) + public static RuntimeGltfInstance Load(this ImporterContext self) { var meassureTime = new ImporterContextSpeedLog(); var task = self.LoadAsync(default(ImmediateCaller), meassureTime.MeasureTime); @@ -24,6 +24,8 @@ public static void Load(this ImporterContext self) #if VRM_DEVELOP Debug.Log($"{self.Parser.TargetPath}: {meassureTime.GetSpeedLog()}"); #endif + + return task.Result; } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs b/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs new file mode 100644 index 0000000000..283b3f90a2 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using UnityEngine; +using VRMShaders; + +namespace UniGLTF +{ + /// + /// ImporterContext の Load 結果の GltfModel + /// + /// Runtime でモデルを Destory したときに関連リソース(Texture, Material...などの UnityEngine.Object)を自動的に Destroy する。 + /// + public class RuntimeGltfInstance : MonoBehaviour, IResponsibilityForDestroyObjects + { + /// + /// this is UniGLTF root gameObject + /// + public GameObject Root => this.gameObject; + + List<(SubAssetKey, UnityEngine.Object)> m_resources = new List<(SubAssetKey, UnityEngine.Object)>(); + + public static RuntimeGltfInstance AttachTo(GameObject go, ImporterContext context) + { + var loaded = go.AddComponent(); + context.TransferOwnership((k, o) => + { + loaded.m_resources.Add((k, o)); + }); + return loaded; + } + + public void ShowMeshes() + { + foreach (var r in GetComponentsInChildren()) + { + r.enabled = true; + } + } + + public void EnableUpdateWhenOffscreen() + { + foreach (var smr in GetComponentsInChildren()) + { + smr.updateWhenOffscreen = true; + } + } + + void OnDestroy() + { + Debug.Log("UnityResourceDestroyer.OnDestroy"); + foreach (var (key, x) in m_resources) + { + UnityObjectDestoyer.DestroyRuntimeOrEditor(x); + } + } + + public void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) + { + foreach (var (key, x) in m_resources.ToArray()) + { + take(key, x); + m_resources.Remove((key, x)); + } + } + + public void Dispose() + { + UnityObjectDestoyer.DestroyRuntimeOrEditor(this.gameObject); + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/UnityResourceDestroyer.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs.meta similarity index 83% rename from Assets/UniGLTF/Runtime/UniGLTF/UnityResourceDestroyer.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs.meta index b07ef89ae4..af47451a06 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/UnityResourceDestroyer.cs.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 93b3af59a4d8b704a883260f2fd40c44 +guid: 423fb0cccbe420047ac28163cce68db4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Runtime/UniGLTF/UnityResourceDestroyer.cs b/Assets/UniGLTF/Runtime/UniGLTF/UnityResourceDestroyer.cs deleted file mode 100644 index b14ae9b457..0000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/UnityResourceDestroyer.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - - -namespace UniGLTF -{ - /// - /// Mesh, Material, Texture などを抱えておいて確実に破棄できるようにする - /// - public class UnityResourceDestroyer : MonoBehaviour - { - List m_resources = new List(); - public IList Resources => m_resources; - - void OnDestroy() - { - Debug.Log("UnityResourceDestroyer.OnDestroy"); - foreach (var x in Resources) - { -#if VRM_DEVELOP - Debug.Log($"Destroy: {x}"); -#endif - Destroy(x); - } - } - - public static Action DestroyResource() - { - Action des = (UnityEngine.Object o) => UnityEngine.Object.Destroy(o); - Action desi = (UnityEngine.Object o) => UnityEngine.Object.DestroyImmediate(o); - Action func = Application.isPlaying - ? des - : desi - ; - return func; - } - } -} diff --git a/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs b/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs index eedddfcba5..dad99978ee 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs @@ -93,27 +93,27 @@ static void RuntimeLoadExport(FileInfo gltf, int subStrStart) { try { - loader.Load(); + var loaded = loader.Load(); + if (loaded == null) + { + Debug.LogWarning($"root is null: ${gltf}"); + return; + } + + if (Skip.Contains(gltf.Directory.Parent.Name)) + { + // Export issue: + // skip + return; + } + + Export(loaded.gameObject); } catch (Exception ex) { Message(gltf.FullName.Substring(subStrStart), ex); } - if (Skip.Contains(gltf.Directory.Parent.Name)) - { - // Export issue: - // skip - return; - } - - if (loader.Root == null) - { - Debug.LogWarning($"root is null: ${gltf}"); - return; - } - - Export(loader.Root); } } diff --git a/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs b/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs index 2273be95e9..8f718abc10 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs @@ -120,9 +120,9 @@ public void UniGLTFSimpleSceneTest() // import using (var context = new ImporterContext(parser)) + using (var loaded = context.Load()) { - context.Load(); - AssertAreEqual(go.transform, context.Root.transform); + AssertAreEqual(go.transform, loaded.transform); } } @@ -557,16 +557,14 @@ public void SameMeshButDifferentMaterialExport() parser.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); using (var context = new ImporterContext(parser)) + using (var loaded = context.Load()) { - //Debug.LogFormat("{0}", context.Json); - context.Load(); - - var importedRed = context.Root.transform.GetChild(0); + var importedRed = loaded.transform.GetChild(0); var importedRedMaterial = importedRed.GetComponent().sharedMaterial; Assert.AreEqual("red", importedRedMaterial.name); Assert.AreEqual(Color.red, importedRedMaterial.color); - var importedBlue = context.Root.transform.GetChild(1); + var importedBlue = loaded.transform.GetChild(1); var importedBlueMaterial = importedBlue.GetComponent().sharedMaterial; Assert.AreEqual("blue", importedBlueMaterial.name); Assert.AreEqual(Color.blue, importedBlueMaterial.color); @@ -579,15 +577,14 @@ public void SameMeshButDifferentMaterialExport() parser.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); //Debug.LogFormat("{0}", context.Json); using (var context = new ImporterContext(parser)) + using (var loaded = context.Load()) { - context.Load(); - - var importedRed = context.Root.transform.GetChild(0); + var importedRed = loaded.transform.GetChild(0); var importedRedMaterial = importedRed.GetComponent().sharedMaterial; Assert.AreEqual("red", importedRedMaterial.name); Assert.AreEqual(Color.red, importedRedMaterial.color); - var importedBlue = context.Root.transform.GetChild(1); + var importedBlue = loaded.transform.GetChild(1); var importedBlueMaterial = importedBlue.GetComponent().sharedMaterial; Assert.AreEqual("blue", importedBlueMaterial.name); Assert.AreEqual(Color.blue, importedBlueMaterial.color); @@ -633,13 +630,11 @@ public void MeshHasNoRendererTest() parser.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); using (var context = new ImporterContext(parser)) + using (var loaded = context.Load()) { - context.Load(); - - Assert.AreEqual(1, context.Root.transform.GetChildren().Count()); - + Assert.AreEqual(1, loaded.transform.GetChildren().Count()); { - var child = context.Root.transform.GetChild(0); + var child = loaded.transform.GetChild(0); Assert.IsNull(child.GetSharedMesh()); } } @@ -700,18 +695,17 @@ public void ExportingNullMeshTest() parser.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); using (var context = new ImporterContext(parser)) + using (var loaded = context.Load()) { - context.Load(); - - Assert.AreEqual(2, context.Root.transform.GetChildren().Count()); + Assert.AreEqual(2, loaded.transform.GetChildren().Count()); { - var child = context.Root.transform.GetChild(0); + var child = loaded.transform.GetChild(0); Assert.IsNull(child.GetSharedMesh()); } { - var child = context.Root.transform.GetChild(1); + var child = loaded.transform.GetChild(1); Assert.IsNull(child.GetSharedMesh()); } } diff --git a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs index 72aca7a9b0..2f6aae909a 100644 --- a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs +++ b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs @@ -47,152 +47,144 @@ public void ImportExportTest() parser.ParseGlb(File.ReadAllBytes(path)); using (var context = new VRMImporterContext(parser)) + using (var loaded = context.Load()) { - context.Load(); - context.ShowMeshes(); - context.EnableUpdateWhenOffscreen(); + loaded.ShowMeshes(); + loaded.EnableUpdateWhenOffscreen(); - var destroyer = context.DisposeOnGameObjectDestroyed(); - try + // mesh { - // mesh + foreach (var renderer in loaded.GetComponentsInChildren()) { - foreach (var renderer in destroyer.GetComponentsInChildren()) + Mesh mesh = default; + if (renderer is MeshRenderer) { - Mesh mesh = default; - if (renderer is MeshRenderer) - { - var f = renderer.GetComponent(); - mesh = f.sharedMesh; - } - else if (renderer is SkinnedMeshRenderer smr) - { - mesh = smr.sharedMesh; - } + var f = renderer.GetComponent(); + mesh = f.sharedMesh; + } + else if (renderer is SkinnedMeshRenderer smr) + { + mesh = smr.sharedMesh; + } - var gltfMesh = parser.GLTF.meshes.Find(x => x.name == mesh.name); - Assert.AreEqual(gltfMesh.name, mesh.name); + var gltfMesh = parser.GLTF.meshes.Find(x => x.name == mesh.name); + Assert.AreEqual(gltfMesh.name, mesh.name); - // materials - foreach (var material in renderer.sharedMaterials) - { - var gltfMaterial = parser.GLTF.materials.Find(x => x.name == material.name); - Assert.AreEqual(gltfMaterial.name, material.name); + // materials + foreach (var material in renderer.sharedMaterials) + { + var gltfMaterial = parser.GLTF.materials.Find(x => x.name == material.name); + Assert.AreEqual(gltfMaterial.name, material.name); - var materialIndex = parser.GLTF.materials.IndexOf(gltfMaterial); - var vrmMaterial = context.VRM.materialProperties[materialIndex]; - // Debug.Log($"shaderName: '{vrmMaterial.shader}'"); - if (vrmMaterial.shader == "VRM/MToon") - { - // MToon - // Debug.Log($"{material.name} is MToon"); - foreach (var kv in vrmMaterial.textureProperties) - { - var texture = material.GetTexture(kv.Key); - // Debug.Log($"{kv.Key}: {texture}"); - Assert.NotNull(texture); - } - } - else if (glTF_KHR_materials_unlit.IsEnable(gltfMaterial)) - { - // Unlit - // Debug.Log($"{material.name} is unlit"); - throw new NotImplementedException(); - } - else + var materialIndex = parser.GLTF.materials.IndexOf(gltfMaterial); + var vrmMaterial = context.VRM.materialProperties[materialIndex]; + // Debug.Log($"shaderName: '{vrmMaterial.shader}'"); + if (vrmMaterial.shader == "VRM/MToon") + { + // MToon + // Debug.Log($"{material.name} is MToon"); + foreach (var kv in vrmMaterial.textureProperties) { - // PBR - // Debug.Log($"{material.name} is PBR"); - throw new NotImplementedException(); + var texture = material.GetTexture(kv.Key); + // Debug.Log($"{kv.Key}: {texture}"); + Assert.NotNull(texture); } } + else if (glTF_KHR_materials_unlit.IsEnable(gltfMaterial)) + { + // Unlit + // Debug.Log($"{material.name} is unlit"); + throw new NotImplementedException(); + } + else + { + // PBR + // Debug.Log($"{material.name} is PBR"); + throw new NotImplementedException(); + } } } + } - // meta - { - var meta = destroyer.GetComponent(); - } - - // humanoid - { - var animator = destroyer.GetComponent(); - } + // meta + { + var meta = loaded.GetComponent(); + } + // humanoid + { + var animator = loaded.GetComponent(); + } - // blendshape - { - var blendshapeProxy = destroyer.GetComponent(); - for (int i = 0; i < context.VRM.blendShapeMaster.blendShapeGroups.Count; ++i) - { - var gltfBlendShapeClip = context.VRM.blendShapeMaster.blendShapeGroups[i]; - var unityBlendShapeClip = blendshapeProxy.BlendShapeAvatar.Clips[i]; - Assert.AreEqual(Enum.Parse(typeof(BlendShapePreset), gltfBlendShapeClip.presetName, true), unityBlendShapeClip.Preset); - } - } - var importedJson = JsonParser.Parse(context.Json); - importedJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION, (f, x) => f.Value(x)); - importedJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION, (f, x) => f.Value(x)); - importedJson.SetValue("/scene", 0, (f, x) => f.Value(x)); - importedJson.SetValue("/materials/*/doubleSided", false, (f, x) => f.Value(x)); - //importJson.SetValue("/materials/*/pbrMetallicRoughness/roughnessFactor", 0); - //importJson.SetValue("/materials/*/pbrMetallicRoughness/baseColorFactor", new float[] { 1, 1, 1, 1 }); - importedJson.SetValue("/accessors/*/normalized", false, (f, x) => f.Value(x)); - importedJson.RemoveValue(Utf8String.From("/nodes/*/extras")); - /* - importJson.SetValue("/bufferViews/12/byteStride", 4); - importJson.SetValue("/bufferViews/13/byteStride", 4); - importJson.SetValue("/bufferViews/14/byteStride", 4); - importJson.SetValue("/bufferViews/15/byteStride", 4); - importJson.SetValue("/bufferViews/22/byteStride", 4); - importJson.SetValue("/bufferViews/29/byteStride", 4); - importJson.SetValue("/bufferViews/45/byteStride", 4); - importJson.SetValue("/bufferViews/46/byteStride", 4); - importJson.SetValue("/bufferViews/47/byteStride", 4); - importJson.SetValue("/bufferViews/201/byteStride", 4); - importJson.SetValue("/bufferViews/202/byteStride", 4); - importJson.SetValue("/bufferViews/203/byteStride", 4); - importJson.SetValue("/bufferViews/204/byteStride", 4); - importJson.SetValue("/bufferViews/211/byteStride", 4); - importJson.SetValue("/bufferViews/212/byteStride", 4); - importJson.SetValue("/bufferViews/213/byteStride", 4); - importJson.SetValue("/bufferViews/214/byteStride", 4); - importJson.SetValue("/bufferViews/215/byteStride", 4); - importJson.SetValue("/bufferViews/243/byteStride", 4); - importJson.SetValue("/bufferViews/247/byteStride", 64); - importJson.SetValue("/bufferViews/248/byteStride", 64); - importJson.SetValue("/bufferViews/249/byteStride", 64); - importJson.SetValue("/bufferViews/250/byteStride", 64); - importJson.SetValue("/bufferViews/251/byteStride", 64); - importJson.SetValue("/bufferViews/252/byteStride", 64); - importJson.SetValue("/bufferViews/253/byteStride", 64); - */ - importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride")); - - var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, context.Root, new EditorTextureSerializer()); - - // TODO: Check contents in JSON - /*var exportJson = */ - JsonParser.Parse(vrm.ToJson()); - - // TODO: Check contents in JSON - /*var newExportedJson = */ - // JsonParser.Parse(JsonSchema.FromType().Serialize(vrm)); - - /* - foreach (var kv in importJson.Diff(exportJson)) + // blendshape + { + var blendshapeProxy = loaded.GetComponent(); + for (int i = 0; i < context.VRM.blendShapeMaster.blendShapeGroups.Count; ++i) { - Debug.Log(kv); + var gltfBlendShapeClip = context.VRM.blendShapeMaster.blendShapeGroups[i]; + var unityBlendShapeClip = blendshapeProxy.BlendShapeAvatar.Clips[i]; + Assert.AreEqual(Enum.Parse(typeof(BlendShapePreset), gltfBlendShapeClip.presetName, true), unityBlendShapeClip.Preset); } - - Assert.AreEqual(importJson, exportJson); - */ } - finally + + var importedJson = JsonParser.Parse(context.Json); + importedJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION, (f, x) => f.Value(x)); + importedJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION, (f, x) => f.Value(x)); + importedJson.SetValue("/scene", 0, (f, x) => f.Value(x)); + importedJson.SetValue("/materials/*/doubleSided", false, (f, x) => f.Value(x)); + //importJson.SetValue("/materials/*/pbrMetallicRoughness/roughnessFactor", 0); + //importJson.SetValue("/materials/*/pbrMetallicRoughness/baseColorFactor", new float[] { 1, 1, 1, 1 }); + importedJson.SetValue("/accessors/*/normalized", false, (f, x) => f.Value(x)); + importedJson.RemoveValue(Utf8String.From("/nodes/*/extras")); + /* + importJson.SetValue("/bufferViews/12/byteStride", 4); + importJson.SetValue("/bufferViews/13/byteStride", 4); + importJson.SetValue("/bufferViews/14/byteStride", 4); + importJson.SetValue("/bufferViews/15/byteStride", 4); + importJson.SetValue("/bufferViews/22/byteStride", 4); + importJson.SetValue("/bufferViews/29/byteStride", 4); + importJson.SetValue("/bufferViews/45/byteStride", 4); + importJson.SetValue("/bufferViews/46/byteStride", 4); + importJson.SetValue("/bufferViews/47/byteStride", 4); + importJson.SetValue("/bufferViews/201/byteStride", 4); + importJson.SetValue("/bufferViews/202/byteStride", 4); + importJson.SetValue("/bufferViews/203/byteStride", 4); + importJson.SetValue("/bufferViews/204/byteStride", 4); + importJson.SetValue("/bufferViews/211/byteStride", 4); + importJson.SetValue("/bufferViews/212/byteStride", 4); + importJson.SetValue("/bufferViews/213/byteStride", 4); + importJson.SetValue("/bufferViews/214/byteStride", 4); + importJson.SetValue("/bufferViews/215/byteStride", 4); + importJson.SetValue("/bufferViews/243/byteStride", 4); + importJson.SetValue("/bufferViews/247/byteStride", 64); + importJson.SetValue("/bufferViews/248/byteStride", 64); + importJson.SetValue("/bufferViews/249/byteStride", 64); + importJson.SetValue("/bufferViews/250/byteStride", 64); + importJson.SetValue("/bufferViews/251/byteStride", 64); + importJson.SetValue("/bufferViews/252/byteStride", 64); + importJson.SetValue("/bufferViews/253/byteStride", 64); + */ + importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride")); + + var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, loaded.gameObject, new EditorTextureSerializer()); + + // TODO: Check contents in JSON + /*var exportJson = */ + JsonParser.Parse(vrm.ToJson()); + + // TODO: Check contents in JSON + /*var newExportedJson = */ + // JsonParser.Parse(JsonSchema.FromType().Serialize(vrm)); + + /* + foreach (var kv in importJson.Diff(exportJson)) { - UnityEngine.Object.DestroyImmediate(destroyer.gameObject); + Debug.Log(kv); } + + Assert.AreEqual(importJson, exportJson); + */ } } @@ -204,10 +196,10 @@ public void MeshCopyTest() parser.ParseGlb(File.ReadAllBytes(path)); using (var context = new VRMImporterContext(parser)) + using (var loaded = context.Load()) { - context.Load(); - context.ShowMeshes(); - context.EnableUpdateWhenOffscreen(); + loaded.ShowMeshes(); + loaded.EnableUpdateWhenOffscreen(); foreach (var mesh in context.Meshes) { var src = mesh.Mesh; diff --git a/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs b/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs index be398c101a..7159d90b75 100644 --- a/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs +++ b/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs @@ -59,13 +59,12 @@ async void OnLoadClicked() Debug.LogFormat("meta: title:{0}", meta.Title); // ParseしたJSONをシーンオブジェクトに変換していく - await context.LoadAsync(); + var loaded = await context.LoadAsync(); - context.ShowMeshes(); - context.EnableUpdateWhenOffscreen(); - var destroyer = context.DisposeOnGameObjectDestroyed(); + loaded.ShowMeshes(); + loaded.EnableUpdateWhenOffscreen(); - OnLoaded(destroyer.gameObject); + OnLoaded(loaded.gameObject); } } diff --git a/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs b/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs index 023690a18e..bb5ad6e964 100644 --- a/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs +++ b/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs @@ -97,16 +97,17 @@ async void LoadVRMClicked() Debug.LogFormat("meta: title:{0}", meta.Title); // ParseしたJSONをシーンオブジェクトに変換していく + var loaded = default(RuntimeGltfInstance); if (m_loadAsync) { - await context.LoadAsync(); + loaded = await context.LoadAsync(); } else { - context.Load(); + loaded = context.Load(); } - OnLoaded(context); + OnLoaded(loaded); } } @@ -135,15 +136,16 @@ async void LoadVRMClicked_without_meta() parser.ParseGlb(bytes); var context = new VRMImporterContext(parser); + var loaded = default(RuntimeGltfInstance); if (m_loadAsync) { - await context.LoadAsync(); + loaded = await context.LoadAsync(); } else { - context.Load(); + loaded = context.Load(); } - OnLoaded(context); + OnLoaded(loaded); } void LoadBVHClicked() @@ -165,15 +167,14 @@ void LoadBVHClicked() #endif } - void OnLoaded(VRMImporterContext context) + void OnLoaded(RuntimeGltfInstance loaded) { - var root = context.Root; + var root = loaded.gameObject; root.transform.SetParent(transform, false); //メッシュを表示します - context.ShowMeshes(); - context.DisposeOnGameObjectDestroyed(); + loaded.ShowMeshes(); // add motion var humanPoseTransfer = root.AddComponent(); diff --git a/Assets/VRM.Samples/Scripts/ViewerUI.cs b/Assets/VRM.Samples/Scripts/ViewerUI.cs index 81af05dc50..5a7eb185a8 100644 --- a/Assets/VRM.Samples/Scripts/ViewerUI.cs +++ b/Assets/VRM.Samples/Scripts/ViewerUI.cs @@ -317,11 +317,10 @@ async void LoadModelAsync(string path) using (var context = new VRMImporterContext(parser)) { await m_texts.UpdateMetaAsync(context); - await context.LoadAsync(); - context.EnableUpdateWhenOffscreen(); - context.ShowMeshes(); - context.DisposeOnGameObjectDestroyed(); - SetModel(context.Root); + var loaded = await context.LoadAsync(); + loaded.EnableUpdateWhenOffscreen(); + loaded.ShowMeshes(); + SetModel(loaded.gameObject); } break; } @@ -333,11 +332,10 @@ async void LoadModelAsync(string path) parser.ParseGlb(file); var context = new UniGLTF.ImporterContext(parser); - context.Load(); - context.EnableUpdateWhenOffscreen(); - context.ShowMeshes(); - context.DisposeOnGameObjectDestroyed(); - SetModel(context.Root); + var loaded = context.Load(); + loaded.EnableUpdateWhenOffscreen(); + loaded.ShowMeshes(); + SetModel(loaded.gameObject); break; } @@ -348,11 +346,10 @@ async void LoadModelAsync(string path) parser.ParsePath(path); var context = new UniGLTF.ImporterContext(parser); - context.Load(); - context.EnableUpdateWhenOffscreen(); - context.ShowMeshes(); - context.DisposeOnGameObjectDestroyed(); - SetModel(context.Root); + var loaded = context.Load(); + loaded.EnableUpdateWhenOffscreen(); + loaded.ShowMeshes(); + SetModel(loaded.gameObject); break; } diff --git a/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs b/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs index 2c03ea8574..552bff92de 100644 --- a/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs +++ b/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs @@ -108,61 +108,51 @@ public void ConvertAndExtractImages(Action> onTextureRelo TextureExtractor.ExtractTextures(m_context.Parser, m_prefabPath.Parent.Child(dirName), m_context.TextureDescriptorGenerator, subAssets, (_x, _y) => { }, onTextureReloaded); } - bool SaveAsAsset(UnityEngine.Object o) + void SaveAsAsset(SubAssetKey _, UnityEngine.Object o) { - if (o is GameObject) - { - return false; - } - if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))) { - // already exists. not dispose #if VRM_DEVELOP - Debug.Log($"Loaded. skip: {o}"); + // 来ない? + Debug.LogWarning($"{o} already exists. skip write"); #endif - return true; + return; } var assetPath = GetAssetPath(m_prefabPath, o); - if (assetPath.IsNull) + if (!assetPath.IsNull) { - // not dispose - return true; + // アセットとして書き込む + assetPath.Parent.EnsureFolder(); + assetPath.CreateAsset(o); + m_paths.Add(assetPath); } - - // アセットとして書き込む - assetPath.Parent.EnsureFolder(); - assetPath.CreateAsset(o); - m_paths.Add(assetPath); - - // 所有権が移動 - return true; } - public void SaveAsAsset() + public void SaveAsAsset(UniGLTF.RuntimeGltfInstance loaded) { - m_context.ShowMeshes(); + loaded.ShowMeshes(); // // save sub assets // m_paths.Clear(); m_paths.Add(m_prefabPath); - m_context.TransferOwnership(SaveAsAsset); + loaded.TransferOwnership(SaveAsAsset); + var root = loaded.Root; + GameObject.DestroyImmediate(loaded); // Create or update Main Asset if (m_prefabPath.IsFileExists) { Debug.LogFormat("replace prefab: {0}", m_prefabPath); var prefab = m_prefabPath.LoadAsset(); - PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction); - + PrefabUtility.SaveAsPrefabAssetAndConnect(root, m_prefabPath.Value, InteractionMode.AutomatedAction); } else { Debug.LogFormat("create prefab: {0}", m_prefabPath); - PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction); + PrefabUtility.SaveAsPrefabAssetAndConnect(root, m_prefabPath.Value, InteractionMode.AutomatedAction); } foreach (var x in m_paths) diff --git a/Assets/VRM/Editor/Format/VRMImporterMenu.cs b/Assets/VRM/Editor/Format/VRMImporterMenu.cs index df531c930e..83e41a089d 100644 --- a/Assets/VRM/Editor/Format/VRMImporterMenu.cs +++ b/Assets/VRM/Editor/Format/VRMImporterMenu.cs @@ -50,11 +50,10 @@ static void ImportRuntime(string path) using (var context = new VRMImporterContext(parser)) { - context.Load(); - context.EnableUpdateWhenOffscreen(); - context.ShowMeshes(); - context.DisposeOnGameObjectDestroyed(); - Selection.activeGameObject = context.Root; + var loaded = context.Load(); + loaded.EnableUpdateWhenOffscreen(); + loaded.ShowMeshes(); + Selection.activeGameObject = loaded.gameObject; } } @@ -88,8 +87,8 @@ static void ImportAsset(string path, UnityPath prefabPath) { VRMShaders.TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures); } - context.Load(); - editor.SaveAsAsset(); + var loaded = context.Load(); + editor.SaveAsAsset(loaded); } }; diff --git a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs index 415b616bad..10c83d5396 100644 --- a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs +++ b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs @@ -63,8 +63,8 @@ static void ImportVrm(UnityPath vrmPath) { VRMShaders.TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures); } - context.Load(); - editor.SaveAsAsset(); + var loaded = context.Load(); + editor.SaveAsAsset(loaded); } }; diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index f2fcca636e..eebf178e4f 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -317,36 +317,30 @@ public async Task ReadMetaAsync(IAwaitCaller awaitCaller = null, return meta; } - public override void TransferOwnership(Func take) + public override void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) { + // VRM-0 は SubAssetKey を使っていないので default で済ます + // VRM 固有のリソース(ScriptableObject) - if (take(HumanoidAvatar)) - { - HumanoidAvatar = null; - } + take(default, HumanoidAvatar); + HumanoidAvatar = null; - if (take(Meta)) - { - Meta = null; - } + take(default, Meta); + Meta = null; - if (take(AvatarDescription)) - { - AvatarDescription = null; - } + take(default, AvatarDescription); + AvatarDescription = null; foreach (var x in BlendShapeAvatar.Clips) { - if (take(x)) + take(default, x); { // do nothing } } - if (take(BlendShapeAvatar)) - { - BlendShapeAvatar = null; - } + take(default, BlendShapeAvatar); + BlendShapeAvatar = null; // GLTF のリソース base.TransferOwnership(take); @@ -354,28 +348,26 @@ public override void TransferOwnership(Func take) public override void Dispose() { - Action destroy = UnityResourceDestroyer.DestroyResource(); - // VRM specific if (HumanoidAvatar != null) { - destroy(HumanoidAvatar); + UnityObjectDestoyer.DestroyRuntimeOrEditor(HumanoidAvatar); } if (Meta != null) { - destroy(Meta); + UnityObjectDestoyer.DestroyRuntimeOrEditor(Meta); } if (AvatarDescription != null) { - destroy(AvatarDescription); + UnityObjectDestoyer.DestroyRuntimeOrEditor(AvatarDescription); } if (BlendShapeAvatar != null) { foreach (var clip in BlendShapeAvatar.Clips) { - destroy(clip); + UnityObjectDestoyer.DestroyRuntimeOrEditor(clip); } - destroy(BlendShapeAvatar); + UnityObjectDestoyer.DestroyRuntimeOrEditor(BlendShapeAvatar); } base.Dispose(); diff --git a/Assets/VRM/Tests/VRMLoadTests.cs b/Assets/VRM/Tests/VRMLoadTests.cs index 5090016809..db4e7ee659 100644 --- a/Assets/VRM/Tests/VRMLoadTests.cs +++ b/Assets/VRM/Tests/VRMLoadTests.cs @@ -74,8 +74,7 @@ static GameObject Load(FileInfo gltf, DirectoryInfo root, byte[] bytes = null) { using (var importer = new VRMImporterContext(parser)) { - importer.Load(); - return importer.DisposeOnGameObjectDestroyed().gameObject; + return importer.Load().gameObject; } } catch (Exception ex) diff --git a/Assets/VRM/Tests/VRMLookAtTests.cs b/Assets/VRM/Tests/VRMLookAtTests.cs index 702d1bf1df..8e071635c9 100644 --- a/Assets/VRM/Tests/VRMLookAtTests.cs +++ b/Assets/VRM/Tests/VRMLookAtTests.cs @@ -24,11 +24,11 @@ public void VRMLookAtTest() parser.ParsePath(AliciaPath); byte[] bytes = default; using (var loader = new VRMImporterContext(parser)) + using (var loaded = loader.Load()) { - loader.Load(); - loader.ShowMeshes(); + loaded.ShowMeshes(); - var go = loader.Root; + var go = loaded.gameObject; var fp = go.GetComponent(); GameObject.DestroyImmediate(go.GetComponent()); var lookAt = go.AddComponent(); @@ -54,11 +54,11 @@ public void VRMLookAtCurveMapWithFreezeTest() byte[] bytes = default; CurveMapper horizontalInner = default; using (var loader = new VRMImporterContext(parser)) + using (var loaded = loader.Load()) { - loader.Load(); - loader.ShowMeshes(); + loaded.ShowMeshes(); - var go = loader.Root; + var go = loaded.gameObject; var fp = go.GetComponent(); var lookAt = go.GetComponent(); horizontalInner = lookAt.HorizontalInner; @@ -71,11 +71,11 @@ public void VRMLookAtCurveMapWithFreezeTest() var parser2 = new GltfParser(); parser2.Parse(AliciaPath, bytes); using (var loader = new VRMImporterContext(parser2)) + using (var loaded = loader.Load()) { - loader.Load(); - loader.ShowMeshes(); + loaded.ShowMeshes(); - var lookAt = loader.Root.GetComponent(); + var lookAt = loaded.GetComponent(); Assert.AreEqual(horizontalInner.CurveXRangeDegree, lookAt.HorizontalInner.CurveXRangeDegree); Assert.AreEqual(horizontalInner.CurveYRangeDegree, lookAt.HorizontalInner.CurveYRangeDegree); } @@ -89,11 +89,11 @@ public void VRMLookAtCurveMapTest() byte[] bytes = default; CurveMapper horizontalInner = default; using (var loader = new VRMImporterContext(parser)) + using (var loaded = loader.Load()) { - loader.Load(); - loader.ShowMeshes(); + loaded.ShowMeshes(); - var go = loader.Root; + var go = loaded.gameObject; var fp = go.GetComponent(); var lookAt = go.GetComponent(); horizontalInner = lookAt.HorizontalInner; @@ -106,11 +106,11 @@ public void VRMLookAtCurveMapTest() var parser2 = new GltfParser(); parser2.Parse(AliciaPath, bytes); using (var loader = new VRMImporterContext(parser2)) + using (var loaded = loader.Load()) { - loader.Load(); - loader.ShowMeshes(); + loaded.ShowMeshes(); - var lookAt = loader.Root.GetComponent(); + var lookAt = loaded.GetComponent(); Assert.AreEqual(horizontalInner.CurveXRangeDegree, lookAt.HorizontalInner.CurveXRangeDegree); Assert.AreEqual(horizontalInner.CurveYRangeDegree, lookAt.HorizontalInner.CurveYRangeDegree); } diff --git a/Assets/VRM/Tests/VrmDividedMeshTests.cs b/Assets/VRM/Tests/VrmDividedMeshTests.cs index f1bdc46af9..ccb2babf23 100644 --- a/Assets/VRM/Tests/VrmDividedMeshTests.cs +++ b/Assets/VRM/Tests/VrmDividedMeshTests.cs @@ -26,9 +26,9 @@ static GameObject Load(byte[] bytes, string path) using (var loader = new VRMImporterContext(parser)) { - loader.Load(); - loader.ShowMeshes(); - return loader.DisposeOnGameObjectDestroyed().gameObject; + var loaded = loader.Load(); + loaded.ShowMeshes(); + return loaded.gameObject; } } diff --git a/Assets/VRM10.Samples/Runtime/ViewerUI.cs b/Assets/VRM10.Samples/Runtime/ViewerUI.cs index 35b4414336..d64d08f004 100644 --- a/Assets/VRM10.Samples/Runtime/ViewerUI.cs +++ b/Assets/VRM10.Samples/Runtime/ViewerUI.cs @@ -308,18 +308,17 @@ void LoadModel(string path) { case ".vrm": { - if(!Vrm10Parser.TryParseOrMigrate(path, doMigrate: true, out Vrm10Parser.Result result, out string error)) + if (!Vrm10Parser.TryParseOrMigrate(path, doMigrate: true, out Vrm10Parser.Result result, out string error)) { Debug.LogError(error); return; } using (var loader = new Vrm10Importer(result.Parser, result.Vrm)) { - loader.Load(); - loader.ShowMeshes(); - loader.EnableUpdateWhenOffscreen(); - var destroyer = loader.DisposeOnGameObjectDestroyed(); - SetModel(destroyer.gameObject); + var loaded = loader.Load(); + loaded.ShowMeshes(); + loaded.EnableUpdateWhenOffscreen(); + SetModel(loaded.gameObject); } break; } @@ -332,12 +331,10 @@ void LoadModel(string path) using (var loader = new UniGLTF.ImporterContext(parser)) { - loader.Load(); - loader.ShowMeshes(); - loader.EnableUpdateWhenOffscreen(); - loader.ShowMeshes(); - var destroyer = loader.DisposeOnGameObjectDestroyed(); - SetModel(destroyer.gameObject); + var loaded = loader.Load(); + loaded.ShowMeshes(); + loaded.EnableUpdateWhenOffscreen(); + SetModel(loaded.gameObject); } break; } @@ -350,12 +347,10 @@ void LoadModel(string path) using (var loader = new UniGLTF.ImporterContext(parser)) { - loader.Load(); - loader.ShowMeshes(); - loader.EnableUpdateWhenOffscreen(); - loader.ShowMeshes(); - var destroyer = loader.DisposeOnGameObjectDestroyed(); - SetModel(destroyer.gameObject); + var loaded = loader.Load(); + loaded.ShowMeshes(); + loaded.EnableUpdateWhenOffscreen(); + SetModel(loaded.gameObject); } break; } diff --git a/Assets/VRM10/Editor/ScriptedImporter/EditorVrm.cs b/Assets/VRM10/Editor/ScriptedImporter/EditorVrm.cs index 37e0d03f9d..48cd04591d 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/EditorVrm.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/EditorVrm.cs @@ -15,18 +15,6 @@ namespace UniVRM10 { public static class EditorVrm { - static ExpressionKey CreateKey(UniGLTF.Extensions.VRMC_vrm.Expression expression) - { - if (expression.Preset == UniGLTF.Extensions.VRMC_vrm.ExpressionPreset.custom) - { - return ExpressionKey.CreateCustom(expression.Name); - } - else - { - return ExpressionKey.CreateFromPreset(expression.Preset); - } - } - public static void OnGUI(ScriptedImporter importer, GltfParser parser, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm) { var hasExternal = importer.GetExternalObjectMap().Any(x => x.Value is VRM10MetaObject || x.Value is VRM10ExpressionAvatar || x.Value is VRM10Expression); @@ -42,7 +30,7 @@ public static void OnGUI(ScriptedImporter importer, GltfParser parser, UniGLTF.E importer.DrawRemapGUI(new SubAssetKey[] { VRM10MetaObject.SubAssetKey }); // expressions - importer.DrawRemapGUI(vrm.Expressions.Select(x => CreateKey(x).SubAssetKey)); + importer.DrawRemapGUI(vrm.Expressions.Select(x => ExpressionKey.CreateFromVrm10(x).SubAssetKey)); if (GUILayout.Button("Clear")) { diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs index 948295c4fd..334a1df38c 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs @@ -42,20 +42,18 @@ public static void Import(ScriptedImporter scriptedImporter, AssetImportContext VRMShaders.TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalTextures); } - loader.Load(); - loader.ShowMeshes(); + var loaded = loader.Load(); + loaded.ShowMeshes(); - loader.TransferOwnership(o => + loaded.TransferOwnership((key, o) => { - context.AddObjectToAsset(o.name, o); - if (o is GameObject) - { - // Root GameObject is main object - context.SetMainObject(loader.Root); - } - - return true; + context.AddObjectToAsset(key.Name, o); }); + var root = loaded.Root; + GameObject.DestroyImmediate(loaded); + + context.AddObjectToAsset(root.name, root); + context.SetMainObject(root); } } } diff --git a/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs b/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs index f9bb60ab6b..19a1ef27fc 100644 --- a/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs +++ b/Assets/VRM10/Runtime/Components/Expression/ExpressionKey.cs @@ -133,6 +133,18 @@ public static ExpressionKey CreateFromClip(VRM10Expression clip) return new ExpressionKey(clip.Preset, clip.ExpressionName); } + public static ExpressionKey CreateFromVrm10(UniGLTF.Extensions.VRMC_vrm.Expression expression) + { + if (expression.Preset == UniGLTF.Extensions.VRMC_vrm.ExpressionPreset.custom) + { + return ExpressionKey.CreateCustom(expression.Name); + } + else + { + return ExpressionKey.CreateFromPreset(expression.Preset); + } + } + public override string ToString() { return _id.Replace(UnknownPresetPrefix, ""); diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index b1ae1537fb..058a866f17 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using UniGLTF; using UnityEngine; -using VrmLib; using VRMShaders; @@ -16,7 +14,7 @@ namespace UniVRM10 /// public class Vrm10Importer : UniGLTF.ImporterContext { - readonly Model m_model; + readonly VrmLib.Model m_model; UniGLTF.Extensions.VRMC_vrm.VRMC_vrm m_vrm; @@ -54,61 +52,61 @@ public Vrm10Importer( // assign humanoid bones if (m_vrm.Humanoid != null) { - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Hips, HumanoidBones.hips); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftUpperLeg, HumanoidBones.leftUpperLeg); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightUpperLeg, HumanoidBones.rightUpperLeg); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLowerLeg, HumanoidBones.leftLowerLeg); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLowerLeg, HumanoidBones.rightLowerLeg); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftFoot, HumanoidBones.leftFoot); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightFoot, HumanoidBones.rightFoot); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Spine, HumanoidBones.spine); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Chest, HumanoidBones.chest); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Neck, HumanoidBones.neck); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Head, HumanoidBones.head); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftShoulder, HumanoidBones.leftShoulder); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightShoulder, HumanoidBones.rightShoulder); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftUpperArm, HumanoidBones.leftUpperArm); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightUpperArm, HumanoidBones.rightUpperArm); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLowerArm, HumanoidBones.leftLowerArm); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLowerArm, HumanoidBones.rightLowerArm); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftHand, HumanoidBones.leftHand); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightHand, HumanoidBones.rightHand); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftToes, HumanoidBones.leftToes); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightToes, HumanoidBones.rightToes); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftEye, HumanoidBones.leftEye); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightEye, HumanoidBones.rightEye); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Jaw, HumanoidBones.jaw); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftThumbProximal, HumanoidBones.leftThumbProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftThumbIntermediate, HumanoidBones.leftThumbIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftThumbDistal, HumanoidBones.leftThumbDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftIndexProximal, HumanoidBones.leftIndexProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftIndexIntermediate, HumanoidBones.leftIndexIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftIndexDistal, HumanoidBones.leftIndexDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftMiddleProximal, HumanoidBones.leftMiddleProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftMiddleIntermediate, HumanoidBones.leftMiddleIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftMiddleDistal, HumanoidBones.leftMiddleDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftRingProximal, HumanoidBones.leftRingProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftRingIntermediate, HumanoidBones.leftRingIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftRingDistal, HumanoidBones.leftRingDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLittleProximal, HumanoidBones.leftLittleProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLittleIntermediate, HumanoidBones.leftLittleIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLittleDistal, HumanoidBones.leftLittleDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightThumbProximal, HumanoidBones.rightThumbProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightThumbIntermediate, HumanoidBones.rightThumbIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightThumbDistal, HumanoidBones.rightThumbDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightIndexProximal, HumanoidBones.rightIndexProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightIndexIntermediate, HumanoidBones.rightIndexIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightIndexDistal, HumanoidBones.rightIndexDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightMiddleProximal, HumanoidBones.rightMiddleProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightMiddleIntermediate, HumanoidBones.rightMiddleIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightMiddleDistal, HumanoidBones.rightMiddleDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightRingProximal, HumanoidBones.rightRingProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightRingIntermediate, HumanoidBones.rightRingIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightRingDistal, HumanoidBones.rightRingDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLittleProximal, HumanoidBones.rightLittleProximal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLittleIntermediate, HumanoidBones.rightLittleIntermediate); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLittleDistal, HumanoidBones.rightLittleDistal); - AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.UpperChest, HumanoidBones.upperChest); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Hips, VrmLib.HumanoidBones.hips); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftUpperLeg, VrmLib.HumanoidBones.leftUpperLeg); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightUpperLeg, VrmLib.HumanoidBones.rightUpperLeg); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLowerLeg, VrmLib.HumanoidBones.leftLowerLeg); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLowerLeg, VrmLib.HumanoidBones.rightLowerLeg); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftFoot, VrmLib.HumanoidBones.leftFoot); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightFoot, VrmLib.HumanoidBones.rightFoot); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Spine, VrmLib.HumanoidBones.spine); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Chest, VrmLib.HumanoidBones.chest); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Neck, VrmLib.HumanoidBones.neck); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Head, VrmLib.HumanoidBones.head); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftShoulder, VrmLib.HumanoidBones.leftShoulder); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightShoulder, VrmLib.HumanoidBones.rightShoulder); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftUpperArm, VrmLib.HumanoidBones.leftUpperArm); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightUpperArm, VrmLib.HumanoidBones.rightUpperArm); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLowerArm, VrmLib.HumanoidBones.leftLowerArm); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLowerArm, VrmLib.HumanoidBones.rightLowerArm); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftHand, VrmLib.HumanoidBones.leftHand); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightHand, VrmLib.HumanoidBones.rightHand); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftToes, VrmLib.HumanoidBones.leftToes); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightToes, VrmLib.HumanoidBones.rightToes); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftEye, VrmLib.HumanoidBones.leftEye); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightEye, VrmLib.HumanoidBones.rightEye); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.Jaw, VrmLib.HumanoidBones.jaw); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftThumbProximal, VrmLib.HumanoidBones.leftThumbProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftThumbIntermediate, VrmLib.HumanoidBones.leftThumbIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftThumbDistal, VrmLib.HumanoidBones.leftThumbDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftIndexProximal, VrmLib.HumanoidBones.leftIndexProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftIndexIntermediate, VrmLib.HumanoidBones.leftIndexIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftIndexDistal, VrmLib.HumanoidBones.leftIndexDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftMiddleProximal, VrmLib.HumanoidBones.leftMiddleProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftMiddleIntermediate, VrmLib.HumanoidBones.leftMiddleIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftMiddleDistal, VrmLib.HumanoidBones.leftMiddleDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftRingProximal, VrmLib.HumanoidBones.leftRingProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftRingIntermediate, VrmLib.HumanoidBones.leftRingIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftRingDistal, VrmLib.HumanoidBones.leftRingDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLittleProximal, VrmLib.HumanoidBones.leftLittleProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLittleIntermediate, VrmLib.HumanoidBones.leftLittleIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.LeftLittleDistal, VrmLib.HumanoidBones.leftLittleDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightThumbProximal, VrmLib.HumanoidBones.rightThumbProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightThumbIntermediate, VrmLib.HumanoidBones.rightThumbIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightThumbDistal, VrmLib.HumanoidBones.rightThumbDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightIndexProximal, VrmLib.HumanoidBones.rightIndexProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightIndexIntermediate, VrmLib.HumanoidBones.rightIndexIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightIndexDistal, VrmLib.HumanoidBones.rightIndexDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightMiddleProximal, VrmLib.HumanoidBones.rightMiddleProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightMiddleIntermediate, VrmLib.HumanoidBones.rightMiddleIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightMiddleDistal, VrmLib.HumanoidBones.rightMiddleDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightRingProximal, VrmLib.HumanoidBones.rightRingProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightRingIntermediate, VrmLib.HumanoidBones.rightRingIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightRingDistal, VrmLib.HumanoidBones.rightRingDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLittleProximal, VrmLib.HumanoidBones.rightLittleProximal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLittleIntermediate, VrmLib.HumanoidBones.rightLittleIntermediate); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.RightLittleDistal, VrmLib.HumanoidBones.rightLittleDistal); + AssignHumanoid(m_model.Nodes, m_vrm.Humanoid.HumanBones.UpperChest, VrmLib.HumanoidBones.upperChest); } } @@ -124,7 +122,7 @@ public class ModelMap /// readonly ModelMap m_map = new ModelMap(); - static void AssignHumanoid(List nodes, UniGLTF.Extensions.VRMC_vrm.HumanBone humanBone, VrmLib.HumanoidBones key) + static void AssignHumanoid(List nodes, UniGLTF.Extensions.VRMC_vrm.HumanBone humanBone, VrmLib.HumanoidBones key) { if (humanBone != null && humanBone.Node.HasValue) { @@ -620,28 +618,22 @@ public static Renderer CreateRenderer(VrmLib.Node node, GameObject go, ModelMap return renderer; } - public override void TransferOwnership(Func take) + public override void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) { // VRM 固有のリソース(ScriptableObject) - if (take(m_humanoid)) - { - m_humanoid = null; - } + take(SubAssetKey.Create(m_humanoid), m_humanoid); + m_humanoid = null; if (m_meta != null) { - if (take(m_meta)) - { - m_meta = null; - } + take(VRM10MetaObject.SubAssetKey, m_meta); + m_meta = null; } foreach (var x in m_expressions) { - if (take(x)) - { - // do nothing - } + take(ExpressionKey.CreateFromClip(x).SubAssetKey, x); + // do nothing } m_expressions.Clear(); @@ -651,21 +643,19 @@ public override void TransferOwnership(Func take) public override void Dispose() { - Action destroy = UnityResourceDestroyer.DestroyResource(); - // VRM specific if (m_humanoid != null) { - destroy(m_humanoid); + UnityObjectDestoyer.DestroyRuntimeOrEditor(m_humanoid); } if (m_meta != null) { - destroy(m_meta); + UnityObjectDestoyer.DestroyRuntimeOrEditor(m_meta); } foreach (var clip in m_expressions) { - destroy(clip); + UnityObjectDestoyer.DestroyRuntimeOrEditor(clip); } base.Dispose(); diff --git a/Assets/VRM10/Runtime/Scenes/Sample.cs b/Assets/VRM10/Runtime/Scenes/Sample.cs index 211d1ce363..eba4892f9d 100644 --- a/Assets/VRM10/Runtime/Scenes/Sample.cs +++ b/Assets/VRM10/Runtime/Scenes/Sample.cs @@ -22,9 +22,9 @@ static GameObject Import(byte[] bytes, FileInfo path) using (var loader = new Vrm10Importer(result.Parser, result.Vrm)) { - loader.Load(); - loader.ShowMeshes(); - return loader.DisposeOnGameObjectDestroyed().gameObject; + var loaded = loader.Load(); + loaded.ShowMeshes(); + return loaded.gameObject; } } diff --git a/Assets/VRM10/Tests.PlayMode/MaterialTests.cs b/Assets/VRM10/Tests.PlayMode/MaterialTests.cs index 55a099959c..92017283d0 100644 --- a/Assets/VRM10/Tests.PlayMode/MaterialTests.cs +++ b/Assets/VRM10/Tests.PlayMode/MaterialTests.cs @@ -31,7 +31,7 @@ public class MaterialTests private (GameObject, IReadOnlyList) ToUnity(byte[] bytes) { // Vrm => Model - if(!Vrm10Parser.TryParseOrMigrate("tpm.vrm", bytes, true, out Vrm10Parser.Result result, out string error)) + if (!Vrm10Parser.TryParseOrMigrate("tpm.vrm", bytes, true, out Vrm10Parser.Result result, out string error)) { throw new Exception(); } @@ -44,9 +44,8 @@ public class MaterialTests // Model => Unity using (var loader = new Vrm10Importer(parser, vrm)) { - loader.Load(); - loader.DisposeOnGameObjectDestroyed(); - return (loader.Root, loader.MaterialFactory.Materials); + var loaded = loader.Load(); + return (loaded.gameObject, loader.MaterialFactory.Materials); } } diff --git a/Assets/VRM10/Tests/ApiSampleTests.cs b/Assets/VRM10/Tests/ApiSampleTests.cs index e4d1c722aa..79daf7e3db 100644 --- a/Assets/VRM10/Tests/ApiSampleTests.cs +++ b/Assets/VRM10/Tests/ApiSampleTests.cs @@ -24,13 +24,13 @@ GameObject BuildGameObject(GltfParser parser, VRMC_vrm vrm, bool showMesh) { using (var loader = new Vrm10Importer(parser, vrm)) { - loader.Load(); + var loaded = loader.Load(); if (showMesh) { - loader.ShowMeshes(); + loaded.ShowMeshes(); } - loader.EnableUpdateWhenOffscreen(); - return loader.DisposeOnGameObjectDestroyed().gameObject; + loaded.EnableUpdateWhenOffscreen(); + return loaded.gameObject; } } diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/IResponsibilityForDestroyObjects.cs b/Assets/VRMShaders/GLTF/IO/Runtime/IResponsibilityForDestroyObjects.cs new file mode 100644 index 0000000000..05ae257b32 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/IResponsibilityForDestroyObjects.cs @@ -0,0 +1,20 @@ +using System; + +namespace VRMShaders +{ + public delegate void TakeResponsibilityForDestroyObjectFunc(SubAssetKey key, UnityEngine.Object obj); + + /// + /// UnityObjectを破棄する責務。 + /// + /// この interface を実装するクラスは、利用後に破棄すべき UnityObject を保持する可能性があるので + /// Dispose により解放すること。 + /// + /// TransferOwnership により、破棄責任を移譲することができる。 + /// + /// + public interface IResponsibilityForDestroyObjects : IDisposable + { + void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take); + } +} diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/IResponsibilityForDestroyObjects.cs.meta b/Assets/VRMShaders/GLTF/IO/Runtime/IResponsibilityForDestroyObjects.cs.meta new file mode 100644 index 0000000000..bb07b2ed61 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/IResponsibilityForDestroyObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93ab2216c7e8c684d84873bd2ae72c6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/KeyValuePariExtensions.cs b/Assets/VRMShaders/GLTF/IO/Runtime/KeyValuePariExtensions.cs new file mode 100644 index 0000000000..91a41891ff --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/KeyValuePariExtensions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace VRMShaders +{ + public static class KeyValuePariExtensions + { + public static void Deconstruct(this KeyValuePair pair, out T key, out U value) + { + key = pair.Key; + value = pair.Value; + } + } +} diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/KeyValuePariExtensions.cs.meta b/Assets/VRMShaders/GLTF/IO/Runtime/KeyValuePariExtensions.cs.meta new file mode 100644 index 0000000000..ec64d27cb0 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/KeyValuePariExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7dd6ef3302d21eb4b83c4f8f2c1e47cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/MaterialFactory.cs b/Assets/VRMShaders/GLTF/IO/Runtime/MaterialFactory.cs index d30f029bcc..eb1ceb870f 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/MaterialFactory.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/MaterialFactory.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using UnityEngine; @@ -9,7 +8,7 @@ namespace VRMShaders { public delegate Task GetTextureAsyncFunc(TextureDescriptor texDesc); - public class MaterialFactory : IDisposable + public class MaterialFactory : IResponsibilityForDestroyObjects { private readonly IReadOnlyDictionary m_externalMap; @@ -30,13 +29,15 @@ public MaterialFactory(IReadOnlyDictionary externalMateri public struct MaterialLoadInfo { + public SubAssetKey Key; public readonly Material Asset; public readonly bool UseExternal; public bool IsSubAsset => !UseExternal; - public MaterialLoadInfo(Material asset, bool useExternal) + public MaterialLoadInfo(SubAssetKey key, Material asset, bool useExternal) { + Key = key; Asset = asset; UseExternal = useExternal; } @@ -64,7 +65,7 @@ public void Dispose() #if VRM_DEVELOP // Debug.Log($"Destroy {x.Asset}"); #endif - UnityEngine.Object.DestroyImmediate(x.Asset, false); + UnityObjectDestoyer.DestroyRuntimeOrEditor(x.Asset); } } } @@ -79,24 +80,17 @@ public void Dispose() /// /// /// - public void TransferOwnership(Func take) + public void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) { - var list = new List(); - foreach (var x in m_materials) + foreach (var x in m_materials.ToArray()) { if (!x.UseExternal) { // 外部の '.asset' からロードしていない - if (take(x.Asset)) - { - list.Add(x.Asset); - } + take(x.Key, x.Asset); + m_materials.Remove(x); } } - foreach (var x in list) - { - Remove(x); - } } public Material GetMaterial(int index) @@ -110,7 +104,7 @@ public async Task LoadAsync(MaterialDescriptor matDesc, GetTextureAsyn { if (m_externalMap.TryGetValue(matDesc.SubAssetKey, out Material material)) { - m_materials.Add(new MaterialLoadInfo(material, true)); + m_materials.Add(new MaterialLoadInfo(matDesc.SubAssetKey, material, true)); return material; } @@ -174,7 +168,7 @@ public async Task LoadAsync(MaterialDescriptor matDesc, GetTextureAsyn action(material); } - m_materials.Add(new MaterialLoadInfo(material, false)); + m_materials.Add(new MaterialLoadInfo(matDesc.SubAssetKey, material, false)); return material; } diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs b/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs index 702d7a863c..d9bd042b03 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using UnityEngine; namespace VRMShaders @@ -7,15 +6,16 @@ namespace VRMShaders /// /// UnityEditor.Experimental.AssetImporter.SourceAssetIdentifier に対応する /// - /// * SourceAssetIdentifier が UnityEditor なので、 Runtime でも使えるように + /// * SourceAssetIdentifier が UnityEditor なので、 Runtime でも使えるように作成 /// * Type が違うが Name が同じだと警告が出る。例えば、Material と 同じ名前の Texture がある場合。 /// Identifier uniqueness violation: 'Alicia_body'. Scripted Importers do not guarantee that subsequent imports of this asset will properly re-link to these targets. - /// * なので、SourceAssetIdentifier は、$"{Type.Name}.{UnityObject.name}" のように強制的に Unique にするのが良さそう - /// * 一方で、Extract したファイル名に $"{Type.Name}." が付属するのは煩わしいのでこれは無しにしたい。 /// /// public void AddRemap(SourceAssetIdentifier identifier, UnityEngine.Object externalObject); - /// - /// の呼び出し時に、identifier.name と externalObject.name が同じでない運用にしてみる。 + /// scriptedImporter.GetExternalObjectMap + /// + /// に関係する。 + /// + /// SubAssetKey を新しく作る場所は集約して、不一致が起こらないように注意する /// /// public readonly struct SubAssetKey : IEquatable @@ -48,6 +48,11 @@ public SubAssetKey(Material obj) Name = obj.name; } + public static SubAssetKey Create(T obj) where T : UnityEngine.Object + { + return new SubAssetKey(typeof(T), obj.name); + } + public SubAssetKey(Type type, string name) { if (type == null || string.IsNullOrEmpty(name)) diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/TextureFactory.cs b/Assets/VRMShaders/GLTF/IO/Runtime/TextureFactory.cs index d3bc48f0c6..e2f8ee6f21 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/TextureFactory.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/TextureFactory.cs @@ -6,7 +6,7 @@ namespace VRMShaders { - public class TextureFactory : IDisposable + public class TextureFactory : IResponsibilityForDestroyObjects { private readonly ITextureDeserializer _textureDeserializer; private readonly IReadOnlyDictionary _externalMap; @@ -33,7 +33,7 @@ public void Dispose() { foreach (var kv in _temporaryTextures) { - DestroyResource(kv.Value); + UnityObjectDestoyer.DestroyRuntimeOrEditor(kv.Value); } _temporaryTextures.Clear(); _textureCache.Clear(); @@ -43,20 +43,12 @@ public void Dispose() /// 所有権(Dispose権)を移譲する /// /// - public void TransferOwnership(Func take) + public void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) { - var transferredAssets = new HashSet(); - foreach (var x in _textureCache) + foreach (var (k, v) in _textureCache.ToArray()) { - if (take(x.Value)) - { - transferredAssets.Add(x.Key); - } - } - - foreach (var key in transferredAssets) - { - _textureCache.Remove(key); + take(k, v); + _textureCache.Remove(k); } } @@ -81,80 +73,68 @@ public async Task GetTextureAsync(TextureDescriptor texDesc) switch (texDesc.TextureType) { case TextureImportTypes.NormalMap: - { - // no conversion. Unity's normal map is same with glTF's. - // - // > contrary to Unity’s usual convention of using Y as “up” - // https://docs.unity3d.com/2018.4/Documentation/Manual/StandardShaderMaterialParameterNormalMap.html - var data0 = await texDesc.Index0(); - var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); - rawTexture.name = subAssetKey.Name; - rawTexture.SetSampler(texDesc.Sampler); - _textureCache.Add(subAssetKey, rawTexture); - return rawTexture; - } - - case TextureImportTypes.StandardMap: - { - Texture2D metallicRoughnessTexture = default; - Texture2D occlusionTexture = default; - - if (texDesc.Index0 != null) { + // no conversion. Unity's normal map is same with glTF's. + // + // > contrary to Unity’s usual convention of using Y as “up” + // https://docs.unity3d.com/2018.4/Documentation/Manual/StandardShaderMaterialParameterNormalMap.html var data0 = await texDesc.Index0(); - metallicRoughnessTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); + var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); + rawTexture.name = subAssetKey.Name; + rawTexture.SetSampler(texDesc.Sampler); + _textureCache.Add(subAssetKey, rawTexture); + return rawTexture; } - if (texDesc.Index1 != null) + + case TextureImportTypes.StandardMap: { - var data1 = await texDesc.Index1(); - occlusionTexture = await _textureDeserializer.LoadTextureAsync(data1, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); + Texture2D metallicRoughnessTexture = default; + Texture2D occlusionTexture = default; + + if (texDesc.Index0 != null) + { + var data0 = await texDesc.Index0(); + metallicRoughnessTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); + } + if (texDesc.Index1 != null) + { + var data1 = await texDesc.Index1(); + occlusionTexture = await _textureDeserializer.LoadTextureAsync(data1, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); + } + + var combinedTexture = OcclusionMetallicRoughnessConverter.Import(metallicRoughnessTexture, + texDesc.MetallicFactor, texDesc.RoughnessFactor, occlusionTexture); + combinedTexture.name = subAssetKey.Name; + combinedTexture.SetSampler(texDesc.Sampler); + _textureCache.Add(subAssetKey, combinedTexture); + UnityObjectDestoyer.DestroyRuntimeOrEditor(metallicRoughnessTexture); + UnityObjectDestoyer.DestroyRuntimeOrEditor(occlusionTexture); + return combinedTexture; } - var combinedTexture = OcclusionMetallicRoughnessConverter.Import(metallicRoughnessTexture, - texDesc.MetallicFactor, texDesc.RoughnessFactor, occlusionTexture); - combinedTexture.name = subAssetKey.Name; - combinedTexture.SetSampler(texDesc.Sampler); - _textureCache.Add(subAssetKey, combinedTexture); - DestroyResource(metallicRoughnessTexture); - DestroyResource(occlusionTexture); - return combinedTexture; - } - case TextureImportTypes.sRGB: - { - var data0 = await texDesc.Index0(); - var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.sRGB); - rawTexture.name = subAssetKey.Name; - rawTexture.SetSampler(texDesc.Sampler); - _textureCache.Add(subAssetKey, rawTexture); - return rawTexture; - } + { + var data0 = await texDesc.Index0(); + var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.sRGB); + rawTexture.name = subAssetKey.Name; + rawTexture.SetSampler(texDesc.Sampler); + _textureCache.Add(subAssetKey, rawTexture); + return rawTexture; + } case TextureImportTypes.Linear: - { - var data0 = await texDesc.Index0(); - var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); - rawTexture.name = subAssetKey.Name; - rawTexture.SetSampler(texDesc.Sampler); - _textureCache.Add(subAssetKey, rawTexture); - return rawTexture; - } + { + var data0 = await texDesc.Index0(); + var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear); + rawTexture.name = subAssetKey.Name; + rawTexture.SetSampler(texDesc.Sampler); + _textureCache.Add(subAssetKey, rawTexture); + return rawTexture; + } default: throw new ArgumentOutOfRangeException(); } throw new NotImplementedException(); } - - private static void DestroyResource(UnityEngine.Object o) - { - if (Application.isPlaying) - { - UnityEngine.Object.Destroy(o); - } - else - { - UnityEngine.Object.DestroyImmediate(o); - } - } } } diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/UnityObjectDestroyer.cs b/Assets/VRMShaders/GLTF/IO/Runtime/UnityObjectDestroyer.cs new file mode 100644 index 0000000000..d35cffc54d --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/UnityObjectDestroyer.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace VRMShaders +{ + public static class UnityObjectDestoyer + { + public static void DestroyRuntimeOrEditor(UnityEngine.Object o) + { + if (Application.isPlaying) + { + UnityEngine.Object.Destroy(o); + } + else + { + UnityEngine.Object.DestroyImmediate(o); + } + } + } +} diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/UnityObjectDestroyer.cs.meta b/Assets/VRMShaders/GLTF/IO/Runtime/UnityObjectDestroyer.cs.meta new file mode 100644 index 0000000000..e4fc70f72a --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/UnityObjectDestroyer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b4d1043455aa2c489e9ad8250a80fc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: