diff --git a/Editor/Scripts/GLTFImporter.cs b/Editor/Scripts/GLTFImporter.cs index 0d0f721f2..872f5b86b 100644 --- a/Editor/Scripts/GLTFImporter.cs +++ b/Editor/Scripts/GLTFImporter.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Linq; using System; +using System.Text.RegularExpressions; using Object = UnityEngine.Object; using UnityGLTF.Loader; using GLTF.Schema; @@ -28,7 +29,7 @@ using UnityGLTF.Plugins; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; -using UnityEngine.Rendering; +using UnityGLTF.Cache; #else using UnityEditor.Experimental.AssetImporters; #endif @@ -48,7 +49,7 @@ namespace UnityGLTF #endif public class GLTFImporter : ScriptedImporter, IGLTFImportRemap { - private const int ImporterVersion = 9; + private const int ImporterVersion = 11; private static void EnsureShadersAreLoaded() { @@ -88,6 +89,7 @@ private static void EnsureShadersAreLoaded() [SerializeField] internal bool _readWriteEnabled = true; [SerializeField] internal bool _generateColliders = false; [SerializeField] internal bool _swapUvs = false; + [SerializeField] internal bool _generateLightmapUVs = false; [SerializeField] internal GLTFImporterNormals _importNormals = GLTFImporterNormals.Import; [SerializeField] internal GLTFImporterNormals _importTangents = GLTFImporterNormals.Import; @@ -108,6 +110,7 @@ private static void EnsureShadersAreLoaded() // asset remapping [SerializeField] internal Material[] m_Materials = new Material[0]; [SerializeField] internal Texture[] m_Textures = new Texture[0]; + [SerializeField] internal string[] m_OrgTexturesNames = new string[0]; [SerializeField] internal bool m_HasSceneData = true; [SerializeField] internal bool m_HasAnimationData = true; [SerializeField] internal bool m_HasMaterialData = true; @@ -143,8 +146,10 @@ internal enum GLTFImporterTextureCompressionQuality [Serializable] public class TextureInfo { + public int imageIndex; public Texture2D texture; public bool shouldBeLinear; + public bool isExtractable; } [Serializable] @@ -223,6 +228,65 @@ void CheckAndAddDependency(string uri) return dependencies.Distinct().ToArray(); } + internal static string ValidateFilename(string filename) + { + return Regex.Replace(filename, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled); + } + + public string ExtractTexture(TextureInfo textureInfo, string toPath) + { + var projectFilePath = assetPath; + + // TODO: replace with GltfImportContext + var importOptions = new ImportOptions + { + DataLoader = new FileLoader(Path.GetDirectoryName(projectFilePath)), + AnimationMethod = _importAnimations, + AnimationLoopTime = _animationLoopTime, + AnimationLoopPose = _animationLoopPose, + //ImportContext = context, + SwapUVs = _swapUvs, + ImportNormals = _importNormals, + ImportTangents = _importTangents + }; + + string resultPath = ""; + using (var stream = File.OpenRead(projectFilePath)) + { + GLTFParser.ParseJson(stream, out var gltfRoot); + stream.Position = 0; // Make sure the read position is changed back to the beginning of the file + var loader = new GLTFSceneImporter(gltfRoot, stream, importOptions); + loader.LoadUnreferencedImagesAndMaterials = true; + loader.MaximumLod = _maximumLod; + loader.IsMultithreaded = false; + + AsyncHelpers.RunSync( () => + loader.SetupLoad(async () => + { + var imageIndex = textureInfo.imageIndex; + if (imageIndex >= 0 && imageIndex < loader.Root.Images.Count) + { + var result = await loader.GetImageFileExtensionAndData(gltfRoot.Images[imageIndex]); + var fileName = ValidateFilename(textureInfo.texture.name); + var relativePath = Path.Combine(toPath, fileName + result.Item1); + relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar); + relativePath = relativePath.Replace('\\', Path.DirectorySeparatorChar); + + var fullPath = Path.GetFullPath(relativePath); + await File.WriteAllBytesAsync(fullPath, result.Item2); + resultPath = relativePath; + } + else + { + Debug.LogError("Invalid image index " + imageIndex); + } + + })); + } + + return resultPath; + } + public override void OnImportAsset(AssetImportContext ctx) { var plugins = new List(); @@ -562,6 +626,26 @@ string GetUniqueName(string desiredName) .Where(x => x) .Union(invalidTextures).Distinct().ToList(); + m_OrgTexturesNames = new string[textures.Count]; + + for (int i = 0; i < textures.Count; i++) + { + bool found = false; + for (int j = 0; j < importer.TextureCache.Length; j++) + { + if (textures[i] == importer.TextureCache[j].Texture) + { + found = true; + m_OrgTexturesNames[i] = importer.TextureSourceAssetId[j].name; + break; + } + } + + if (!found) + { + m_OrgTexturesNames[i] = textures[i].name; + } + } // if we're not importing materials or textures, we can clear the lists // so that no assets are actually created. if (!_importMaterials) @@ -654,6 +738,7 @@ string GetUniqueName(string desiredName) m_Materials = materials.ToArray(); m_Textures = textures.ToArray(); + m_HasSceneData = gltfScene; m_HasMaterialData = importer.Root.Materials != null && importer.Root.Materials.Count > 0; m_HasTextureData = importer.Root.Textures != null && importer.Root.Textures.Count > 0; @@ -829,9 +914,35 @@ private void CreateGLTFScene(GLTFImportContext context, out GameObject scene, _extensions = new List(); } + bool isTextureExtractable(TextureCacheData tex) + { + var source = GLTFSceneImporter.GetTextureSource(tex.TextureDefinition); + if (source == null) + return false; + + if (source.Value == null) + return false; + + var uri = source.Value.Uri; + + if (string.IsNullOrEmpty(uri)) + return true; + + if (URIHelper.IsBase64Uri(uri)) + return true; + + return false; + } + _textures = loader.TextureCache .Where(x => x != null) - .Select(x => new TextureInfo() { texture = x.Texture, shouldBeLinear = x.IsLinear }) + .Select(x => new TextureInfo() + { + texture = x.Texture, + shouldBeLinear = x.IsLinear, + imageIndex = GLTFSceneImporter.GetTextureSourceId(x.TextureDefinition), + isExtractable = isTextureExtractable(x) + }) .ToList(); scene = loader.LastLoadedScene; diff --git a/Editor/Scripts/GLTFImporterInspector.cs b/Editor/Scripts/GLTFImporterInspector.cs index f047fc985..dd5e3d887 100644 --- a/Editor/Scripts/GLTFImporterInspector.cs +++ b/Editor/Scripts/GLTFImporterInspector.cs @@ -215,7 +215,7 @@ private void RemappingUI(GLTFImporter t, SerializedProperty importedData, str // TODO this also counts old remaps that are not used anymore var remapCount = externalObjectMap.Values.Count(x => x is T); - void ExtractAsset(T subAsset, bool importImmediately) + void ExtractAsset(T subAsset, bool importImmediately, int index = -1) { if (!subAsset) return; var filename = SanitizePath(subAsset.name); @@ -225,11 +225,27 @@ void ExtractAsset(T subAsset, bool importImmediately) var destinationPath = dirName + "/" + filename + fileExtension; var assetPath = AssetDatabase.GetAssetPath(subAsset); - var clone = Instantiate(subAsset); - AssetDatabase.CreateAsset(clone, destinationPath); + if (subAsset is Texture) + { + var newFile = t.ExtractTexture(t.Textures[index], dirName); - var assetImporter = AssetImporter.GetAtPath(assetPath); - assetImporter.AddRemap(new AssetImporter.SourceAssetIdentifier(subAsset), clone); + if (string.IsNullOrEmpty(newFile)) + return; + + AssetDatabase.ImportAsset(newFile, ImportAssetOptions.ForceUpdate); + var newImage = AssetDatabase.LoadAssetAtPath(newFile); + //newImage.name = Path.GetFileNameWithoutExtension(newFile); + var assetImporter = AssetImporter.GetAtPath(assetPath); + AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); + assetImporter.AddRemap(new AssetImporter.SourceAssetIdentifier(subAsset), newImage); + } + else + { + var clone = Instantiate(subAsset); + AssetDatabase.CreateAsset(clone, destinationPath); + var assetImporter = AssetImporter.GetAtPath(assetPath); + assetImporter.AddRemap(new AssetImporter.SourceAssetIdentifier(subAsset), clone); + } if (importImmediately) { @@ -243,53 +259,61 @@ void ExtractAsset(T subAsset, bool importImmediately) SessionState.SetBool(remapFoldoutKey, remapFoldout); if (remapFoldout) { - if (remapCount > 0) - { - EditorGUILayout.BeginHorizontal(); + EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Restore all " + subDirectoryName)) + if (remapCount > 0 && GUILayout.Button("Restore all " + subDirectoryName)) + { + for (var i = 0; i < importedData.arraySize; i++) { - for (var i = 0; i < importedData.arraySize; i++) - { - var mat = importedData.GetArrayElementAtIndex(i).objectReferenceValue as T; - if (!mat) continue; - t.RemoveRemap(new AssetImporter.SourceAssetIdentifier(mat)); - } + var mat = importedData.GetArrayElementAtIndex(i).objectReferenceValue as T; + if (!mat) continue; + t.RemoveRemap(new AssetImporter.SourceAssetIdentifier(mat)); + } - // also remove all old remaps - var oldRemaps = externalObjectMap.Where(x => x.Value is T).ToList(); - foreach (var oldRemap in oldRemaps) - { - t.RemoveRemap(oldRemap.Key); - } + // also remove all old remaps + var oldRemaps = externalObjectMap.Where(x => x.Value is T).ToList(); + foreach (var oldRemap in oldRemaps) + { + t.RemoveRemap(oldRemap.Key); } + } - if (typeof(T) == typeof(Material) && GUILayout.Button("Extract all " + subDirectoryName)) + if (typeof(T) == typeof(Material) && GUILayout.Button("Extract all " + subDirectoryName)) + { + var materials = new T[importedData.arraySize]; + for (var i = 0; i < importedData.arraySize; i++) + materials[i] = importedData.GetArrayElementAtIndex(i).objectReferenceValue as T; + + for (var i = 0; i < materials.Length; i++) { - var materials = new T[importedData.arraySize]; - for (var i = 0; i < importedData.arraySize; i++) - materials[i] = importedData.GetArrayElementAtIndex(i).objectReferenceValue as T; + if (!materials[i]) continue; - for (var i = 0; i < materials.Length; i++) - { - if (!materials[i]) continue; - AssetDatabase.StartAssetEditing(); - ExtractAsset(materials[i], false); - AssetDatabase.StopAssetEditing(); - var assetPath = AssetDatabase.GetAssetPath(target); - AssetDatabase.WriteImportSettingsIfDirty(assetPath); - AssetDatabase.Refresh(); - } - } + bool canExtracted = materials[i] is Material || (materials[i] is Texture && t.Textures[i].isExtractable); + if (!canExtracted) continue; - EditorGUILayout.EndHorizontal(); + AssetDatabase.StartAssetEditing(); + ExtractAsset(materials[i], false); + AssetDatabase.StopAssetEditing(); + var assetPath = AssetDatabase.GetAssetPath(target); + AssetDatabase.WriteImportSettingsIfDirty(assetPath); + AssetDatabase.Refresh(); + } } + EditorGUILayout.EndHorizontal(); + + for (var i = 0; i < importedData.arraySize; i++) { var mat = importedData.GetArrayElementAtIndex(i).objectReferenceValue as T; if (!mat) continue; - var id = new AssetImporter.SourceAssetIdentifier(mat); + + AssetImporter.SourceAssetIdentifier id; + if (mat is Texture2D && i < t.m_OrgTexturesNames.Length) + id = new AssetImporter.SourceAssetIdentifier(typeof(Texture2D), t.m_OrgTexturesNames[i]); + else + id = new AssetImporter.SourceAssetIdentifier(mat); + externalObjectMap.TryGetValue(id, out var remap); EditorGUILayout.BeginHorizontal(); // EditorGUILayout.ObjectField(/*mat.name,*/ mat, typeof(Material), false); @@ -303,25 +327,29 @@ void ExtractAsset(T subAsset, bool importImmediately) t.RemoveRemap(id); } - if (!remap) + bool canExtracted = mat is Material || (mat is Texture && t.Textures[i].isExtractable); + if (canExtracted) { - if (GUILayout.Button("Extract", GUILayout.Width(60))) + if (!remap) { - ExtractAsset(mat, true); - GUIUtility.ExitGUI(); + if (GUILayout.Button("Extract", GUILayout.Width(60))) + { + ExtractAsset(mat, true, i); + GUIUtility.ExitGUI(); + } } - } - else - { - if (GUILayout.Button("Restore", GUILayout.Width(60))) + else { - t.RemoveRemap(id); + if (GUILayout.Button("Restore", GUILayout.Width(60))) + { + t.RemoveRemap(id); #if UNITY_2022_2_OR_NEWER - SaveChanges(); + SaveChanges(); #else - ApplyAndImport(); + ApplyAndImport(); #endif - GUIUtility.ExitGUI(); + GUIUtility.ExitGUI(); + } } } diff --git a/Editor/Scripts/ShaderGraph/MaterialEditorBridge.cs b/Editor/Scripts/ShaderGraph/MaterialEditorBridge.cs index e3d093cd5..54afabade 100644 --- a/Editor/Scripts/ShaderGraph/MaterialEditorBridge.cs +++ b/Editor/Scripts/ShaderGraph/MaterialEditorBridge.cs @@ -23,11 +23,22 @@ private static void OnImmutableMaterialChanged(Material material) // var mainAsset = AssetDatabase.LoadMainAssetAtPath(assetPath); // Transform[] rootTransforms = null; - var exporter = new GLTFSceneExporter((Transform[]) null, new ExportOptions()); + var glftSettingsCopy = ScriptableObject.Instantiate(GLTFSettings.GetOrCreateSettings()); + glftSettingsCopy.ExportFullPath = true; + glftSettingsCopy.TryExportTexturesFromDisk = true; + var exportSettings = new ExportOptions(glftSettingsCopy); + exportSettings.TexturePathRetriever += texture => + { + return AssetDatabase.GetAssetPath(texture); + }; + var exporter = new GLTFSceneExporter((Transform[]) null, exportSettings); // load all materials from mainAsset var importer = AssetImporter.GetAtPath(assetPath) as GLTFImporter; if (!importer) return; + var path = Path.GetDirectoryName(assetPath); + var name = Path.GetFileName(assetPath); + // var allObjects = AssetDatabase.LoadAllAssetsAtPath(assetPath); foreach (var obj in importer.m_Materials) { @@ -36,46 +47,35 @@ private static void OnImmutableMaterialChanged(Material material) // TODO warn that there are extra objects we can't store right now continue; } - exporter.ExportMaterial(mat); } - var path = Path.GetDirectoryName(assetPath); - var name = Path.GetFileName(assetPath); + var images = exporter.GetRoot().Images; + foreach (var image in images) + if (!string.IsNullOrEmpty(image.Uri)) + image.Uri = Path.GetRelativePath( path, image.Uri); // Save file and make sure we reimport it exporter.SaveGLTFandBin(path, name, false); - AssetDatabase.ImportAsset(path); + ScriptableObject.DestroyImmediate(glftSettingsCopy); + AssetDatabase.ImportAsset(assetPath); + + importer = AssetImporter.GetAtPath(assetPath) as GLTFImporter; + if (!importer) return; + // add texture remaps, so that the textures we just exported with stay valid. // We want to always have default paths in the file, and remapping is done on the Unity side to a project specific path, // to avoid breaking references all the time when paths change. var exportedTextures = exporter.GetRoot().Textures; - var importedTextures = importer.m_Textures; - // If these don't match, we could only try by name... not ideal. - // They may not match due to different sampler settings etc. - if (exportedTextures.Count == importedTextures.Length) - { - for (int i = 0; i < exportedTextures.Count; i++) - { - var exported = exportedTextures[i]; - var imported = importedTextures[i]; - // TODO could we also use the imported texture definitions instead of the actual imported textures? - // Then we wouldn't need to create mock textures on import for all missing/remapped ones. - if (exported.Name != imported.name) - { - Debug.LogWarning($"Texture name mismatch: {exported.Name} != {imported.name}"); - } - var sourceTextureForExportedTexture = exporter.GetSourceTextureForExportedTexture(exported); - - // we should not remap if that is actually the same texture - if (imported == sourceTextureForExportedTexture) continue; - - importer.AddRemap(new AssetImporter.SourceAssetIdentifier(imported), sourceTextureForExportedTexture); - } - importer.SaveAndReimport(); + for (int i = 0; i < exportedTextures.Count; i++) + { + var exported = exportedTextures[i]; + var sourceTextureForExportedTexture = exporter.GetSourceTextureForExportedTexture(exported); + importer.AddRemap(new AssetImporter.SourceAssetIdentifier(typeof(Texture2D), exported.Name), sourceTextureForExportedTexture); } + importer.SaveAndReimport(); // TODO we should get rid of this, but without it currently the inspector doesn't repaint // after importing a changed material, which can be confusing. Could be caching inside PBRGraphGUI diff --git a/Runtime/Scripts/Cache/AssetCache.cs b/Runtime/Scripts/Cache/AssetCache.cs index d00884bf2..cadb6ab18 100644 --- a/Runtime/Scripts/Cache/AssetCache.cs +++ b/Runtime/Scripts/Cache/AssetCache.cs @@ -2,6 +2,7 @@ using UnityEngine; using System.IO; using GLTF.Schema; +using UnityEditor; namespace UnityGLTF.Cache { @@ -20,6 +21,14 @@ public class AssetCache : IDisposable /// public Texture2D[] ImageCache { get; private set; } +#if UNITY_EDITOR + /// + /// Loaded texture asset ids + /// + public AssetImporter.SourceAssetIdentifier[] ImageSourceAssetId { get; private set; } + public AssetImporter.SourceAssetIdentifier[] TextureAssetId { get; private set; } +#endif + /// /// Invalid/missing textures. These are cached since we can still remap them after import, but don't /// want to apply them to materials. @@ -65,6 +74,11 @@ public class AssetCache : IDisposable public AssetCache(GLTFRoot root) { ImageCache = new Texture2D[root.Images?.Count ?? 0]; +#if UNITY_EDITOR + ImageSourceAssetId = new AssetImporter.SourceAssetIdentifier[root.Images?.Count ?? 0]; + TextureAssetId = new AssetImporter.SourceAssetIdentifier[root.Textures?.Count ?? 0]; +#endif + InvalidImageCache = new Texture2D[ImageCache.Length]; ImageStreamCache = new Stream[ImageCache.Length]; TextureCache = new TextureCacheData[root.Textures?.Count ?? 0]; diff --git a/Runtime/Scripts/GLTFSceneImporter.cs b/Runtime/Scripts/GLTFSceneImporter.cs index afca30874..e159b15c2 100644 --- a/Runtime/Scripts/GLTFSceneImporter.cs +++ b/Runtime/Scripts/GLTFSceneImporter.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; @@ -22,6 +21,9 @@ using ThreadPriority = System.Threading.ThreadPriority; #endif using WrapMode = UnityEngine.WrapMode; +#if UNITY_EDITOR +using UnityEditor; +#endif namespace UnityGLTF { @@ -214,6 +216,9 @@ public GameObject LastLoadedScene get { return _lastLoadedScene; } } +#if UNITY_EDITOR + internal AssetImporter.SourceAssetIdentifier[] TextureSourceAssetId => _assetCache.TextureAssetId; +#endif public TextureCacheData[] TextureCache => _assetCache.TextureCache; public Texture2D[] InvalidImageCache => _assetCache.InvalidImageCache; public MaterialCacheData[] MaterialCache => _assetCache.MaterialCache; @@ -1114,7 +1119,7 @@ private void Cleanup() } } - private async Task SetupLoad(Func callback) + internal async Task SetupLoad(Func callback) { try { diff --git a/Runtime/Scripts/SceneImporter/ImporterTextures.cs b/Runtime/Scripts/SceneImporter/ImporterTextures.cs index 0b94da581..a792aedd3 100644 --- a/Runtime/Scripts/SceneImporter/ImporterTextures.cs +++ b/Runtime/Scripts/SceneImporter/ImporterTextures.cs @@ -132,6 +132,93 @@ protected async Task ConstructImageBuffer(GLTFTexture texture, int textureIndex) } } + internal async Task<(string, byte[])> GetImageFileExtensionAndData(GLTFImage image) + { + (string, byte[]) result = new ("", new byte[0]); + + switch (image.MimeType) + { + case "image/png": + result.Item1 = ".png"; + break; + case "image/jpeg": + result.Item1 = ".jpg"; + break; + case "image/exr": + result.Item1 = ".exr"; + break; + case "image/ktx2": + result.Item1 = ".ktx2"; + break; + } + + int bufferIndex = image.BufferView.Value.Buffer.Id; + await ConstructBuffer(_gltfRoot.Buffers[bufferIndex], bufferIndex); + + Stream stream = null; + if (image.Uri == null) + { + var bufferView = image.BufferView.Value; + var data = new byte[bufferView.ByteLength]; + + BufferCacheData bufferContents = _assetCache.BufferCache[bufferView.Buffer.Id]; + bufferContents.Stream.Position = bufferView.ByteOffset + bufferContents.ChunkOffset; + stream = new SubStream(bufferContents.Stream, 0, data.Length); + } + else + { + string uri = image.Uri; + + byte[] bufferData; + URIHelper.TryParseBase64(uri, out bufferData); + if (bufferData != null) + { + stream = new MemoryStream(bufferData, 0, bufferData.Length, false, true); + } + else + { + result.Item2 = bufferData; + return result; + } + } + +#if UNITY_EDITOR + if (stream is AssetDatabaseStream) + { + // Is Asset File, abort here + return result; + } +#endif + if (stream is FileLoader.InvalidStream invalidStream) + { + // Abort here + return result; + } + + if (stream is MemoryStream) + { + using (MemoryStream memoryStream = stream as MemoryStream) + { + result.Item2 = memoryStream.ToArray(); + } + } + else + { + byte[] buffer = new byte[stream.Length]; + + // todo: potential optimization is to split stream read into multiple frames (or put it on a thread?) + if (stream.Length > int.MaxValue) + { + throw new Exception("Stream is larger than can be copied into byte array"); + } + stream.Read(buffer, 0, (int)stream.Length); + result.Item2 = buffer; + } + + return result; + } + + // With using KTX, we need to return a new Texture2D instance at the moment. Unity KTX package does not support loading into existing one async Task CheckMimeTypeAndLoadImage(GLTFImage image, Texture2D texture, byte[] data, bool markGpuOnly) { @@ -207,12 +294,15 @@ protected virtual async Task ConstructUnityTexture(Stream stream, bool markGpuOn var newTextureObject = texture; #if UNITY_EDITOR + + var sourceIdentifier = new AssetImporter.SourceAssetIdentifier(texture); var haveRemappedTexture = false; + _assetCache.ImageSourceAssetId[imageCacheIndex] = sourceIdentifier; + if (Context.SourceImporter != null) { // check for remapping, we don't even need to attempt loading the texture in that case. var externalObjects = Context.SourceImporter.GetExternalObjectMap(); - var sourceIdentifier = new AssetImporter.SourceAssetIdentifier(texture); externalObjects.TryGetValue(sourceIdentifier, out var o); if (o is Texture2D remappedTexture) { @@ -281,14 +371,19 @@ protected virtual async Task ConstructUnityTexture(Stream stream, bool markGpuOn _assetCache.ImageCache[imageCacheIndex] = texture; } - - protected virtual int GetTextureSourceId(GLTFTexture texture) + internal static ImageId GetTextureSource(GLTFTexture texture) { if (texture.Extensions != null && texture.Extensions.ContainsKey(KHR_texture_basisu.EXTENSION_NAME)) { - return ((KHR_texture_basisu)texture.Extensions[KHR_texture_basisu.EXTENSION_NAME]).source.Id; + return (texture.Extensions[KHR_texture_basisu.EXTENSION_NAME] as KHR_texture_basisu).source; } - return texture.Source?.Id ?? 0; + return texture.Source; + } + + internal static int GetTextureSourceId(GLTFTexture texture) + { + var source = GetTextureSource(texture); + return source?.Id ?? 0; } protected virtual bool IsTextureFlipped(GLTFTexture texture) @@ -336,7 +431,6 @@ public virtual async Task LoadTextureAsync(GLTFTexture texture, int textureIndex { _assetCache = new AssetCache(_gltfRoot); } - await ConstructImageBuffer(texture, textureIndex); await ConstructTexture(texture, textureIndex, markGpuOnly, isLinear); } @@ -487,6 +581,8 @@ TextureWrapMode UnityWrapMode(GLTF.Schema.WrapMode gltfWrapMode) Debug.Log(LogType.Warning, ($"Sampler state doesn't match but source texture is non-readable. Results might not be correct if textures are used multiple times with different sampler states. {source.filterMode} == {desiredFilterMode} && {source.wrapModeU} == {desiredWrapModeS} && {source.wrapModeV} == {desiredWrapModeT}")); _assetCache.TextureCache[textureIndex].Texture = source; } + + _assetCache.TextureAssetId[textureIndex] = _assetCache.ImageSourceAssetId[sourceId]; #endif }