diff --git a/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef b/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef index d1fb540d7..6c391dfbe 100644 --- a/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef +++ b/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef @@ -1,7 +1,8 @@ { "name": "UniGLTF.Editor", "references": [ - "UniGLTF" + "UniGLTF", + "MeshUtility.Editor" ], "optionalUnityReferences": [], "includePlatforms": [ diff --git a/Assets/UniGLTF/Editor/UniGLTF/ImporterMenu.cs b/Assets/UniGLTF/Editor/UniGLTF/ImporterMenu.cs index 32b1b603d..30d799abc 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ImporterMenu.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ImporterMenu.cs @@ -1,4 +1,5 @@ -using System.IO; +#if false +using System.IO; using UnityEditor; using UnityEngine; @@ -21,8 +22,10 @@ namespace UniGLTF // // load into scene // - var context = new ImporterContext(); - context.Load(path); + var parser = new GltfParser(); + parser.ParsePath(path); + var context = new ImporterContext(parser); + context.Load(); context.ShowMeshes(); Selection.activeGameObject = context.Root; } @@ -49,3 +52,4 @@ namespace UniGLTF } } } +#endif \ No newline at end of file diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter.meta b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter.meta new file mode 100644 index 000000000..58ddb67d9 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 552c42899d5f1664b8fba3faef53f3eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs new file mode 100644 index 000000000..9301ea1fd --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.Experimental.AssetImporters; +using UnityEngine; + + +namespace UniGLTF +{ + [ScriptedImporter(1, "glb")] + public class GltfScriptedImporter : ScriptedImporter + { + [SerializeField] + Axises m_reverseAxis = default; + + const string TextureDirName = "Textures"; + const string MaterialDirName = "Materials"; + + public override void OnImportAsset(AssetImportContext ctx) + { + Debug.Log("OnImportAsset to " + ctx.assetPath); + + try + { + // Parse + var parser = new GltfParser(); + parser.ParsePath(ctx.assetPath); + + // Build Unity Model + var externalObjectMap = GetExternalObjectMap() + .Select(kv => (kv.Key.name, kv.Value)) + ; + var context = new ImporterContext(parser, externalObjectMap); + context.InvertAxis = m_reverseAxis; + context.Load(); + context.ShowMeshes(); + + // Texture + foreach (var info in context.TextureFactory.Textures) + { + if (!info.IsUsed) + { + continue; + } + if (!info.IsExternal) + { + var texture = info.Texture; + ctx.AddObjectToAsset(texture.name, texture); + } + } + + // Material + foreach (var info in context.MaterialFactory.Materials) + { + if (!info.UseExternal) + { + var material = info.Asset; + ctx.AddObjectToAsset(material.name, material); + } + } + + // Mesh + foreach (var mesh in context.Meshes.Select(x => x.Mesh)) + { + ctx.AddObjectToAsset(mesh.name, mesh); + } + + // Animation + foreach (var clip in context.AnimationClips) + { + ctx.AddObjectToAsset(clip.name, clip); + } + + // Root + ctx.AddObjectToAsset(context.Root.name, context.Root); + ctx.SetMainObject(context.Root); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + } + } + + public void ExtractMaterialsAndTextures() + { + this.ExtractTextures(TextureDirName, () => + { + this.ExtractAssets(MaterialDirName, ".mat"); + AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); + }); + } + + public void SetExternalUnityObject(UnityEditor.AssetImporter.SourceAssetIdentifier sourceAssetIdentifier, T obj) where T : UnityEngine.Object + { + this.AddRemap(sourceAssetIdentifier, obj); + AssetDatabase.WriteImportSettingsIfDirty(this.assetPath); + AssetDatabase.ImportAsset(this.assetPath, ImportAssetOptions.ForceUpdate); + } + } +} diff --git a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporter.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs.meta similarity index 83% rename from Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporter.cs.meta rename to Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs.meta index d016d7b3a..e0edbf009 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporter.cs.meta +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5f9566aa8f690614f872fc63691397e9 +guid: aecd2106718f2444db3ca21345da2cef MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditorGUI.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditorGUI.cs new file mode 100644 index 000000000..579ba7c36 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditorGUI.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.Experimental.AssetImporters; +using UnityEngine; + +namespace UniGLTF +{ + [CustomEditor(typeof(GltfScriptedImporter))] + public class GltfScriptedImporterEditorGUI : ScriptedImporterEditor + { + GltfScriptedImporter m_importer; + GltfParser m_parser; + + public override void OnEnable() + { + m_importer = target as GltfScriptedImporter; + m_parser = new GltfParser(); + m_parser.ParsePath(m_importer.assetPath); + } + + enum Tabs + { + Model, + Animation, + Materials, + } + static Tabs s_currentTab; + + public override void OnInspectorGUI() + { + s_currentTab = MeshUtility.TabBar.OnGUI(s_currentTab); + GUILayout.Space(10); + + switch (s_currentTab) + { + case Tabs.Model: + base.OnInspectorGUI(); + break; + + case Tabs.Animation: + OnGUIAnimation(m_importer, m_parser); + break; + + case Tabs.Materials: + OnGUIMaterial(m_importer, m_parser); + break; + } + } + + static bool s_foldMaterials; + static bool s_foldTextures; + + class TmpGuiEnable : IDisposable + { + bool m_backup; + public TmpGuiEnable(bool enable) + { + m_backup = GUI.enabled; + GUI.enabled = enable; + } + + public void Dispose() + { + GUI.enabled = m_backup; + } + } + + static void OnGUIMaterial(GltfScriptedImporter importer, GltfParser parser) + { + var canExtract = !importer.GetExternalObjectMap().Any(x => x.Value is Material || x.Value is Texture2D); + using (new TmpGuiEnable(canExtract)) + { + if (GUILayout.Button("Extract Materials And Textures ...")) + { + importer.ExtractMaterialsAndTextures(); + } + } + + // ObjectMap + s_foldMaterials = EditorGUILayout.Foldout(s_foldMaterials, "Remapped Materials"); + if (s_foldMaterials) + { + DrawRemapGUI(importer, parser.GLTF.materials.Select(x => x.name)); + } + + s_foldTextures = EditorGUILayout.Foldout(s_foldTextures, "Remapped Textures"); + if (s_foldTextures) + { + DrawRemapGUI(importer, parser.EnumerateTextures().Select(x => x.Name)); + } + + if (GUILayout.Button("Clear")) + { + importer.ClearExternalObjects(); + importer.ClearExternalObjects(); + } + } + + static void DrawRemapGUI(GltfScriptedImporter importer, IEnumerable names) where T : UnityEngine.Object + { + EditorGUI.indentLevel++; + var map = importer.GetExternalObjectMap() + .Select(x => (x.Key.name, x.Value as T)) + .Where(x => x.Item2 != null) + .ToDictionary(x => x.Item1, x => x.Item2) + ; + foreach (var name in names) + { + if (string.IsNullOrEmpty(name)) + { + throw new System.ArgumentNullException(); + } + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel(name); + map.TryGetValue(name, out T value); + var asset = EditorGUILayout.ObjectField(value, typeof(T), true) as T; + if (asset != value) + { + importer.SetExternalUnityObject(new AssetImporter.SourceAssetIdentifier(value), asset); + } + EditorGUILayout.EndHorizontal(); + } + EditorGUI.indentLevel--; + } + + static void OnGUIAnimation(GltfScriptedImporter importer, GltfParser parser) + { + foreach (var a in parser.GLTF.animations) + { + GUILayout.Label(a.name); + } + } + } +} diff --git a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporterEditorGUI.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditorGUI.cs.meta similarity index 83% rename from Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporterEditorGUI.cs.meta rename to Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditorGUI.cs.meta index 6efbfa7a9..f20742643 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporterEditorGUI.cs.meta +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditorGUI.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d4faa0a7a13c9c1489b5eed3a9575a01 +guid: 706590752e82d004e99da97aff535f67 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterExtension.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterExtension.cs new file mode 100644 index 000000000..6328c67d8 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterExtension.cs @@ -0,0 +1,200 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor.Experimental.AssetImporters; +using UnityEditor; +using System; +using UnityEngine; +using System.Text.RegularExpressions; + +namespace UniGLTF +{ + public static class ScriptedImporterExtension + { + public static void ClearExternalObjects(this ScriptedImporter importer) where T : UnityEngine.Object + { + foreach (var extarnalObject in importer.GetExternalObjectMap().Where(x => x.Key.type == typeof(T))) + { + importer.RemoveRemap(extarnalObject.Key); + } + + AssetDatabase.WriteImportSettingsIfDirty(importer.assetPath); + AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); + } + + public static void ClearExtarnalObjects(this ScriptedImporter importer) + { + foreach (var extarnalObject in importer.GetExternalObjectMap()) + { + importer.RemoveRemap(extarnalObject.Key); + } + + AssetDatabase.WriteImportSettingsIfDirty(importer.assetPath); + AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); + } + + private static T GetSubAsset(this ScriptedImporter importer, string assetPath) where T : UnityEngine.Object + { + return importer.GetSubAssets(assetPath) + .FirstOrDefault(); + } + + public static IEnumerable GetSubAssets(this ScriptedImporter importer, string assetPath) where T : UnityEngine.Object + { + return AssetDatabase + .LoadAllAssetsAtPath(assetPath) + .Where(x => AssetDatabase.IsSubAsset(x)) + .Where(x => x is T) + .Select(x => x as T); + } + + private static void ExtractFromAsset(UnityEngine.Object subAsset, string destinationPath, bool isForceUpdate) + { + string assetPath = AssetDatabase.GetAssetPath(subAsset); + + var clone = UnityEngine.Object.Instantiate(subAsset); + AssetDatabase.CreateAsset(clone, destinationPath); + + var assetImporter = AssetImporter.GetAtPath(assetPath); + assetImporter.AddRemap(new AssetImporter.SourceAssetIdentifier(subAsset), clone); + + if (isForceUpdate) + { + AssetDatabase.WriteImportSettingsIfDirty(assetPath); + AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); + } + } + + public static void ExtractAssets(this ScriptedImporter importer, string dirName, string extension) where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(importer.assetPath)) + return; + + var subAssets = importer.GetSubAssets(importer.assetPath); + + var path = string.Format("{0}/{1}.{2}", + Path.GetDirectoryName(importer.assetPath), + Path.GetFileNameWithoutExtension(importer.assetPath), + dirName + ); + + var info = importer.SafeCreateDirectory(path); + + foreach (var asset in subAssets) + { + ExtractFromAsset(asset, string.Format("{0}/{1}{2}", path, asset.name, extension), false); + } + } + + struct TextureInfo + { + public string Path; + public bool sRGB; + public bool IsNormalMap; + } + + class TextureExtractor + { + GltfParser m_parser; + public GltfParser Parser => m_parser; + + public glTF GLTF => m_parser.GLTF; + + public readonly List Textures = new List(); + UnityEngine.Texture2D[] m_subAssets; + string m_path; + + public TextureExtractor(ScriptedImporter importer) + { + // parse GLTF + m_parser = new GltfParser(); + m_parser.ParsePath(importer.assetPath); + + m_path = $"{Path.GetDirectoryName(importer.assetPath)}/{Path.GetFileNameWithoutExtension(importer.assetPath)}.Textures"; + m_subAssets = importer.GetSubAssets(importer.assetPath).ToArray(); + } + + static Regex s_mimeTypeReg = new Regex("image/(?.*)$"); + + public void Extract(GetTextureParam param) + { + var subAsset = m_subAssets.FirstOrDefault(x => x.name == param.Name); + var targetPath = string.Format("{0}/{1}{2}", + m_path, + param.Name, + ".png" + ); + File.WriteAllBytes(targetPath, subAsset.EncodeToPNG().ToArray()); + AssetDatabase.ImportAsset(targetPath); + + Textures.Add(new TextureInfo + { + Path = targetPath, + sRGB = true, + IsNormalMap = param.TextureType == GetTextureParam.NORMAL_PROP, + }); + } + } + + public static void ExtractTextures(this ScriptedImporter importer, string dirName, Action onCompleted = null) + { + if (string.IsNullOrEmpty(importer.assetPath)) + { + return; + } + + var path = string.Format("{0}/{1}.{2}", + Path.GetDirectoryName(importer.assetPath), + Path.GetFileNameWithoutExtension(importer.assetPath), + dirName + ); + importer.SafeCreateDirectory(path); + + // Reload Model + var extractor = new TextureExtractor(importer); + + foreach (var material in extractor.GLTF.materials) + { + foreach (var x in extractor.Parser.EnumerateTextures(material)) + { + extractor.Extract(x); + } + } + + EditorApplication.delayCall += () => + { + foreach (var extracted in extractor.Textures) + { + // TextureImporter + var targetTextureImporter = AssetImporter.GetAtPath(extracted.Path) as TextureImporter; + targetTextureImporter.sRGBTexture = extracted.sRGB; + if (extracted.IsNormalMap) + { + targetTextureImporter.textureType = TextureImporterType.NormalMap; + } + targetTextureImporter.SaveAndReimport(); + + // remap + var externalObject = AssetDatabase.LoadAssetAtPath(extracted.Path); + importer.AddRemap(new AssetImporter.SourceAssetIdentifier(typeof(UnityEngine.Texture2D), externalObject.name), externalObject); + } + + AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); + + if (onCompleted != null) + { + onCompleted(); + } + }; + } + + public static DirectoryInfo SafeCreateDirectory(this ScriptedImporter importer, string path) + { + if (Directory.Exists(path)) + { + return null; + } + return Directory.CreateDirectory(path); + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/LoopAwaitable.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterExtension.cs.meta similarity index 83% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/LoopAwaitable.cs.meta rename to Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterExtension.cs.meta index 125c21d2f..fac355f38 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/LoopAwaitable.cs.meta +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/ScriptedImporterExtension.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: db36517c11c455e4b94d9cbb8c1cc3ff +guid: 1c57d58453713684bb3888c33177ed78 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Editor/UniGLTF/gltfAssetPostprocessor.cs b/Assets/UniGLTF/Editor/UniGLTF/gltfAssetPostprocessor.cs index c1e884c08..e12c8b02c 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/gltfAssetPostprocessor.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/gltfAssetPostprocessor.cs @@ -1,4 +1,5 @@ -using System; +#if false +using System; using System.IO; using UnityEditor; using UnityEngine; @@ -44,8 +45,9 @@ namespace UniGLTF return; } - var context = new ImporterContext(); - context.Parse(src); + var parser = new GltfParser(); + parser.ParsePath(src); + var context = new ImporterContext(parser); // Extract textures to assets folder context.ExtractImages(prefabPath); @@ -84,3 +86,4 @@ namespace UniGLTF } } } +#endif \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs index 7f0202668..e56fb7729 100644 --- a/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs @@ -45,11 +45,21 @@ namespace UniGLTF return new Vector4(v.x, v.y, -v.z, v.w); } + public static Vector4 ReverseX(this Vector4 v) + { + return new Vector4(-v.x, v.y, v.z, v.w); + } + public static Vector3 ReverseZ(this Vector3 v) { return new Vector3(v.x, v.y, -v.z); } + public static Vector3 ReverseX(this Vector3 v) + { + return new Vector3(-v.x, v.y, v.z); + } + [Obsolete] public static Vector2 ReverseY(this Vector2 v) { @@ -69,6 +79,14 @@ namespace UniGLTF return Quaternion.AngleAxis(-angle, ReverseZ(axis)); } + public static Quaternion ReverseX(this Quaternion q) + { + float angle; + Vector3 axis; + q.ToAngleAxis(out angle, out axis); + return Quaternion.AngleAxis(-angle, ReverseX(axis)); + } + public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3) { #if UNITY_2017_1_OR_NEWER @@ -100,6 +118,12 @@ namespace UniGLTF return m; } + public static Matrix4x4 ReverseX(this Matrix4x4 m) + { + m.SetTRS(m.ExtractPosition().ReverseX(), m.ExtractRotation().ReverseX(), m.ExtractScale()); + return m; + } + public static Matrix4x4 MatrixFromArray(float[] values) { var m = new Matrix4x4(); diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index 3733ed86d..a206e9aa6 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -325,7 +325,8 @@ namespace UniGLTF var bufferCount = vertexAccessor.count * vertexAccessor.TypeCount; float[] result = null; - if(vertexAccessor.bufferView != -1){ + if (vertexAccessor.bufferView != -1) + { var attrib = new float[vertexAccessor.count * vertexAccessor.TypeCount]; var view = self.bufferViews[vertexAccessor.bufferView]; var segment = self.buffers[view.buffer].GetBytes(); @@ -333,8 +334,9 @@ namespace UniGLTF bytes.MarshalCopyTo(attrib); result = attrib; } - else{ - result = new float[bufferCount]; + else + { + result = new float[bufferCount]; } var sparse = vertexAccessor.sparse; @@ -354,28 +356,15 @@ namespace UniGLTF return result; } - public static ArraySegment GetImageBytes(this glTF self, IStorage storage, int imageIndex, out string textureName) + public static ArraySegment GetImageBytes(this glTF self, IStorage storage, int imageIndex) { var image = self.images[imageIndex]; if (string.IsNullOrEmpty(image.uri)) { - // - // use buffer view (GLB) - // - //m_imageBytes = ToArray(byteSegment); - textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#GLB", imageIndex); return self.GetViewBytes(image.bufferView); } else { - if (image.uri.FastStartsWith("data:")) - { - textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#Base64Embedded", imageIndex); - } - else - { - textureName = !string.IsNullOrEmpty(image.name) ? image.name : Path.GetFileNameWithoutExtension(image.uri); - } return storage.Get(image.uri); } } @@ -441,7 +430,7 @@ namespace UniGLTF // remove unused extenions var json = f.ToString().ParseAsJson().ToString(" "); self.RemoveUnusedExtensions(json); - + return Glb.Create(json, self.buffers[0].GetBytes()).ToBytes(); } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTF.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTF.cs index d623afeaf..73aef408a 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTF.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTF.cs @@ -67,16 +67,6 @@ namespace UniGLTF [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List images = new List(); - public int GetImageIndexFromTextureIndex(int textureIndex) - { - return textures[textureIndex].source; - } - - public glTFImage GetImageFromTextureIndex(int textureIndex) - { - return images[GetImageIndexFromTextureIndex(textureIndex)]; - } - public glTFTextureSampler GetSamplerFromTextureIndex(int textureIndex) { var samplerIndex = textures[textureIndex].sampler; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/Awaitable.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/Awaitable.cs index eb4a16706..545082372 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/Awaitable.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/Awaitable.cs @@ -79,10 +79,16 @@ namespace UniGLTF.AltTask public Awaitable(Task task) { _task = task; + if (_task.Exception != null) + { + throw _task.Exception; + } } public bool IsCompleted => _task.IsCompleted; + public Exception Exception => _task.Exception; + public IAwaiter GetAwaiter() { return new Awaiter(this); @@ -126,6 +132,10 @@ namespace UniGLTF.AltTask public void GetResult() { + if (m_task.Exception != null) + { + throw m_task.Exception; + } } public void OnCompleted(Action continuation) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/GenericAwaitable.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/GenericAwaitable.cs index 8b4c51bbe..87326a28f 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/GenericAwaitable.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/GenericAwaitable.cs @@ -70,11 +70,15 @@ namespace UniGLTF.AltTask public Awaitable(Task task) { _task = task; + if (_task.Exception != null) + { + throw _task.Exception; + } } - public bool IsCompleted => _task.IsCompleted; public T Result => _task.Result; + public Exception Exception => _task.Exception; public IAwaiter GetAwaiter() { @@ -110,6 +114,10 @@ namespace UniGLTF.AltTask public T GetResult() { + if (m_task.Exception != null) + { + throw m_task.Exception; + } return m_task.Result; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/LoopAwaitable.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/NextFrameAwaitable.cs similarity index 87% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/LoopAwaitable.cs rename to Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/NextFrameAwaitable.cs index f6410a344..f1be89203 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/LoopAwaitable.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/NextFrameAwaitable.cs @@ -2,7 +2,7 @@ using System; namespace UniGLTF.AltTask { - public static class LoopAwaitable + public static class NextFrameAwaitable { // TODO // loop スレッド使わないようにしたい diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/NextFrameAwaitable.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/NextFrameAwaitable.cs.meta new file mode 100644 index 000000000..498037b0f --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AltTask/NextFrameAwaitable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81795a4f6e605d74787f604354a8565f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs index b300827ab..0e4c16fe5 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs @@ -64,7 +64,7 @@ namespace UniGLTF } - public delegate float[] ReverseZ(float[] current, float[] last); + public delegate float[] ReverseFunc(float[] current, float[] last); public static void SetAnimationCurve( AnimationClip targetClip, string relativePath, @@ -73,7 +73,7 @@ namespace UniGLTF float[] output, string interpolation, Type curveType, - ReverseZ reverse) + ReverseFunc reverse) { var tangentMode = GetTangentMode(interpolation); @@ -164,18 +164,18 @@ namespace UniGLTF private static string RelativePathFrom(List nodes, glTFNode root, glTFNode target, List path) { - if(path.Count == 0) path.Add(target.name); + if (path.Count == 0) path.Add(target.name); var targetIndex = nodes.IndexOf(target); foreach (var parent in nodes) { - if(parent.children == null || parent.children.Length == 0) continue; + if (parent.children == null || parent.children.Length == 0) continue; - foreach(var child in parent.children) + foreach (var child in parent.children) { - if(child != targetIndex) continue; + if (child != targetIndex) continue; - if(parent == root) return string.Join("/", path); + if (parent == root) return string.Join("/", path); path.Insert(0, parent.name); return RelativePathFrom(nodes, root, parent, path); @@ -185,7 +185,7 @@ namespace UniGLTF return string.Join("/", path); } - public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, glTFNode root = null) + public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, AxisInverter inverter, glTFNode root = null) { var clip = new AnimationClip(); clip.ClearCurves(); @@ -215,7 +215,7 @@ namespace UniGLTF (values, last) => { Vector3 temp = new Vector3(values[0], values[1], values[2]); - return temp.ReverseZ().ToArray(); + return inverter.InvertVector3(temp).ToArray(); } ); } @@ -239,7 +239,7 @@ namespace UniGLTF { Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); - return AnimationImporterUtil.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray(); + return AnimationImporterUtil.GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)).ToArray(); } ); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs new file mode 100644 index 000000000..9096e708f --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs @@ -0,0 +1,35 @@ +using System; +using UnityEngine; + +namespace UniGLTF +{ + public enum Axises + { + Z, + X, + } + + public struct AxisInverter + { + public Func InvertVector3; + public Func InvertVector4; + public Func InvertQuaternion; + public Func InvertMat4; + + public static AxisInverter ReverseZ => new AxisInverter + { + InvertVector3 = x => x.ReverseZ(), + InvertVector4 = x => x.ReverseZ(), + InvertQuaternion = x => x.ReverseZ(), + InvertMat4 = x => x.ReverseZ(), + }; + + public static AxisInverter ReverseX => new AxisInverter + { + InvertVector3 = x => x.ReverseX(), + InvertVector4 = x => x.ReverseX(), + InvertQuaternion = x => x.ReverseX(), + InvertMat4 = x => x.ReverseX(), + }; + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs.meta new file mode 100644 index 000000000..1af1e98ff --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b3b7b9629a4da242bacf52f5ca0fd80 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs new file mode 100644 index 000000000..63d352b11 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs @@ -0,0 +1,436 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using UniJSON; +using UnityEngine; + +namespace UniGLTF +{ + public class GltfParser + { + /// + /// JSON source + /// + public String Json; + + /// + /// GLTF parsed from JSON + /// + public glTF GLTF; + + /// + /// URI access + /// + public IStorage Storage; + + public static bool IsGeneratedUniGLTFAndOlderThan(string generatorVersion, int major, int minor) + { + if (string.IsNullOrEmpty(generatorVersion)) return false; + if (generatorVersion == "UniGLTF") return true; + if (!generatorVersion.FastStartsWith("UniGLTF-")) return false; + + try + { + var splitted = generatorVersion.Substring(8).Split('.'); + var generatorMajor = int.Parse(splitted[0]); + var generatorMinor = int.Parse(splitted[1]); + + if (generatorMajor < major) + { + return true; + } + else if (generatorMajor > major) + { + return false; + } + else + { + if (generatorMinor >= minor) + { + return false; + } + else + { + return true; + } + } + } + catch (Exception ex) + { + Debug.LogWarningFormat("{0}: {1}", generatorVersion, ex); + return false; + } + } + + public bool IsGeneratedUniGLTFAndOlder(int major, int minor) + { + if (GLTF == null) return false; + if (GLTF.asset == null) return false; + return IsGeneratedUniGLTFAndOlderThan(GLTF.asset.generator, major, minor); + } + + #region Parse + public void ParsePath(string path) + { + Parse(path, File.ReadAllBytes(path)); + } + + /// + /// Parse gltf json or Parse json chunk of glb + /// + /// + /// + public virtual void Parse(string path, Byte[] bytes) + { + var ext = Path.GetExtension(path).ToLower(); + switch (ext) + { + case ".gltf": + ParseJson(Encoding.UTF8.GetString(bytes), new FileSystemStorage(Path.GetDirectoryName(path))); + break; + + case ".zip": + { + var zipArchive = Zip.ZipArchiveStorage.Parse(bytes); + var gltf = zipArchive.Entries.FirstOrDefault(x => x.FileName.ToLower().EndsWith(".gltf")); + if (gltf == null) + { + throw new Exception("no gltf in archive"); + } + var jsonBytes = zipArchive.Extract(gltf); + var json = Encoding.UTF8.GetString(jsonBytes); + ParseJson(json, zipArchive); + } + break; + + default: + ParseGlb(bytes); + break; + } + } + + /// + /// + /// + /// + public void ParseGlb(Byte[] bytes) + { + var chunks = glbImporter.ParseGlbChunks(bytes); + + if (chunks.Count != 2) + { + throw new Exception("unknown chunk count: " + chunks.Count); + } + + if (chunks[0].ChunkType != GlbChunkType.JSON) + { + throw new Exception("chunk 0 is not JSON"); + } + + if (chunks[1].ChunkType != GlbChunkType.BIN) + { + throw new Exception("chunk 1 is not BIN"); + } + + try + { + var jsonBytes = chunks[0].Bytes; + ParseJson(Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count), + new SimpleStorage(chunks[1].Bytes)); + } + catch (StackOverflowException ex) + { + throw new Exception("[UniVRM Import Error] json parsing failed, nesting is too deep.\n" + ex); + } + catch + { + throw; + } + } + + public virtual void ParseJson(string json, IStorage storage) + { + Json = json; + Storage = storage; + GLTF = GltfDeserializer.Deserialize(json.ParseAsJson()); + if (GLTF.asset.version != "2.0") + { + throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version); + } + + // Version Compatibility + RestoreOlderVersionValues(); + + FixMeshNameUnique(); + FixTextureNameUnique(); + FixMaterialNameUnique(); + FixNodeName(); + + // parepare byte buffer + //GLTF.baseDir = System.IO.Path.GetDirectoryName(Path); + foreach (var buffer in GLTF.buffers) + { + buffer.OpenStorage(storage); + } + } + + void FixMeshNameUnique() + { + var used = new HashSet(); + foreach (var mesh in GLTF.meshes) + { + if (string.IsNullOrEmpty(mesh.name)) + { + // empty + mesh.name = "mesh_" + Guid.NewGuid().ToString("N"); + Debug.LogWarning($"no name: => {mesh.name}"); + used.Add(mesh.name); + } + else + { + var lower = mesh.name.ToLower(); + if (used.Contains(lower)) + { + // rename + var uname = lower + "_" + Guid.NewGuid().ToString("N"); + Debug.LogWarning($"same name: {lower} => {uname}"); + mesh.name = uname; + lower = uname; + } + used.Add(lower); + } + } + } + + void RenameImageFromTexture(int i) + { + foreach (var texture in GLTF.textures) + { + if (texture.source == i) + { + if (!string.IsNullOrEmpty(texture.name)) + { + GLTF.images[i].name = texture.name; + return; + } + } + } + } + + /// + /// gltfTexture.name を Unity Asset 名として運用する。 + /// ユニークである必要がある。 + /// + void FixTextureNameUnique() + { + var used = new HashSet(); + for (int i = 0; i < GLTF.textures.Count; ++i) + { + var gltfTexture = GLTF.textures[i]; + if (string.IsNullOrEmpty(gltfTexture.name)) + { + // use image name + gltfTexture.name = GLTF.images[gltfTexture.source].name; + } + if (string.IsNullOrEmpty(gltfTexture.name)) + { + var newName = $"texture_{i}"; + if (!used.Add(newName)) + { + newName = "texture_" + Guid.NewGuid().ToString("N"); + if (!used.Add(newName)) + { + throw new Exception(); + } + } + gltfTexture.name = newName; + } + else + { + var lower = gltfTexture.name.ToLower(); + if (used.Contains(lower)) + { + // rename + var uname = lower + "_" + Guid.NewGuid().ToString("N"); + Debug.LogWarning($"same name: {lower} => {uname}"); + gltfTexture.name = uname; + lower = uname; + } + used.Add(lower); + } + } + } + + public void FixMaterialNameUnique() + { + foreach (var material in GLTF.materials) + { + var originalName = material.name; + int j = 2; + while (GLTF.materials.Any(x => x != material && x.name == material.name)) + { + material.name = string.Format("{0}({1})", originalName, j++); + } + } + } + + /// + /// rename empty name to $"{index}" + /// + void FixNodeName() + { + for (var i = 0; i < GLTF.nodes.Count; ++i) + { + var node = GLTF.nodes[i]; + if (string.IsNullOrWhiteSpace(node.name)) + { + node.name = $"{i}"; + } + } + } + + void RestoreOlderVersionValues() + { + var parsed = UniJSON.JsonParser.Parse(Json); + for (int i = 0; i < GLTF.images.Count; ++i) + { + if (string.IsNullOrEmpty(GLTF.images[i].name)) + { + try + { + var extraName = parsed["images"][i]["extra"]["name"].Value.GetString(); + if (!string.IsNullOrEmpty(extraName)) + { + //Debug.LogFormat("restore texturename: {0}", extraName); + GLTF.images[i].name = extraName; + } + } + catch (Exception) + { + // do nothing + } + } + } + } + #endregion + + + public static void AppendImageExtension(glTFImage texture, string extension) + { + if (!texture.name.EndsWith(extension)) + { + texture.name = texture.name + extension; + } + } + + public string GetTextureExtension(int imageIndex) + { + foreach (var m in GLTF.materials) + { + if (m.pbrMetallicRoughness != null) + { + // base color + if (m.pbrMetallicRoughness?.baseColorTexture != null) + { + if (m.pbrMetallicRoughness.baseColorTexture.index == imageIndex) + { + return ""; + } + } + + // metallic roughness + if (m.pbrMetallicRoughness?.metallicRoughnessTexture != null) + { + if (m.pbrMetallicRoughness.metallicRoughnessTexture.index == imageIndex) + { + return ".metallicRoughness"; + } + } + } + + // emission + if (m.emissiveTexture != null) + { + if (m.emissiveTexture.index == imageIndex) + { + return ""; + } + } + + // normal + if (m.normalTexture != null) + { + if (m.normalTexture.index == imageIndex) + { + return ""; + } + } + + // occlusion + if (m.occlusionTexture != null) + { + if (m.occlusionTexture.index == imageIndex) + { + return ".occlusion"; + } + } + } + + return ""; + } + + public IEnumerable EnumerateTextures(glTFMaterial m) + { + if (m.pbrMetallicRoughness != null) + { + // base color + if (m.pbrMetallicRoughness?.baseColorTexture != null) + { + yield return PBRMaterialItem.BaseColorTexture(GLTF, m); + } + + // metallic roughness + if (m.pbrMetallicRoughness?.metallicRoughnessTexture != null) + { + yield return PBRMaterialItem.MetallicRoughnessTexture(GLTF, m); + } + } + + // emission + if (m.emissiveTexture != null) + { + yield return GetTextureParam.Create(GLTF, m.emissiveTexture.index); + } + + // normal + if (m.normalTexture != null) + { + yield return PBRMaterialItem.NormalTexture(GLTF, m); + } + + // occlusion + if (m.occlusionTexture != null) + { + yield return PBRMaterialItem.OcclusionTexture(GLTF, m); + } + } + + public IEnumerable EnumerateTextures() + { + var used = new HashSet(); + for (int i = 0; i < GLTF.materials.Count; ++i) + { + var m = GLTF.materials[i]; + foreach (var x in EnumerateTextures(m)) + { + if (used.Add(x.Name)) + { + yield return x; + } + } + } + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs.meta new file mode 100644 index 000000000..75eba128b --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae3083233546b58449904dca65e76005 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index bc9828bfb..5c82ba2fe 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -3,8 +3,6 @@ using System.Linq; using System.Collections.Generic; using UnityEngine; using System.IO; -using System.Text; -using UniJSON; using UniGLTF.AltTask; #if UNITY_EDITOR using UnityEditor; @@ -12,76 +10,11 @@ using UnityEditor; namespace UniGLTF { - - /// /// GLTF importer /// public class ImporterContext : IDisposable { - #region MeasureTime - bool m_showSpeedLog -#if VRM_DEVELOP - = true -#endif - ; - public bool ShowSpeedLog - { - set { m_showSpeedLog = value; } - } - - public struct KeyElapsed - { - public string Key; - public TimeSpan Elapsed; - public KeyElapsed(string key, TimeSpan elapsed) - { - Key = key; - Elapsed = elapsed; - } - } - - public struct MeasureScope : IDisposable - { - Action m_onDispose; - public MeasureScope(Action onDispose) - { - m_onDispose = onDispose; - } - public void Dispose() - { - m_onDispose(); - } - } - - public List m_speedReports = new List(); - - public IDisposable MeasureTime(string key) - { - var sw = System.Diagnostics.Stopwatch.StartNew(); - return new MeasureScope(() => - { - m_speedReports.Add(new KeyElapsed(key, sw.Elapsed)); - }); - } - - public string GetSpeedLog() - { - var total = TimeSpan.Zero; - - var sb = new StringBuilder(); - sb.AppendLine("【SpeedLog】"); - foreach (var kv in m_speedReports) - { - sb.AppendLine(string.Format("{0}: {1}ms", kv.Key, (int)kv.Elapsed.TotalMilliseconds)); - total += kv.Elapsed; - } - sb.AppendLine(string.Format("total: {0}ms", (int)total.TotalMilliseconds)); - - return sb.ToString(); - } - #endregion - #region Animation protected IAnimationImporter m_animationImporter; public void SetAnimationImporter(IAnimationImporter animationImporter) @@ -108,258 +41,54 @@ namespace UniGLTF TextureFactory m_textureFactory; public TextureFactory TextureFactory => m_textureFactory; - public ImporterContext() + public ImporterContext(GltfParser parser, IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null) { + m_parser = parser; + m_textureFactory = new TextureFactory(GLTF, Storage, externalObjectMap); + m_materialFactory = new MaterialFactory(GLTF, Storage, externalObjectMap); } + #region Source - - /// - /// JSON source - /// - public String Json; - - /// - /// GLTF parsed from JSON - /// - public glTF GLTF; // parsed - - public static bool IsGeneratedUniGLTFAndOlderThan(string generatorVersion, int major, int minor) - { - if (string.IsNullOrEmpty(generatorVersion)) return false; - if (generatorVersion == "UniGLTF") return true; - if (!generatorVersion.FastStartsWith("UniGLTF-")) return false; - - try - { - var splitted = generatorVersion.Substring(8).Split('.'); - var generatorMajor = int.Parse(splitted[0]); - var generatorMinor = int.Parse(splitted[1]); - - if (generatorMajor < major) - { - return true; - } - else if (generatorMajor > major) - { - return false; - } - else - { - if (generatorMinor >= minor) - { - return false; - } - else - { - return true; - } - } - } - catch (Exception ex) - { - Debug.LogWarningFormat("{0}: {1}", generatorVersion, ex); - return false; - } - } - - public bool IsGeneratedUniGLTFAndOlder(int major, int minor) - { - if (GLTF == null) return false; - if (GLTF.asset == null) return false; - return IsGeneratedUniGLTFAndOlderThan(GLTF.asset.generator, major, minor); - } - - /// - /// URI access - /// - public IStorage Storage; + GltfParser m_parser; + public GltfParser Parser => m_parser; + public String Json => m_parser.Json; + public glTF GLTF => m_parser.GLTF; + public IStorage Storage => m_parser.Storage; #endregion - #region Parse - public void Parse(string path) - { - Parse(path, File.ReadAllBytes(path)); - } + // configuration /// - /// Parse gltf json or Parse json chunk of glb + /// GLTF から Unity に変換するときに反転させる軸 /// - /// - /// - public virtual void Parse(string path, Byte[] bytes) + public Axises InvertAxis = Axises.Z; + + #region Load. Build unity objects + public virtual async Awaitable LoadAsync(Func MeasureTime = null) { - var ext = Path.GetExtension(path).ToLower(); - switch (ext) + if (MeasureTime == null) { - case ".gltf": - ParseJson(Encoding.UTF8.GetString(bytes), new FileSystemStorage(Path.GetDirectoryName(path))); + MeasureTime = new ImporterContextSpeedLog().MeasureTime; + } + + AxisInverter inverter = default; + switch (InvertAxis) + { + case Axises.Z: + inverter = AxisInverter.ReverseZ; break; - case ".zip": - { - var zipArchive = Zip.ZipArchiveStorage.Parse(bytes); - var gltf = zipArchive.Entries.FirstOrDefault(x => x.FileName.ToLower().EndsWith(".gltf")); - if (gltf == null) - { - throw new Exception("no gltf in archive"); - } - var jsonBytes = zipArchive.Extract(gltf); - var json = Encoding.UTF8.GetString(jsonBytes); - ParseJson(json, zipArchive); - } - break; - - case ".glb": - ParseGlb(bytes); + case Axises.X: + inverter = AxisInverter.ReverseX; break; default: throw new NotImplementedException(); } - } - /// - /// - /// - /// - public void ParseGlb(Byte[] bytes) - { - var chunks = glbImporter.ParseGlbChunks(bytes); - - if (chunks.Count != 2) - { - throw new Exception("unknown chunk count: " + chunks.Count); - } - - if (chunks[0].ChunkType != GlbChunkType.JSON) - { - throw new Exception("chunk 0 is not JSON"); - } - - if (chunks[1].ChunkType != GlbChunkType.BIN) - { - throw new Exception("chunk 1 is not BIN"); - } - - try - { - var jsonBytes = chunks[0].Bytes; - ParseJson(Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count), - new SimpleStorage(chunks[1].Bytes)); - } - catch (StackOverflowException ex) - { - throw new Exception("[UniVRM Import Error] json parsing failed, nesting is too deep.\n" + ex); - } - catch - { - throw; - } - } - - public virtual void ParseJson(string json, IStorage storage) - { - Json = json; - Storage = storage; - GLTF = GltfDeserializer.Deserialize(json.ParseAsJson()); - if (GLTF.asset.version != "2.0") - { - throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version); - } - - m_textureFactory = new TextureFactory(GLTF, Storage); - m_materialFactory = new MaterialFactory(GLTF, Storage); - - // Version Compatibility - RestoreOlderVersionValues(); - - FixUnique(); - FixNodeName(); - - // parepare byte buffer - //GLTF.baseDir = System.IO.Path.GetDirectoryName(Path); - foreach (var buffer in GLTF.buffers) - { - buffer.OpenStorage(storage); - } - } - - void FixUnique() - { - var used = new HashSet(); - foreach (var mesh in GLTF.meshes) - { - if (string.IsNullOrEmpty(mesh.name)) - { - mesh.name = "mesh_" + Guid.NewGuid().ToString("N"); - used.Add(mesh.name); - } - else - { - var lname = mesh.name.ToLower(); - if (used.Contains(lname)) - { - // rename - var uname = lname + "_" + Guid.NewGuid().ToString("N"); - Debug.LogWarning($"same name: {lname} => {uname}"); - mesh.name = uname; - lname = uname; - } - - used.Add(lname); - } - } - } - - /// - /// rename empty name to $"{index}" - /// - void FixNodeName() - { - for (var i = 0; i < GLTF.nodes.Count; ++i) - { - var node = GLTF.nodes[i]; - if (string.IsNullOrWhiteSpace(node.name)) - { - node.name = $"{i}"; - } - } - } - - void RestoreOlderVersionValues() - { - var parsed = UniJSON.JsonParser.Parse(Json); - for (int i = 0; i < GLTF.images.Count; ++i) - { - if (string.IsNullOrEmpty(GLTF.images[i].name)) - { - try - { - var extraName = parsed["images"][i]["extra"]["name"].Value.GetString(); - if (!string.IsNullOrEmpty(extraName)) - { - //Debug.LogFormat("restore texturename: {0}", extraName); - GLTF.images[i].name = extraName; - } - } - catch (Exception) - { - // do nothing - } - } - } - } - #endregion - - #region Load. Build unity objects - - public bool EnableLoadBalancing; - - public virtual async Awaitable LoadAsync() - { if (Root == null) { - Root = new GameObject("_root_"); + Root = new GameObject("GLTF"); } // UniGLTF does not support draco @@ -369,17 +98,30 @@ namespace UniGLTF throw new UniGLTFNotSupportedException("draco is not supported"); } - await m_materialFactory.LoadMaterialsAsync(m_textureFactory.GetTextureAsync); + // using (MeasureTime("LoadTextures")) + // { + // for (int i = 0; i < GLTF.materials.Count; ++i) + // { + // foreach (var param in MaterialFactory.EnumerateGetTextureparam(i)) + // { + // await m_textureFactory.GetTextureAsync(GLTF, param); + // } + // } + // } + + using (MeasureTime("LoadMaterials")) + { + await m_materialFactory.LoadMaterialsAsync(m_textureFactory.GetTextureAsync); + } - // meshes var meshImporter = new MeshImporter(); for (int i = 0; i < GLTF.meshes.Count; ++i) { var index = i; using (MeasureTime("ReadMesh")) { - var x = meshImporter.ReadMesh(this, index); - var y = await BuildMeshAsync(x, index); + var x = meshImporter.ReadMesh(this, index, inverter); + var y = await BuildMeshAsync(MeasureTime, x, index); Meshes.Add(y); } } @@ -391,7 +133,7 @@ namespace UniGLTF Nodes.Add(NodeImporter.ImportNode(GLTF.nodes[i], i).transform); } } - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); using (MeasureTime("BuildHierarchy")) { @@ -401,12 +143,12 @@ namespace UniGLTF nodes.Add(NodeImporter.BuildHierarchy(this, i)); } - NodeImporter.FixCoordinate(this, nodes); + NodeImporter.FixCoordinate(this, nodes, inverter); // skinning for (int i = 0; i < nodes.Count; ++i) { - NodeImporter.SetupSkinning(this, nodes, i); + NodeImporter.SetupSkinning(this, nodes, i, inverter); } // connect root @@ -416,41 +158,26 @@ namespace UniGLTF t.SetParent(Root.transform, false); } } - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); using (MeasureTime("AnimationImporter")) { AnimationImporter.Import(this); } - await OnLoadModel(); - - if (m_showSpeedLog) - { - Debug.Log(GetSpeedLog()); - } + await OnLoadModel(MeasureTime); } - protected virtual async Awaitable OnLoadModel() + protected virtual async Awaitable OnLoadModel(Func MeasureTime) { - Root.name = "GLTF"; - await LoopAwaitable.Create(); + // do nothing } - async Awaitable BuildMeshAsync(MeshImporter.MeshContext x, int i) + async Awaitable BuildMeshAsync(Func MeasureTime, MeshImporter.MeshContext x, int i) { using (MeasureTime("BuildMesh")) { - MeshWithMaterials meshWithMaterials; - if (EnableLoadBalancing) - { - meshWithMaterials = await MeshImporter.BuildMeshAsync(MaterialFactory, x); - } - else - { - meshWithMaterials = MeshImporter.BuildMesh(MaterialFactory, x); - } - + var meshWithMaterials = await MeshImporter.BuildMeshAsync(MaterialFactory, x); var mesh = meshWithMaterials.Mesh; // mesh name @@ -664,30 +391,29 @@ namespace UniGLTF // https://answers.unity.com/questions/647615/how-to-update-import-settings-for-newly-created-as.html // int created = 0; - //for (int i = 0; i < GLTF.textures.Count; ++i) - for (int i = 0; i < GLTF.images.Count; ++i) + for (int i = 0; i < GLTF.textures.Count; ++i) { folder.EnsureFolder(); - //var x = GLTF.textures[i]; - var image = GLTF.images[i]; - var src = Storage.GetPath(image.uri); + var gltfTexture = GLTF.textures[i]; + var gltfImage = GLTF.images[gltfTexture.source]; + var src = Storage.GetPath(gltfImage.uri); if (UnityPath.FromFullpath(src).IsUnderAssetsFolder) { // asset is exists. } else { - string textureName; - var byteSegment = GLTF.GetImageBytes(Storage, i, out textureName); + var byteSegment = GLTF.GetImageBytes(Storage, gltfTexture.source); + var textureName = gltfTexture.name; // path - var dst = folder.Child(textureName + image.GetExt()); + var dst = folder.Child(textureName + gltfImage.GetExt()); File.WriteAllBytes(dst.FullPath, byteSegment.ToArray()); dst.ImportAsset(); // make relative path from PrefabParentDir - image.uri = dst.Value.Substring(prefabParentDir.Value.Length + 1); + gltfImage.uri = dst.Value.Substring(prefabParentDir.Value.Length + 1); ++created; } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs index 04f1c2e98..5eaf1915a 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs @@ -1,40 +1,20 @@ using System.IO; using UniGLTF.AltTask; +using UnityEngine; namespace UniGLTF { public static class ImporterContextExtensions { - /// - /// ReadAllBytes, Parse, Create GameObject - /// - /// allbytes - public static void Load(this ImporterContext self, string path) - { - var bytes = File.ReadAllBytes(path); - self.Load(path, bytes); - } - - /// - /// Parse, Create GameObject - /// - /// gltf or glb path - /// allbytes - public static void Load(this ImporterContext self, string path, byte[] bytes) - { - self.Parse(path, bytes); - self.Load(); - self.Root.name = Path.GetFileNameWithoutExtension(path); - } - /// /// Build unity objects from parsed gltf /// public static void Load(this ImporterContext self) { + var meassureTime = new ImporterContextSpeedLog(); using (var queue = TaskQueue.Create()) { - var task = self.LoadAsync(); + var task = self.LoadAsync(meassureTime.MeasureTime); // 中断された await を消化する while (!task.IsCompleted) @@ -43,6 +23,10 @@ namespace UniGLTF queue.ExecuteOneCallback(); } } + +#if VRM_DEVELOP + Debug.Log(meassureTime.GetSpeedLog()); +#endif } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs new file mode 100644 index 000000000..db3c45561 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniGLTF +{ + public class ImporterContextSpeedLog + { + public struct KeyElapsed + { + public string Key; + public TimeSpan Elapsed; + public KeyElapsed(string key, TimeSpan elapsed) + { + Key = key; + Elapsed = elapsed; + } + } + + public struct MeasureScope : IDisposable + { + Action m_onDispose; + public MeasureScope(Action onDispose) + { + m_onDispose = onDispose; + } + public void Dispose() + { + m_onDispose(); + } + } + + public List m_speedReports = new List(); + + public IDisposable MeasureTime(string key) + { + var sw = System.Diagnostics.Stopwatch.StartNew(); + return new MeasureScope(() => + { + m_speedReports.Add(new KeyElapsed(key, sw.Elapsed)); + }); + } + + public string GetSpeedLog() + { + var total = TimeSpan.Zero; + + var sb = new StringBuilder(); + sb.AppendLine("【SpeedLog】"); + foreach (var kv in m_speedReports) + { + sb.AppendLine(string.Format("{0}: {1}ms", kv.Key, (int)kv.Elapsed.TotalMilliseconds)); + total += kv.Elapsed; + } + sb.AppendLine(string.Format("total: {0}ms", (int)total.TotalMilliseconds)); + + return sb.ToString(); + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs.meta new file mode 100644 index 000000000..1df8a4951 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e99bb16028e30ce4b972caecca5343b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs index 915882998..041122e9c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/MaterialFactory.cs @@ -10,13 +10,38 @@ namespace UniGLTF { glTF m_gltf; IStorage m_storage; - public MaterialFactory(glTF gltf, IStorage storage) + Dictionary m_externalMap; + public bool TryGetExternal(int index, out Material external) + { + if (m_externalMap != null) + { + var gltfMaterial = m_gltf.materials[index]; + if (m_externalMap.TryGetValue(gltfMaterial.name, out external)) + { + return true; + } + } + + external = default; + return false; + } + + public MaterialFactory(glTF gltf, IStorage storage, + IEnumerable<(string, UnityEngine.Object)> externalMap) { m_gltf = gltf; m_storage = storage; + if (externalMap != null) + { + m_externalMap = externalMap + .Select(kv => (kv.Item1, kv.Item2 as Material)) + .Where(kv => kv.Item2 != null) + .ToDictionary(kv => kv.Item1, kv => kv.Item2) + ; + } } - public delegate Awaitable CreateMaterialAsyncFunc(glTF glTF, int i, GetTextureAsyncFunc getTexture); + public delegate Awaitable CreateMaterialAsyncFunc(glTF gltf, int i, GetTextureAsyncFunc getTexture); CreateMaterialAsyncFunc m_createMaterialAsync; public CreateMaterialAsyncFunc CreateMaterialAsync { @@ -34,8 +59,20 @@ namespace UniGLTF } } - List m_materials = new List(); - public IReadOnlyList Materials => m_materials; + public struct MaterialLoadInfo + { + public readonly Material Asset; + public readonly bool UseExternal; + + public MaterialLoadInfo(Material asset, bool useExternal) + { + Asset = asset; + UseExternal = useExternal; + } + } + + List m_materials = new List(); + public IReadOnlyList Materials => m_materials; public void Dispose() { foreach (var x in ObjectsForSubAsset()) @@ -48,41 +85,42 @@ namespace UniGLTF { foreach (var x in m_materials) { - yield return x; + yield return x.Asset; } } - public void AddMaterial(Material material) - { - var originalName = material.name; - int j = 2; - while (m_materials.Any(x => x.name == material.name)) - { - material.name = string.Format("{0}({1})", originalName, j++); - } - m_materials.Add(material); - } public Material GetMaterial(int index) { if (index < 0) return null; if (index >= m_materials.Count) return null; - return m_materials[index]; + return m_materials[index].Asset; } + /// + /// テクスチャ生成 + /// + /// + /// public async Awaitable LoadMaterialsAsync(GetTextureAsyncFunc getTexture) { if (m_gltf.materials == null || m_gltf.materials.Count == 0) { + // no material. work around. var material = await CreateMaterialAsync(m_gltf, 0, getTexture); - AddMaterial(material); + m_materials.Add(new MaterialLoadInfo(material, false)); + return; } - else + + for (int i = 0; i < m_gltf.materials.Count; ++i) { - for (int i = 0; i < m_gltf.materials.Count; ++i) + if (TryGetExternal(i, out Material material)) { - var material = await CreateMaterialAsync(m_gltf, i, getTexture); - AddMaterial(material); + m_materials.Add(new MaterialLoadInfo(material, true)); + continue; } + + material = await CreateMaterialAsync(m_gltf, i, getTexture); + m_materials.Add(new MaterialLoadInfo(material, false)); } } @@ -125,21 +163,20 @@ namespace UniGLTF public static Awaitable DefaultCreateMaterialAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture) { - if (i < 0 || i >= gltf.materials.Count) { UnityEngine.Debug.LogWarning("glTFMaterial is empty"); - return PBRMaterialItem.CreateAsync(i, null, getTexture); + return PBRMaterialItem.CreateAsync(gltf, i, getTexture); } var x = gltf.materials[i]; if (glTF_KHR_materials_unlit.IsEnable(x)) { var hasVertexColor = gltf.MaterialHasVertexColor(i); - return UnlitMaterialItem.CreateAsync(i, x, getTexture, hasVertexColor); + return UnlitMaterialItem.CreateAsync(gltf, i, getTexture, hasVertexColor); } - return PBRMaterialItem.CreateAsync(i, x, getTexture); + return PBRMaterialItem.CreateAsync(gltf, i, getTexture); } /// @@ -158,5 +195,22 @@ namespace UniGLTF var task = DefaultCreateMaterialAsync(gltf, i, null); return task.Result; } + + public IEnumerable EnumerateGetTextureparam(int i) + { + var m = m_gltf.materials[i]; + + // color texture + var colorIndex = m.pbrMetallicRoughness?.baseColorTexture?.index; + if (colorIndex.HasValue) + { + yield return GetTextureParam.Create(m_gltf, i); + } + + if (!glTF_KHR_materials_unlit.IsEnable(m)) + { + // PBR + } + } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/PBRMaterialItem.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/PBRMaterialItem.cs index 7f568e385..cf3605552 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/PBRMaterialItem.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/PBRMaterialItem.cs @@ -43,12 +43,35 @@ namespace UniGLTF Transparent } - public static async Awaitable CreateAsync(int i, glTFMaterial src, GetTextureAsyncFunc getTexture) + public static GetTextureParam BaseColorTexture(glTF gltf, glTFMaterial src) + { + return GetTextureParam.Create(gltf, src.pbrMetallicRoughness.baseColorTexture.index); + } + + public static GetTextureParam MetallicRoughnessTexture(glTF gltf, glTFMaterial src) + { + return GetTextureParam.CreateMetallic(gltf, + src.pbrMetallicRoughness.metallicRoughnessTexture.index, + src.pbrMetallicRoughness.metallicFactor); + } + + public static GetTextureParam OcclusionTexture(glTF gltf, glTFMaterial src) + { + return GetTextureParam.CreateOcclusion(gltf, src.occlusionTexture.index); + } + + public static GetTextureParam NormalTexture(glTF gltf, glTFMaterial src) + { + return GetTextureParam.CreateNormal(gltf, src.normalTexture.index); + } + + public static async Awaitable CreateAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture) { if (getTexture == null) { - getTexture = _ => Awaitable.FromResult(null); + getTexture = (_x, _y) => Awaitable.FromResult(null); } + var src = gltf.materials[i]; var material = MaterialFactory.CreateMaterial(i, src, ShaderName); @@ -65,7 +88,7 @@ namespace UniGLTF if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) { - material.mainTexture = await getTexture(GetTextureParam.Create(src.pbrMetallicRoughness.baseColorTexture.index)); + material.mainTexture = await getTexture(gltf, BaseColorTexture(gltf, src)); // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.pbrMetallicRoughness.baseColorTexture, "_MainTex"); @@ -75,9 +98,7 @@ namespace UniGLTF { material.EnableKeyword("_METALLICGLOSSMAP"); - var texture = await getTexture(GetTextureParam.CreateMetallic( - src.pbrMetallicRoughness.metallicRoughnessTexture.index, - src.pbrMetallicRoughness.metallicFactor)); + var texture = await getTexture(gltf, MetallicRoughnessTexture(gltf, src)); if (texture != null) { material.SetTexture(GetTextureParam.METALLIC_GLOSS_PROP, texture); @@ -100,7 +121,7 @@ namespace UniGLTF if (src.normalTexture != null && src.normalTexture.index != -1) { material.EnableKeyword("_NORMALMAP"); - var texture = await getTexture(GetTextureParam.CreateNormal(src.normalTexture.index)); + var texture = await getTexture(gltf, NormalTexture(gltf, src)); if (texture != null) { material.SetTexture(GetTextureParam.NORMAL_PROP, texture); @@ -113,7 +134,7 @@ namespace UniGLTF if (src.occlusionTexture != null && src.occlusionTexture.index != -1) { - var texture = await getTexture(GetTextureParam.CreateOcclusion(src.occlusionTexture.index)); + var texture = await getTexture(gltf, OcclusionTexture(gltf, src)); if (texture != null) { material.SetTexture(GetTextureParam.OCCLUSION_PROP, texture); @@ -137,7 +158,7 @@ namespace UniGLTF if (src.emissiveTexture != null && src.emissiveTexture.index != -1) { - var texture = await getTexture(GetTextureParam.Create(src.emissiveTexture.index)); + var texture = await getTexture(gltf, GetTextureParam.Create(gltf, src.emissiveTexture.index)); if (texture != null) { material.SetTexture("_EmissionMap", texture); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/UnlitMaterialItem.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/UnlitMaterialItem.cs index f1f9ea2f1..cd382d012 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/UnlitMaterialItem.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialLoader/UnlitMaterialItem.cs @@ -7,19 +7,20 @@ namespace UniGLTF { public const string ShaderName = "UniGLTF/UniUnlit"; - public static async Awaitable CreateAsync(int i, glTFMaterial src, GetTextureAsyncFunc getTexture, bool hasVertexColor) + public static async Awaitable CreateAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture, bool hasVertexColor) { if (getTexture == null) { - getTexture = _ => Awaitable.FromResult(null); + getTexture = (_x, _y) => Awaitable.FromResult(default); } + var src = gltf.materials[i]; var material = MaterialFactory.CreateMaterial(i, src, ShaderName); // texture if (src.pbrMetallicRoughness.baseColorTexture != null) { - material.mainTexture = await getTexture(GetTextureParam.Create(src.pbrMetallicRoughness.baseColorTexture.index)); + material.mainTexture = await getTexture(gltf, GetTextureParam.Create(gltf, src.pbrMetallicRoughness.baseColorTexture.index)); // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.pbrMetallicRoughness.baseColorTexture, "_MainTex"); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs index ce0bdb40c..aa35e5e27 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs @@ -8,8 +8,6 @@ using UnityEngine; namespace UniGLTF { - - public class MeshImporter { const float FRAME_WEIGHT = 100.0f; @@ -109,7 +107,7 @@ namespace UniGLTF /// /// /// - public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) + public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, AxisInverter inverter) { foreach (var prim in gltfMesh.primitives) { @@ -119,7 +117,7 @@ namespace UniGLTF // position は必ずある var positions = ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION); var fillLength = m_positions.Count; - m_positions.AddRange(positions.Select(x => x.ReverseZ())); + m_positions.AddRange(positions.Select(inverter.InvertVector3)); // normal if (prim.attributes.NORMAL != -1) @@ -130,7 +128,7 @@ namespace UniGLTF throw new Exception("different length"); } FillZero(m_normals, fillLength); - m_normals.AddRange(normals.Select(x => x.ReverseZ())); + m_normals.AddRange(normals.Select(inverter.InvertVector3)); } #if false @@ -142,7 +140,7 @@ namespace UniGLTF throw new Exception("different length"); } FillZero(tangetns, fillLength); - tangents.AddRange(.Select(x => x.ReverseZ())); + tangents.AddRange(.Select(inverter.InvertVector4)); } #endif @@ -154,7 +152,7 @@ namespace UniGLTF { throw new Exception("different length"); } - if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) + if (ctx.Parser.IsGeneratedUniGLTFAndOlder(1, 16)) { #pragma warning disable 0612 // backward compatibility @@ -242,7 +240,7 @@ namespace UniGLTF throw new Exception("different length"); } FillZero(blendShape.Positions, fillLength); - blendShape.Positions.AddRange(array.Select(x => x.ReverseZ()).ToArray()); + blendShape.Positions.AddRange(array.Select(inverter.InvertVector3).ToArray()); } if (primTarget.NORMAL != -1) { @@ -252,7 +250,7 @@ namespace UniGLTF throw new Exception("different length"); } FillZero(blendShape.Normals, fillLength); - blendShape.Normals.AddRange(array.Select(x => x.ReverseZ()).ToArray()); + blendShape.Normals.AddRange(array.Select(inverter.InvertVector3).ToArray()); } if (primTarget.TANGENT != -1) { @@ -262,7 +260,7 @@ namespace UniGLTF throw new Exception("different length"); } FillZero(blendShape.Tangents, fillLength); - blendShape.Tangents.AddRange(array.Select(x => x.ReverseZ()).ToArray()); + blendShape.Tangents.AddRange(array.Select(inverter.InvertVector3).ToArray()); } m_blendShapes.Add(blendShape); } @@ -293,31 +291,31 @@ namespace UniGLTF /// /// /// - public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) + public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, AxisInverter inverter) { { // 同じVertexBufferを共有しているので先頭のモノを使う var prim = gltfMesh.primitives.First(); - m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ())); + m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(inverter.InvertVector3)); // normal if (prim.attributes.NORMAL != -1) { - m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ())); + m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).SelectInplace(inverter.InvertVector3)); } #if false // tangent if (prim.attributes.TANGENT != -1) { - tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).SelectInplace(x => x.ReverseZ())); + tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).SelectInplace(inverter.InvertVector4)); } #endif // uv if (prim.attributes.TEXCOORD_0 != -1) { - if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) + if (ctx.Parser.IsGeneratedUniGLTFAndOlder(1, 16)) { #pragma warning disable 0612 // backward compatibility @@ -403,17 +401,17 @@ namespace UniGLTF if (primTarget.POSITION != -1) { blendShape.Positions.Assign( - ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION), x => x.ReverseZ()); + ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION), inverter.InvertVector3); } if (primTarget.NORMAL != -1) { blendShape.Normals.Assign( - ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL), x => x.ReverseZ()); + ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL), inverter.InvertVector3); } if (primTarget.TANGENT != -1) { blendShape.Tangents.Assign( - ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT), x => x.ReverseZ()); + ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT), inverter.InvertVector3); } } } @@ -509,18 +507,18 @@ namespace UniGLTF return sharedAttributes; } - public MeshContext ReadMesh(ImporterContext ctx, int meshIndex) + public MeshContext ReadMesh(ImporterContext ctx, int meshIndex, AxisInverter inverter) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; var meshContext = new MeshContext(gltfMesh.name, meshIndex); if (HasSharedVertexBuffer(gltfMesh)) { - meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh); + meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh, inverter); } else { - meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh); + meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh, inverter); } meshContext.RenameBlendShape(gltfMesh); @@ -627,42 +625,15 @@ namespace UniGLTF } } - public static MeshWithMaterials BuildMesh(MaterialFactory ctx, MeshImporter.MeshContext meshContext) - { - var (mesh, recalculateTangents) = _BuildMesh(meshContext); - - if (recalculateTangents) - { - mesh.RecalculateTangents(); - } - - // 先にすべてのマテリアルを作成済みなのでテクスチャーは生成済み。Resultを使ってよい - var result = new MeshWithMaterials - { - Mesh = mesh, - Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray() - }; - - if (meshContext.BlendShapes.Count > 0) - { - var emptyVertices = new Vector3[mesh.vertexCount]; - foreach (var blendShape in meshContext.BlendShapes) - { - BuildBlendShape(mesh, meshContext, blendShape, emptyVertices); - } - } - return result; - } - public static async Awaitable BuildMeshAsync(MaterialFactory ctx, MeshImporter.MeshContext meshContext) { var (mesh, recalculateTangents) = _BuildMesh(meshContext); if (recalculateTangents) { - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); mesh.RecalculateTangents(); - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); } // 先にすべてのマテリアルを作成済みなのでテクスチャーは生成済み。Resultを使ってよい @@ -672,7 +643,7 @@ namespace UniGLTF Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray() }; - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); if (meshContext.BlendShapes.Count > 0) { var emptyVertices = new Vector3[mesh.vertexCount]; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs index b0782b1fa..da02b9272 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs @@ -16,7 +16,7 @@ namespace UniGLTF Debug.LogWarningFormat("node {0} contains /. replace _", node.name); nodeName = nodeName.Replace("/", "_"); } - if(string.IsNullOrEmpty(nodeName)) + if (string.IsNullOrEmpty(nodeName)) { nodeName = string.Format("nodeIndex_{0}", nodeIndex); } @@ -131,7 +131,7 @@ namespace UniGLTF // // fix node's coordinate. z-back to z-forward // - public static void FixCoordinate(ImporterContext context, List nodes) + public static void FixCoordinate(ImporterContext context, List nodes, AxisInverter inverter) { var globalTransformMap = nodes.ToDictionary(x => x.Transform, x => new PosRot { @@ -148,13 +148,13 @@ namespace UniGLTF foreach (var transform in t.Traverse()) { var g = globalTransformMap[transform]; - transform.position = g.Position.ReverseZ(); - transform.rotation = g.Rotation.ReverseZ(); + transform.position = inverter.InvertVector3(g.Position); + transform.rotation = inverter.InvertQuaternion(g.Rotation); } } } - public static void SetupSkinning(ImporterContext context, List nodes, int i) + public static void SetupSkinning(ImporterContext context, List nodes, int i, AxisInverter inverter) { var x = nodes[i]; var skinnedMeshRenderer = x.Transform.GetComponent(); @@ -181,7 +181,7 @@ namespace UniGLTF if (skin.inverseBindMatrices != -1) { var bindPoses = context.GLTF.GetArrayFromAccessor(skin.inverseBindMatrices) - .Select(y => y.ReverseZ()) + .Select(inverter.InvertMat4) .ToArray() ; mesh.bindposes = bindPoses; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs index 5c3b4e406..029efc3c4 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs @@ -12,7 +12,7 @@ namespace UniGLTF if (context.GLTF.animations != null && context.GLTF.animations.Any()) { var animation = context.Root.AddComponent(); - context.AnimationClips = ImportAnimationClips(context.GLTF); + context.AnimationClips = ImportAnimationClips(context.GLTF, context.InvertAxis); foreach (var clip in context.AnimationClips) { @@ -25,7 +25,7 @@ namespace UniGLTF } } - private List ImportAnimationClips(glTF gltf) + private List ImportAnimationClips(glTF gltf, Axises invertAxis) { var animationClips = new List(); for (var i = 0; i < gltf.animations.Count; ++i) @@ -46,7 +46,23 @@ namespace UniGLTF animation.name = $"animation:{i}"; } - animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation)); + AxisInverter inverter = default; + switch (invertAxis) + { + case Axises.X: + inverter = AxisInverter.ReverseX; + break; + + case Axises.Z: + inverter = AxisInverter.ReverseZ; + break; + + default: + throw new System.Exception(); + + } + + animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation, inverter)); } return animationClips; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureConverter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureConverter.cs index 3b400d799..52270561b 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureConverter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureConverter.cs @@ -31,22 +31,6 @@ namespace UniGLTF return copyTexture; } - public static void AppendTextureExtension(Texture texture, string extension) - { - if (!texture.name.EndsWith(extension)) - { - texture.name = texture.name + extension; - } - } - - public static void RemoveTextureExtension(Texture texture, string extension) - { - if (texture.name.EndsWith(extension)) - { - texture.name = texture.name.Replace(extension, ""); - } - } - struct ColorSpaceScope : IDisposable { bool m_sRGBWrite; @@ -194,8 +178,6 @@ namespace UniGLTF public class MetallicRoughnessConverter : ITextureConverter { - private const string m_extension = ".metallicRoughness"; - private float _smoothnessOrRoughness; public MetallicRoughnessConverter(float smoothnessOrRoughness) @@ -206,14 +188,12 @@ namespace UniGLTF public Texture2D GetImportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Import, null); - TextureConverter.AppendTextureExtension(converted, m_extension); return converted; } public Texture2D GetExportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Export, null); - TextureConverter.RemoveTextureExtension(converted, m_extension); return converted; } @@ -260,8 +240,6 @@ namespace UniGLTF public class NormalConverter : ITextureConverter { - private const string m_extension = ".normal"; - private Material m_decoder; private Material GetDecoder() { @@ -288,7 +266,6 @@ namespace UniGLTF { var mat = GetEncoder(); var converted = TextureConverter.Convert(texture, glTFTextureTypes.Normal, null, mat); - TextureConverter.AppendTextureExtension(converted, m_extension); return converted; } @@ -298,26 +275,22 @@ namespace UniGLTF { var mat = GetDecoder(); var converted = TextureConverter.Convert(texture, glTFTextureTypes.Normal, null, mat); - TextureConverter.RemoveTextureExtension(converted, m_extension); return converted; } } public class OcclusionConverter : ITextureConverter { - private const string m_extension = ".occlusion"; public Texture2D GetImportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Occlusion, Import, null); - TextureConverter.AppendTextureExtension(converted, m_extension); return converted; } public Texture2D GetExportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Occlusion, Export, null); - TextureConverter.RemoveTextureExtension(converted, m_extension); return converted; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GetTextureParam.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GetTextureParam.cs index c2bce5fbc..bc3f1c5b7 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GetTextureParam.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GetTextureParam.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using UnityEngine; +using System; namespace UniGLTF { @@ -9,6 +8,7 @@ namespace UniGLTF public const string METALLIC_GLOSS_PROP = "_MetallicGlossMap"; public const string OCCLUSION_PROP = "_OcclusionMap"; + public readonly string Name; public readonly string TextureType; public readonly float MetallicFactor; public readonly ushort? Index0; @@ -18,8 +18,14 @@ namespace UniGLTF public readonly ushort? Index4; public readonly ushort? Index5; - public GetTextureParam(string textureType, float metallicFactor, int i0, int i1, int i2, int i3, int i4, int i5) + public GetTextureParam(string name, string textureType, float metallicFactor, int i0, int i1, int i2, int i3, int i4, int i5) { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(); + } + Name = name; + TextureType = textureType; MetallicFactor = metallicFactor; Index0 = (ushort)i0; @@ -30,25 +36,46 @@ namespace UniGLTF Index5 = (ushort)i5; } - public static GetTextureParam Create(int index) + public static GetTextureParam Create(glTF gltf, int textureIndex) { - return new GetTextureParam(default, default, index, default, default, default, default, default); + var name = gltf.textures[textureIndex].name; + return new GetTextureParam(name, default, default, textureIndex, default, default, default, default, default); } - public static GetTextureParam CreateNormal(int index) + public static GetTextureParam Create(glTF gltf, int index, string prop) { - return new GetTextureParam(NORMAL_PROP, default, index, default, default, default, default, default); + switch (prop) + { + case NORMAL_PROP: + return CreateNormal(gltf, index); + + case OCCLUSION_PROP: + return CreateOcclusion(gltf, index); + + case METALLIC_GLOSS_PROP: + return CreateMetallic(gltf, index, 1); + + default: + return Create(gltf, index); + } } - public static GetTextureParam CreateMetallic(int index, float metallicFactor) + public static GetTextureParam CreateNormal(glTF gltf, int textureIndex) { - return new GetTextureParam(METALLIC_GLOSS_PROP, metallicFactor, index, default, default, default, default, default); + var name = gltf.textures[textureIndex].name; + return new GetTextureParam(name, NORMAL_PROP, default, textureIndex, default, default, default, default, default); } - public static GetTextureParam CreateOcclusion(int index) + public static GetTextureParam CreateMetallic(glTF gltf, int textureIndex, float metallicFactor) { - return new GetTextureParam(OCCLUSION_PROP, default, index, default, default, default, default, default); + var name = gltf.textures[textureIndex].name; + return new GetTextureParam(name + ".metallicRoughness", METALLIC_GLOSS_PROP, metallicFactor, textureIndex, default, default, default, default, default); + } + + public static GetTextureParam CreateOcclusion(glTF gltf, int textureIndex) + { + var name = gltf.textures[textureIndex].name; + return new GetTextureParam(name + ".occlusion", OCCLUSION_PROP, default, textureIndex, default, default, default, default, default); } } - } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GltfTextureLoader.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GltfTextureLoader.cs index 3a526a60c..5169e5f70 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GltfTextureLoader.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/GltfTextureLoader.cs @@ -24,27 +24,25 @@ namespace UniGLTF } } - public static async Awaitable LoadTextureAsync(glTF gltf, IStorage storage, int index) + public static async Awaitable LoadTextureAsync(glTF gltf, IStorage storage, int textureIndex) { - string m_textureName = default; - var imageBytes = await Awaitable.Run(() => { - var imageIndex = gltf.GetImageIndexFromTextureIndex(index); - var segments = gltf.GetImageBytes(storage, imageIndex, out m_textureName); + var imageIndex = gltf.textures[textureIndex].source; + var segments = gltf.GetImageBytes(storage, imageIndex); return ToArray(segments); }); // // texture from image(png etc) bytes // - var textureType = TextureIO.GetglTFTextureType(gltf, index); + var textureType = TextureIO.GetglTFTextureType(gltf, textureIndex); var colorSpace = TextureIO.GetColorSpace(textureType); var isLinear = colorSpace == RenderTextureReadWrite.Linear; - var sampler = gltf.GetSamplerFromTextureIndex(index); + var sampler = gltf.GetSamplerFromTextureIndex(textureIndex); var texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, isLinear); - texture.name = m_textureName; + texture.name = gltf.textures[textureIndex].name; if (imageBytes != null) { texture.LoadImage(imageBytes); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs index debf74e16..1b0ff44d1 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/TextureFactory.cs @@ -1,28 +1,82 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using UniGLTF.AltTask; -using UnityEditor; using UnityEngine; +using System.Linq; +#if UNITY_EDITOR +using UnityEditor; +#endif namespace UniGLTF { - public delegate Awaitable GetTextureAsyncFunc(GetTextureParam param); - public class TextureFactory : IDisposable + [Flags] + public enum TextureLoadFlags + { + None = 0, + Used = 1, + External = 1 << 1, + } + public struct TextureLoadInfo + { + public readonly Texture2D Texture; + public readonly TextureLoadFlags Flags; + public bool IsUsed => Flags.HasFlag(TextureLoadFlags.Used); + public bool IsExternal => Flags.HasFlag(TextureLoadFlags.External); + + public TextureLoadInfo(Texture2D texture, bool used, bool isExternal) + { + Texture = texture; + var flags = TextureLoadFlags.None; + if (used) + { + flags |= TextureLoadFlags.Used; + } + if (isExternal) + { + flags |= TextureLoadFlags.External; + } + Flags = flags; + } + } + + public delegate Awaitable GetTextureAsyncFunc(glTF gltf, GetTextureParam param); + public class TextureFactory : IDisposable { glTF m_gltf; IStorage m_storage; + Dictionary m_externalMap; + public bool TryGetExternal(GetTextureParam param, bool used, out Texture2D external) + { + if (param.Index0.HasValue && m_externalMap != null) + { + if (m_externalMap.TryGetValue(param.Name, out external)) + { + // Debug.Log($"use external: {param.Name}"); + m_textureCache.Add(param.Name, new TextureLoadInfo(external, used, true)); + return external; + } + } + external = default; + return false; + } public UnityPath ImageBaseDir { get; set; } - public TextureFactory(glTF gltf, IStorage storage) + public TextureFactory(glTF gltf, IStorage storage, + IEnumerable<(string, UnityEngine.Object)> externalMap) { m_gltf = gltf; m_storage = storage; + if (externalMap != null) + { + m_externalMap = externalMap + .Select(kv => (kv.Item1, kv.Item2 as Texture2D)) + .Where(kv => kv.Item2 != null) + .ToDictionary(kv => kv.Item1, kv => kv.Item2); + } } - List m_textuers = new List(); public void Dispose() { foreach (var x in ObjectsForSubAsset()) @@ -35,21 +89,35 @@ namespace UniGLTF { foreach (var kv in m_textureCache) { - yield return kv.Value; + yield return kv.Value.Texture; } } - Dictionary m_textureCache = new Dictionary(); + Dictionary m_textureCache = new Dictionary(); - public virtual Awaitable LoadTextureAsync(int index) + public IEnumerable Textures => m_textureCache.Values; + + public virtual async Awaitable LoadTextureAsync(int index, bool used) { #if UNIGLTF_USE_WEBREQUEST_TEXTURELOADER return UnityWebRequestTextureLoader.LoadTextureAsync(index); #else - return GltfTextureLoader.LoadTextureAsync(m_gltf, m_storage, index); + var texture = await GltfTextureLoader.LoadTextureAsync(m_gltf, m_storage, index); + return new TextureLoadInfo(texture, used, false); #endif } + async Awaitable GetOrCreateBaseTexture(glTF gltf, int textureIndex, bool used) + { + var name = gltf.textures[textureIndex].name; + if (!m_textureCache.TryGetValue(name, out TextureLoadInfo cacheInfo)) + { + cacheInfo = await LoadTextureAsync(textureIndex, used); + m_textureCache.Add(name, cacheInfo); + } + return cacheInfo; + } + /// /// テクスチャーをロード、必要であれば変換して返す。 /// 同じものはキャッシュを返す @@ -58,20 +126,15 @@ namespace UniGLTF /// METALLIC_GLOSS_PROPの追加パラメーター /// gltf の texture index /// - public async Awaitable GetTextureAsync(GetTextureParam param) + public async Awaitable GetTextureAsync(glTF gltf, GetTextureParam param) { - if (m_textureCache.TryGetValue(param, out Texture2D texture)) + if (m_textureCache.TryGetValue(param.Name, out TextureLoadInfo cacheInfo)) { - return texture; + return cacheInfo.Texture; } - + if (TryGetExternal(param, true, out Texture2D external)) { - var defaultParam = GetTextureParam.Create(param.Index0.Value); - if (!m_textureCache.TryGetValue(defaultParam, out texture)) - { - texture = await LoadTextureAsync(param.Index0.Value); - m_textureCache.Add(defaultParam, texture); - } + return external; } switch (param.TextureType) @@ -80,48 +143,55 @@ namespace UniGLTF { if (Application.isPlaying) { - var converted = new NormalConverter().GetImportTexture(texture); - m_textureCache.Add(param, converted); - return converted; + var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, false); + var converted = new NormalConverter().GetImportTexture(baseTexture.Texture); + var info = new TextureLoadInfo(converted, true, false); + m_textureCache.Add(param.Name, info); + return info.Texture; } else { #if UNITY_EDITOR - var textureAssetPath = AssetDatabase.GetAssetPath(texture); - if (!string.IsNullOrEmpty(textureAssetPath)) - { - TextureIO.MarkTextureAssetAsNormalMap(textureAssetPath); - } - else - { - Debug.LogWarningFormat("no asset for {0}", texture); - } + var info = await LoadTextureAsync(param.Index0.Value, true); + var name = gltf.textures[param.Index0.Value].name; + m_textureCache.Add(name, info); + + var textureAssetPath = AssetDatabase.GetAssetPath(info.Texture); + TextureIO.MarkTextureAssetAsNormalMap(textureAssetPath); #endif - m_textureCache.Add(param, texture); - return texture; + return info.Texture; } } case GetTextureParam.METALLIC_GLOSS_PROP: { // Bake roughnessFactor values into a texture. - var converted = new MetallicRoughnessConverter(param.MetallicFactor).GetImportTexture(texture); - m_textureCache.Add(param, converted); - return converted; + var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, false); + var converted = new MetallicRoughnessConverter(param.MetallicFactor).GetImportTexture(baseTexture.Texture); + converted.name = param.Name; + var info = new TextureLoadInfo(converted, true, false); + m_textureCache.Add(param.Name, info); + return info.Texture; } case GetTextureParam.OCCLUSION_PROP: { - var converted = new OcclusionConverter().GetImportTexture(texture); - m_textureCache.Add(param, converted); - return converted; + var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, false); + var converted = new OcclusionConverter().GetImportTexture(baseTexture.Texture); + converted.name = param.Name; + var info = new TextureLoadInfo(converted, true, false); + m_textureCache.Add(param.Name, info); + return info.Texture; } default: - return texture; - } + { + var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, true); + return baseTexture.Texture; + } - throw new NotImplementedException(); + throw new NotImplementedException(); + } } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/UnityWebRequestTextureLoader.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/UnityWebRequestTextureLoader.cs index 347fa074e..5712e8161 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/UnityWebRequestTextureLoader.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureLoader/UnityWebRequestTextureLoader.cs @@ -55,8 +55,8 @@ namespace UniGLTF public IEnumerator ProcessOnMainThread(glTF gltf, IStorage storage, bool isLinear, glTFTextureSampler sampler) { - var imageIndex = gltf.GetImageIndexFromTextureIndex(m_textureIndex); - var bytes = gltf.GetImageBytes(storage, imageIndex, out m_textureName); + var gltfTexture = gltf.textures[m_textureIndex]; + var bytes = gltf.GetImageBytes(storage, gltfTexture.source); // tmp file var tmp = Path.GetTempFileName(); diff --git a/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs b/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs index 8d0ce2d1b..cc2ce351d 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs @@ -98,7 +98,7 @@ namespace UniGLTF public void UniGLTFSimpleSceneTest() { var go = CreateSimpleScene(); - var context = new ImporterContext(); + ImporterContext context = default; try { @@ -117,9 +117,12 @@ namespace UniGLTF json = gltf.ToJson(); } + // parse + var parser = new GltfParser(); + parser.ParseJson(json, new SimpleStorage(new ArraySegment())); + // import - context.ParseJson(json, new SimpleStorage(new ArraySegment())); - //Debug.LogFormat("{0}", context.Json); + context = new ImporterContext(parser); context.Load(); AssertAreEqual(go.transform, context.Root.transform); @@ -128,7 +131,10 @@ namespace UniGLTF { //Debug.LogFormat("Destroy, {0}", go.name); GameObject.DestroyImmediate(go); - context.EditorDestroyRootAndAssets(); + if (context != null) + { + context.EditorDestroyRootAndAssets(); + } } } @@ -191,12 +197,12 @@ namespace UniGLTF [Test] public void VersionChecker() { - Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("hoge", 1, 16)); - Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.16", 1, 16)); - Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.15", 1, 16)); - Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-11.16", 1, 16)); - Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-0.16", 1, 16)); - Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF", 1, 16)); + Assert.False(GltfParser.IsGeneratedUniGLTFAndOlderThan("hoge", 1, 16)); + Assert.False(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.16", 1, 16)); + Assert.True(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.15", 1, 16)); + Assert.False(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-11.16", 1, 16)); + Assert.True(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-0.16", 1, 16)); + Assert.True(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF", 1, 16)); } [Test] @@ -439,7 +445,7 @@ namespace UniGLTF public void SkinTestEmptyName() { var model = new glTFSkin() - { + { name = "", inverseBindMatrices = 4, joints = new int[] { 1 }, @@ -559,8 +565,9 @@ namespace UniGLTF // import { - var context = new ImporterContext(); - context.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); + var parser = new GltfParser(); + parser.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); + var context = new ImporterContext(parser); //Debug.LogFormat("{0}", context.Json); context.Load(); @@ -577,9 +584,10 @@ namespace UniGLTF // import new version { - var context = new ImporterContext(); - context.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); + var parser = new GltfParser(); + parser.ParseJson(json, new SimpleStorage(new ArraySegment(new byte[1024 * 1024]))); //Debug.LogFormat("{0}", context.Json); + var context = new ImporterContext(parser); context.Load(); var importedRed = context.Root.transform.GetChild(0); diff --git a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs index ebbcf2b28..fb7203026 100644 --- a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs +++ b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs @@ -42,8 +42,10 @@ namespace VRM.Samples public void ImportExportTest() { var path = AliciaPath; - var context = new VRMImporterContext(); - context.ParseGlb(File.ReadAllBytes(path)); + var parser = new GltfParser(); + parser.ParseGlb(File.ReadAllBytes(path)); + + var context = new VRMImporterContext(parser); context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); @@ -114,8 +116,9 @@ namespace VRM.Samples public void MeshCopyTest() { var path = AliciaPath; - var context = new VRMImporterContext(); - context.ParseGlb(File.ReadAllBytes(path)); + var parser = new GltfParser(); + parser.ParseGlb(File.ReadAllBytes(path)); + var context = new VRMImporterContext(parser); context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); @@ -133,8 +136,9 @@ namespace VRM.Samples { // Aliciaを古いデシリアライザでロードする var path = AliciaPath; - var context = new VRMImporterContext(); - context.ParseGlb(File.ReadAllBytes(path)); + var parser = new GltfParser(); + parser.ParseGlb(File.ReadAllBytes(path)); + var context = new VRMImporterContext(parser); var oldJson = context.GLTF.ToJson().ParseAsJson().ToString(" "); // 生成シリアライザでJSON化する diff --git a/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs b/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs index 53f846acd..888a4dc66 100644 --- a/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs +++ b/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs @@ -46,11 +46,11 @@ namespace VRM.Samples var bytes = File.ReadAllBytes(path); // なんらかの方法でByte列を得た - var context = new VRMImporterContext(); - // GLB形式でJSONを取得しParseします - context.ParseGlb(bytes); + var parser = new GltfParser(); + parser.ParseGlb(bytes); + var context = new VRMImporterContext(parser); // metaを取得(todo: thumbnailテクスチャのロード) var meta = await context.ReadMetaAsync(); diff --git a/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs b/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs index 34aba0ad2..192de0f0f 100644 --- a/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs +++ b/Assets/VRM.Samples/Scripts/VRMRuntimeLoader.cs @@ -1,14 +1,11 @@ #pragma warning disable 0414 using System.IO; using UniGLTF; -using UniGLTF.AltTask; using UnityEngine; namespace VRM.Samples { - - public class VRMRuntimeLoader : MonoBehaviour { [SerializeField] @@ -89,33 +86,33 @@ namespace VRM.Samples var bytes = File.ReadAllBytes(path); // なんらかの方法でByte列を得た - var context = new VRMImporterContext(); - // GLB形式でJSONを取得しParseします - context.ParseGlb(bytes); + var parser = new GltfParser(); + parser.Parse(path, bytes); + var context = new VRMImporterContext(parser); // metaを取得(todo: thumbnailテクスチャのロード) var meta = await context.ReadMetaAsync(); Debug.LogFormat("meta: title:{0}", meta.Title); - // ParseしたJSONをシーンオブジェクトに変換していく if (m_loadAsync) { - await LoadAsync(context); + await context.LoadAsync(); } else { - context.LoadAsync(); - OnLoaded(context); + context.Load(); } + + OnLoaded(context); } /// /// メタが不要な場合のローダー /// - void LoadVRMClicked_without_meta() + async void LoadVRMClicked_without_meta() { #if UNITY_STANDALONE_WIN var path = FileDialogForWindows.FileDialog("open VRM", ".vrm"); @@ -129,55 +126,23 @@ namespace VRM.Samples return; } -#if true var bytes = File.ReadAllBytes(path); // なんらかの方法でByte列を得た - var context = new VRMImporterContext(); - // GLB形式でJSONを取得しParseします - context.ParseGlb(bytes); + var parser = new GltfParser(); + parser.ParseGlb(bytes); + var context = new VRMImporterContext(parser); if (m_loadAsync) { - // ローカルファイルシステムからロードします - LoadAsync(context); + await context.LoadAsync(); } else { context.Load(); - OnLoaded(context); } - -#else - // ParseしたJSONをシーンオブジェクトに変換していく - if (m_loadAsync) - { - // ローカルファイルシステムからロードします - VRMImporter.LoadVrmAsync(path, OnLoaded); - } - else - { - var root=VRMImporter.LoadFromPath(path); - OnLoaded(root); - } -#endif - } - - - async Awaitable LoadAsync(VRMImporterContext context) - { -#if true - var now = Time.time; - await context.LoadAsync(); - - var delta = Time.time - now; - Debug.LogFormat("LoadAsync {0:0.0} seconds", delta); OnLoaded(context); -#else - // ローカルファイルシステムからロードします - VRMImporter.LoadVrmAsync(path, OnLoaded); -#endif } void LoadBVHClicked() diff --git a/Assets/VRM.Samples/Scripts/ViewerUI.cs b/Assets/VRM.Samples/Scripts/ViewerUI.cs index a760a8fc6..b5fcfb76f 100644 --- a/Assets/VRM.Samples/Scripts/ViewerUI.cs +++ b/Assets/VRM.Samples/Scripts/ViewerUI.cs @@ -309,15 +309,15 @@ namespace VRM.Samples { case ".vrm": { - var context = new VRMImporterContext(); var file = File.ReadAllBytes(path); - context.ParseGlb(file); + + var parser = new GltfParser(); + parser.ParseGlb(file); + + var context = new VRMImporterContext(parser); await m_texts.UpdateMetaAsync(context); -#if true await context.LoadAsync(); -#else - context.Load(); -#endif + context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); context.ShowMeshes(); @@ -327,9 +327,11 @@ namespace VRM.Samples case ".glb": { - var context = new UniGLTF.ImporterContext(); var file = File.ReadAllBytes(path); - context.ParseGlb(file); + var parser = new GltfParser(); + parser.ParseGlb(file); + + var context = new UniGLTF.ImporterContext(parser); context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); @@ -341,8 +343,10 @@ namespace VRM.Samples case ".gltf": case ".zip": { - var context = new UniGLTF.ImporterContext(); - context.Parse(path); + var parser = new GltfParser(); + parser.ParsePath(path); + + var context = new UniGLTF.ImporterContext(parser); context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); diff --git a/Assets/VRM/Editor/Format/VRMImporterMenu.cs b/Assets/VRM/Editor/Format/VRMImporterMenu.cs index 59d4430a6..0741f360b 100644 --- a/Assets/VRM/Editor/Format/VRMImporterMenu.cs +++ b/Assets/VRM/Editor/Format/VRMImporterMenu.cs @@ -20,8 +20,10 @@ namespace VRM if (Application.isPlaying) { // load into scene - var context = new VRMImporterContext(); - context.Load(path); + var parser = new GltfParser(); + parser.ParsePath(path); + var context = new VRMImporterContext(parser); + context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); Selection.activeGameObject = context.Root; @@ -48,8 +50,9 @@ namespace VRM // import as asset var prefabPath = UnityPath.FromUnityPath(assetPath); - var context = new VRMImporterContext(); - context.ParseGlb(File.ReadAllBytes(path)); + var parser = new GltfParser(); + parser.ParseGlb(File.ReadAllBytes(path)); + var context = new VRMImporterContext(parser); context.ExtractImages(prefabPath); EditorApplication.delayCall += () => diff --git a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs index 8bdcaaab0..5806cdfad 100644 --- a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs +++ b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs @@ -36,11 +36,11 @@ namespace VRM { throw new Exception(); } - var context = new VRMImporterContext(); + var parser = new GltfParser(); try { - context.ParseGlb(File.ReadAllBytes(path.FullPath)); + parser.ParseGlb(File.ReadAllBytes(path.FullPath)); } catch (KeyNotFoundException) { @@ -52,6 +52,7 @@ namespace VRM var prefabPath = path.Parent.Child(path.FileNameWithoutExtension + ".prefab"); // save texture assets ! + var context = new VRMImporterContext(parser); context.ExtractImages(prefabPath); EditorApplication.delayCall += () => diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index a3ae2051c..79709b567 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -15,30 +15,8 @@ namespace VRM { public VRM.glTF_VRM_extensions VRM { get; private set; } - public VRMImporterContext() + public VRMImporterContext(GltfParser parser) : base(parser) { - } - - public override void Parse(string path, byte[] bytes) - { - var ext = Path.GetExtension(path).ToLower(); - switch (ext) - { - case ".vrm": - ParseGlb(bytes); - break; - - default: - base.Parse(path, bytes); - break; - } - } - - public override void ParseJson(string json, IStorage storage) - { - // parse GLTF part(core + unlit, textureTransform, targetNames) - base.ParseJson(json, storage); - // parse VRM part if (glTF_VRM_extensions.TryDeserilize(GLTF.extensions, out glTF_VRM_extensions vrm)) { @@ -53,7 +31,7 @@ namespace VRM } #region OnLoad - protected override async Awaitable OnLoadModel() + protected override async Awaitable OnLoadModel(Func MeasureTime) { Root.name = "VRM"; @@ -61,26 +39,26 @@ namespace VRM { await LoadMetaAsync(); } - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); using (MeasureTime("VRM LoadHumanoid")) { LoadHumanoid(); } - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); using (MeasureTime("VRM LoadBlendShapeMaster")) { LoadBlendShapeMaster(); } - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); using (MeasureTime("VRM LoadSecondary")) { VRMSpringUtility.LoadSecondary(Root.transform, Nodes, VRM.secondaryAnimation); } - await LoopAwaitable.Create(); + await NextFrameAwaitable.Create(); using (MeasureTime("VRM LoadFirstPerson")) { @@ -196,6 +174,7 @@ namespace VRM } var material = MaterialFactory.Materials + .Select(y => y.Asset) .FirstOrDefault(y => y.name == x.materialName); var propertyName = x.propertyName; if (x.propertyName.FastEndsWith("_ST_S") @@ -307,7 +286,7 @@ namespace VRM meta.ContactInformation = gltfMeta.contactInformation; meta.Reference = gltfMeta.reference; meta.Title = gltfMeta.title; - meta.Thumbnail = await TextureFactory.GetTextureAsync(GetTextureParam.Create(gltfMeta.texture)); + meta.Thumbnail = await TextureFactory.GetTextureAsync(GLTF, GetTextureParam.Create(GLTF, gltfMeta.texture)); meta.AllowedUser = gltfMeta.allowedUser; meta.ViolentUssage = gltfMeta.violentUssage; meta.SexualUssage = gltfMeta.sexualUssage; diff --git a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs b/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs index b39524f14..b18313c66 100644 --- a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs +++ b/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs @@ -71,7 +71,8 @@ namespace VRM } foreach (var kv in item.textureProperties) { - var texture = await getTexture(new GetTextureParam(kv.Key, default, kv.Value, default, default, default, default, default)); + var param = GetTextureParam.Create(gltf, kv.Value, kv.Key); + var texture = await getTexture(gltf, param); if (texture != null) { material.SetTexture(kv.Key, texture); diff --git a/Assets/VRM10.Samples/Runtime/ViewerUI.cs b/Assets/VRM10.Samples/Runtime/ViewerUI.cs index b23a42874..3d87e4089 100644 --- a/Assets/VRM10.Samples/Runtime/ViewerUI.cs +++ b/Assets/VRM10.Samples/Runtime/ViewerUI.cs @@ -333,9 +333,11 @@ namespace UniVRM10.Samples case ".glb": { - var context = new UniGLTF.ImporterContext(); var file = File.ReadAllBytes(path); - context.ParseGlb(file); + var parser = new GltfParser(); + parser.ParseGlb(file); + + var context = new UniGLTF.ImporterContext(parser); context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); @@ -347,8 +349,10 @@ namespace UniVRM10.Samples case ".gltf": case ".zip": { - var context = new UniGLTF.ImporterContext(); - context.Parse(path); + var parser = new GltfParser(); + parser.ParsePath(path); + + var context = new UniGLTF.ImporterContext(parser); context.Load(); context.ShowMeshes(); context.EnableUpdateWhenOffscreen(); diff --git a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporter.cs b/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporter.cs deleted file mode 100644 index 7fcf0c4bf..000000000 --- a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporter.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEditor.Experimental.AssetImporters; -using UnityEngine; -using VrmLib; - -namespace UniVRM10 -{ -#if flase - [ScriptedImporter(1, "glb")] -#endif - public class GltfScriptedImporter : ScriptedImporter, IExternalUnityObject - { - const string TextureDirName = "Textures"; - const string MaterialDirName = "Materials"; - - public override void OnImportAsset(AssetImportContext ctx) - { - Debug.Log("OnImportAsset to " + ctx.assetPath); - - try - { - // Create model - VrmLib.Model model = CreateGlbModel(ctx.assetPath); - Debug.Log($"ModelLoader.Load: {model}"); - - // Build Unity Model - var assets = EditorUnityBuilder.ToUnityAsset(model, assetPath, this); - - // Texture - var externalTextures = this.GetExternalUnityObjects(); - foreach (var texture in assets.Textures) - { - if (texture == null) - continue; - - if (externalTextures.ContainsValue(texture)) - { - } - else - { - ctx.AddObjectToAsset(texture.name, texture); - } - } - - // Material - var externalMaterials = this.GetExternalUnityObjects(); - foreach (var material in assets.Materials) - { - if (material == null) - continue; - - if (externalMaterials.ContainsValue(material)) - { - - } - else - { - ctx.AddObjectToAsset(material.name, material); - } - } - - // Mesh - foreach (var mesh in assets.Meshes) - { - ctx.AddObjectToAsset(mesh.name, mesh); - } - - // Root - ctx.AddObjectToAsset(assets.Root.name, assets.Root); - ctx.SetMainObject(assets.Root); - - } - catch (System.Exception ex) - { - Debug.LogError(ex); - } - } - - private Model CreateGlbModel(string path) - { - var bytes = File.ReadAllBytes(path); - if (!UniGLTF.Glb.TryParse(bytes, out UniGLTF.Glb glb, out Exception ex)) - { - throw ex; - } - - VrmLib.Model model = null; - VrmLib.IVrmStorage storage; - storage = new Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes); - model = VrmLib.ModelLoader.Load(storage, Path.GetFileNameWithoutExtension(path)); - model.ConvertCoordinate(VrmLib.Coordinates.Unity); - - return model; - } - - public void ExtractTextures() - { - this.ExtractTextures(TextureDirName, (path) => { return CreateGlbModel(path); }); - AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); - } - - public void ExtractMaterials() - { - this.ExtractAssets(MaterialDirName, ".mat"); - AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); - } - - public void ExtractMaterialsAndTextures() - { - this.ExtractTextures(TextureDirName, (path) => { return CreateGlbModel(path); }, () => { this.ExtractAssets(MaterialDirName, ".mat"); }); - AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); - } - - public Dictionary GetExternalUnityObjects() where T : UnityEngine.Object - { - return this.GetExternalObjectMap().Where(x => x.Key.type == typeof(T)).ToDictionary(x => x.Key.name, x => (T)x.Value); - } - - public void SetExternalUnityObject(UnityEditor.AssetImporter.SourceAssetIdentifier sourceAssetIdentifier, T obj) where T : UnityEngine.Object - { - this.AddRemap(sourceAssetIdentifier, obj); - AssetDatabase.WriteImportSettingsIfDirty(this.assetPath); - AssetDatabase.ImportAsset(this.assetPath, ImportAssetOptions.ForceUpdate); - } - } -} diff --git a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporterEditorGUI.cs b/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporterEditorGUI.cs deleted file mode 100644 index 596dc6a66..000000000 --- a/Assets/VRM10/Editor/ScriptedImporter/GltfScriptedImporterEditorGUI.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEditor; -using UnityEditor.Experimental.AssetImporters; -using UnityEngine; - -namespace UniVRM10 -{ - [CustomEditor(typeof(GltfScriptedImporter))] - public class GltfScriptedImporterEditorGUI : ScriptedImporterEditor - { - - private bool _isOpen = true; - - public override void OnInspectorGUI() - { - var importer = target as GltfScriptedImporter; - - EditorGUILayout.LabelField("Extract settings"); - - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.PrefixLabel("Materials And Textures"); - GUI.enabled = !(importer.GetExternalUnityObjects().Any() - && importer.GetExternalUnityObjects().Any()); - if (GUILayout.Button("Extract")) - { - importer.ExtractMaterialsAndTextures(); - } - GUI.enabled = !GUI.enabled; - if (GUILayout.Button("Clear")) - { - importer.ClearExternalObjects(); - importer.ClearExternalObjects(); - } - GUI.enabled = true; - EditorGUILayout.EndHorizontal(); - - // ObjectMap - DrawRemapGUI("Material Remap", importer); - DrawRemapGUI("Texture Remap", importer); - - base.OnInspectorGUI(); - } - - private void DrawRemapGUI(string title, GltfScriptedImporter importer) where T: UnityEngine.Object - { - EditorGUILayout.Foldout(_isOpen, title); - EditorGUI.indentLevel++; - var objects = importer.GetExternalObjectMap().Where(x => x.Key.type == typeof(T)); - foreach (var obj in objects) - { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.PrefixLabel(obj.Key.name); - var asset = EditorGUILayout.ObjectField(obj.Value, obj.Key.type, true) as T; - if(asset != obj.Value) - { - importer.SetExternalUnityObject(obj.Key, asset); - } - EditorGUILayout.EndHorizontal(); - } - EditorGUI.indentLevel--; - } - } -}