From f88e8d728675658495d7b03bea7d37d231f331fe Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Thu, 20 May 2021 18:23:26 +0900 Subject: [PATCH] Refactoring Serializing Textures --- .../Editor/MeshUtility/TextureSaver.cs | 2 +- .../UniGLTF/ExportDialog/GltfExportWindow.cs | 2 +- .../IO/TextureIO/GltfTextureExporter.cs | 10 +-- .../Runtime/UniGLTF/IO/gltfExporter.cs | 23 ++---- Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs | 4 +- Assets/UniGLTF/Tests/UniGLTF/MaterialTests.cs | 4 +- .../TextureColorSpaceSpecificationTests.cs | 2 +- Assets/UniGLTF/Tests/UniGLTF/TextureTests.cs | 2 +- Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs | 8 +- .../Editor/Tests/VRMImportExportTests.cs | 2 +- .../Editor/Tests/VRMMaterialTests.cs | 2 +- .../VRM.Samples/Scripts/VRMRuntimeExporter.cs | 2 +- Assets/VRM/Editor/Format/VRMEditorExporter.cs | 4 +- Assets/VRM/Runtime/IO/VRMExporter.cs | 8 +- Assets/VRM/Tests/MToonTest.cs | 2 +- Assets/VRM/Tests/VRMLoadTests.cs | 2 +- Assets/VRM/Tests/VrmDividedMeshTests.cs | 14 ++-- Assets/VRM10/Editor/Vrm10ExportDialog.cs | 6 +- Assets/VRM10/Runtime/IO/Vrm10Exporter.cs | 29 +++---- Assets/VRM10/Tests/ApiSampleTests.cs | 2 +- ...tureUtil.cs => EditorTextureSerializer.cs} | 79 +++++++++---------- ...s.meta => EditorTextureSerializer.cs.meta} | 0 .../GLTF/IO/Runtime/ITextureSerializer.cs | 22 ++++++ .../IO/Runtime/ITextureSerializer.cs.meta | 3 + .../IO/Runtime/RuntimeTextureSerializer.cs | 58 ++++++++++++++ .../Runtime/RuntimeTextureSerializer.cs.meta | 3 + .../GLTF/IO/Runtime/TextureExporter.cs | 64 +++------------ .../Tests/MetallicRoughnessConverterTests.cs | 7 +- .../GLTF/IO/Tests/TextureBytesTests.cs | 4 +- 29 files changed, 199 insertions(+), 171 deletions(-) rename Assets/VRMShaders/GLTF/IO/Editor/{AssetTextureUtil.cs => EditorTextureSerializer.cs} (81%) rename Assets/VRMShaders/GLTF/IO/Editor/{AssetTextureUtil.cs.meta => EditorTextureSerializer.cs.meta} (100%) create mode 100644 Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs create mode 100644 Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs.meta create mode 100644 Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs create mode 100644 Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs.meta diff --git a/Assets/UniGLTF/Editor/MeshUtility/TextureSaver.cs b/Assets/UniGLTF/Editor/MeshUtility/TextureSaver.cs index 02e8b35e9b..90172a28a6 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/TextureSaver.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/TextureSaver.cs @@ -36,7 +36,7 @@ static void SaveAsPng(bool sRGB) return; } - var (tex, mime) = TextureExporter.GetTextureBytesWithMime(texture, sRGB ? ColorSpace.sRGB : ColorSpace.Linear); + var (tex, mime) = new EditorTextureSerializer().ExportBytesWithMime(texture, sRGB ? ColorSpace.sRGB : ColorSpace.Linear); File.WriteAllBytes(path, tex); Debug.Log($"save: {path}"); diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs index 7da38e10a0..2ad68337ac 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs @@ -125,7 +125,7 @@ protected override void ExportPath(string path) UseSparseAccessorForMorphTarget = m_settings.Sparse, DivideVertexBuffer = m_settings.DivideVertexBuffer, }; - exporter.Export(settings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); + exporter.Export(settings, new EditorTextureSerializer()); } if (isGlb) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureExporter.cs index c80a0fd678..3f3cbc6377 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureExporter.cs @@ -8,22 +8,22 @@ public static class GltfTextureExporter { /// /// gltf に texture を足す - /// + /// /// * textures /// * samplers /// * images /// * bufferViews - /// + /// /// を更新し、textures の index を返す - /// + /// /// /// /// /// /// gltf texture index - public static int PushGltfTexture(this glTF gltf, int bufferIndex, Texture2D texture, ColorSpace textureColorSpace, gltfExporter.GetBytesWithMimeFromTexture2D getTextureBytes) + public static int PushGltfTexture(this glTF gltf, int bufferIndex, Texture2D texture, ColorSpace textureColorSpace, ITextureSerializer textureSerializer) { - var bytesWithMime = getTextureBytes(texture, textureColorSpace); + var bytesWithMime = textureSerializer.ExportBytesWithMime(texture, textureColorSpace); // add view var view = gltf.buffers[bufferIndex].Append(bytesWithMime.bytes, glBufferTarget.NONE); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index b109dd1408..2bb0df5c39 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -21,7 +21,7 @@ public GameObject Copy /// /// Mesh毎に、元のBlendShapeIndex => ExportされたBlendShapeIndex の対応を記録する - /// + /// /// BlendShape が空の場合にスキップするので /// /// @@ -148,7 +148,7 @@ static glTFNode ExportNode(Transform x, List nodes, List(); - + if (meshRenderer != null) { var meshFilter = x.GetComponent(); @@ -214,21 +214,12 @@ private static bool TryGetSameMeshIndex(List meshWithRenderers return false; } - public virtual void ExportExtensions(GetBytesWithMimeFromTexture2D getTextureBytes) + public virtual void ExportExtensions(ITextureSerializer textureSerializer) { // do nothing } - /// - /// Texture2D から実際のバイト列を取得するデリゲート。 - /// - /// textureColorSpace は Texture2D をコピーする際に用いる。 - /// Texture2D 単体では、色空間を知ることができないため。 - /// 一般には、その Texture2D がアサインされる glTF のプロパティの仕様が定める色空間と一致する。 - /// - public delegate (byte[] bytes, string mime) GetBytesWithMimeFromTexture2D(Texture2D texture, ColorSpace textureColorSpace); - - public virtual void Export(MeshExportSettings meshExportSettings, Func useAsset, GetBytesWithMimeFromTexture2D getTextureBytes) + public virtual void Export(MeshExportSettings meshExportSettings, ITextureSerializer textureSerializer) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = glTF.AddBuffer(bytesBuffer); @@ -247,7 +238,7 @@ public virtual void Export(MeshExportSettings meshExportSettings, Func x.Renderer.sharedMaterials).Where(x => x != null).Distinct().ToList(); - TextureManager = new TextureExporter(useAsset); + TextureManager = new TextureExporter(textureSerializer); var materialExporter = CreateMaterialExporter(); glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList(); @@ -366,13 +357,13 @@ public virtual void Export(MeshExportSettings meshExportSettings, Func(resourceName); var exporter = new VRMMaterialExporter(); - var textureManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); + var textureManager = new TextureExporter(new EditorTextureSerializer()); var exported = exporter.ExportMaterial(material, textureManager); // parse glTFExtensionExport to glTFExtensionImport diff --git a/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs b/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs index f0056b16f5..431ab54596 100644 --- a/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs +++ b/Assets/VRM.Samples/Scripts/VRMRuntimeExporter.cs @@ -96,7 +96,7 @@ void OnExportClicked() return; } - var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, m_model, (Texture _) => false, TextureExporter.GetTextureBytesWithMime); + var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, m_model, new RuntimeTextureSerializer()); var bytes = vrm.ToGlbBytes(); File.WriteAllBytes(path, bytes); Debug.LogFormat("export to {0}", path); diff --git a/Assets/VRM/Editor/Format/VRMEditorExporter.cs b/Assets/VRM/Editor/Format/VRMEditorExporter.cs index 3c765525c5..b8c3e27e6d 100644 --- a/Assets/VRM/Editor/Format/VRMEditorExporter.cs +++ b/Assets/VRM/Editor/Format/VRMEditorExporter.cs @@ -130,7 +130,7 @@ static void ForceUniqueName(Transform transform, Dictionary nameCou } /// - /// + /// /// /// /// @@ -225,7 +225,7 @@ static byte[] Export(GameObject exportRoot, VRMMetaObject meta, using (var exporter = new VRMExporter(gltf)) { exporter.Prepare(target); - exporter.Export(settings.MeshExportSettings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); + exporter.Export(settings.MeshExportSettings, new EditorTextureSerializer()); } var bytes = gltf.ToGlbBytes(); Debug.LogFormat("Export elapsed {0}", sw.Elapsed); diff --git a/Assets/VRM/Runtime/IO/VRMExporter.cs b/Assets/VRM/Runtime/IO/VRMExporter.cs index 87b02bccef..6eb45654f9 100644 --- a/Assets/VRM/Runtime/IO/VRMExporter.cs +++ b/Assets/VRM/Runtime/IO/VRMExporter.cs @@ -15,13 +15,13 @@ protected override IMaterialExporter CreateMaterialExporter() return new VRMMaterialExporter(); } - public static glTF Export(MeshExportSettings configuration, GameObject go, Func useAsset, GetBytesWithMimeFromTexture2D getTextureBytes) + public static glTF Export(MeshExportSettings configuration, GameObject go, ITextureSerializer textureSerializer) { var gltf = new glTF(); using (var exporter = new VRMExporter(gltf)) { exporter.Prepare(go); - exporter.Export(configuration, useAsset, getTextureBytes); + exporter.Export(configuration, textureSerializer); } return gltf; } @@ -33,7 +33,7 @@ public VRMExporter(glTF gltf) : base(gltf, Axises.Z) gltf.extensionsUsed.Add(glTF_VRM_extensions.ExtensionName); } - public override void ExportExtensions(GetBytesWithMimeFromTexture2D getTextureBytes) + public override void ExportExtensions(ITextureSerializer textureSerializer) { // avatar var animator = Copy.GetComponent(); @@ -111,7 +111,7 @@ public override void ExportExtensions(GetBytesWithMimeFromTexture2D getTextureBy VRM.meta.title = meta.Title; if (meta.Thumbnail != null) { - VRM.meta.texture = glTF.PushGltfTexture(glTF.buffers.Count - 1, meta.Thumbnail, ColorSpace.sRGB, getTextureBytes); + VRM.meta.texture = glTF.PushGltfTexture(glTF.buffers.Count - 1, meta.Thumbnail, ColorSpace.sRGB, textureSerializer); } VRM.meta.licenseType = meta.LicenseType; diff --git a/Assets/VRM/Tests/MToonTest.cs b/Assets/VRM/Tests/MToonTest.cs index 4ad1a574f9..73686c489c 100644 --- a/Assets/VRM/Tests/MToonTest.cs +++ b/Assets/VRM/Tests/MToonTest.cs @@ -18,7 +18,7 @@ public void TextureTransformTest() filterMode = FilterMode.Bilinear, }; - var textureManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset); + var textureManager = new TextureExporter(new EditorTextureSerializer()); var srcMaterial = new Material(Shader.Find("VRM/MToon")); var offset = new Vector2(0.3f, 0.2f); diff --git a/Assets/VRM/Tests/VRMLoadTests.cs b/Assets/VRM/Tests/VRMLoadTests.cs index 3399073962..5090016809 100644 --- a/Assets/VRM/Tests/VRMLoadTests.cs +++ b/Assets/VRM/Tests/VRMLoadTests.cs @@ -106,7 +106,7 @@ public void VrmTestModelsTests() try { // export - var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, go, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); + var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, go, new EditorTextureSerializer()); // re import if (vrm != null) diff --git a/Assets/VRM/Tests/VrmDividedMeshTests.cs b/Assets/VRM/Tests/VrmDividedMeshTests.cs index aa7eb86a4a..f1bdc46af9 100644 --- a/Assets/VRM/Tests/VrmDividedMeshTests.cs +++ b/Assets/VRM/Tests/VrmDividedMeshTests.cs @@ -49,12 +49,12 @@ static IEnumerable GetMeshes(GameObject gameObject) /// /// positions: [ - /// {1, 1, 0} - /// {1, 1, 1} - /// {1, 1, 2} - /// {1, 1, 3} - /// {1, 1, 4} - /// {1, 1, 5} + /// {1, 1, 0} + /// {1, 1, 1} + /// {1, 1, 2} + /// {1, 1, 3} + /// {1, 1, 4} + /// {1, 1, 5} /// ] /// submesh /// 0 1 2 @@ -73,7 +73,7 @@ public void ExportDividedMeshTest() ExportOnlyBlendShapePosition = true, ExportTangents = false, UseSparseAccessorForMorphTarget = true, - }, loaded, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); + }, loaded, new EditorTextureSerializer()); var bytes = exported.ToGlbBytes(); var divided = Load(bytes, path); diff --git a/Assets/VRM10/Editor/Vrm10ExportDialog.cs b/Assets/VRM10/Editor/Vrm10ExportDialog.cs index 2270d2b610..c5af2a6e9b 100644 --- a/Assets/VRM10/Editor/Vrm10ExportDialog.cs +++ b/Assets/VRM10/Editor/Vrm10ExportDialog.cs @@ -166,7 +166,7 @@ protected override IEnumerable ValidatorFactory() protected override void OnLayout() { - // m_settings, m_meshes.Meshes + // m_settings, m_meshes.Meshes m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings); } @@ -297,9 +297,9 @@ protected override void ExportPath(string path) model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false); // export vrm-1.0 - var exporter = new UniVRM10.Vrm10Exporter(AssetTextureUtil.IsTextureEditorAsset); + var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer()); var option = new VrmLib.ExportArgs(); - exporter.Export(root, model, converter, option, AssetTextureUtil.GetTextureBytesWithMime, Meta ? Meta : m_tmpMeta); + exporter.Export(root, model, converter, option, Meta ? Meta : m_tmpMeta); var exportedBytes = exporter.Storage.ToBytes(); diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index eda93c2f93..5b68808bd2 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -15,10 +15,16 @@ public class Vrm10Exporter : IDisposable public readonly string VrmExtensionName = "VRMC_vrm"; + ITextureSerializer m_textureSerializer; TextureExporter m_textureExporter; - public Vrm10Exporter(Func useAsset) + public Vrm10Exporter(ITextureSerializer textureSerializer) { + if (textureSerializer == null) + { + throw new ArgumentException(nameof(textureSerializer)); + } + Storage.Gltf.extensionsUsed.Add(glTF_KHR_materials_unlit.ExtensionName); Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName); Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName); @@ -30,7 +36,8 @@ public Vrm10Exporter(Func useAsset) }); - m_textureExporter = new TextureExporter(useAsset); + m_textureSerializer = textureSerializer; + m_textureExporter = new TextureExporter(m_textureSerializer); } public void Dispose() @@ -127,7 +134,7 @@ static float[] ReverseX(Vector3 v) return new float[] { -v.x, v.y, v.z }; } - public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, gltfExporter.GetBytesWithMimeFromTexture2D getTextureBytes, VRM10MetaObject metaObject = null) + public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, VRM10MetaObject metaObject = null) { ExportAsset(model); @@ -181,7 +188,7 @@ public void Export(GameObject root, Model model, ModelExporter converter, Export for (int i = 0; i < m_textureExporter.Exported.Count; ++i) { var (unityTexture, texColorSpace) = m_textureExporter.Exported[i]; - Storage.Gltf.PushGltfTexture(0, unityTexture, texColorSpace, getTextureBytes); + Storage.Gltf.PushGltfTexture(0, unityTexture, texColorSpace, m_textureSerializer); } if (thumbnailTextureIndex.HasValue) @@ -631,7 +638,7 @@ void ExportExpression(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10Controller vrm.Meta.CopyrightInformation = meta.CopyrightInformation; vrm.Meta.ContactInformation = meta.ContactInformation; vrm.Meta.References = meta.References.ToList(); - // vrm.Meta.ThirdPartyLicenses = + // vrm.Meta.ThirdPartyLicenses = vrm.Meta.AvatarPermission = meta.AllowedUser; vrm.Meta.AllowExcessivelyViolentUsage = meta.ViolentUsage; vrm.Meta.AllowExcessivelySexualUsage = meta.SexualUsage; @@ -775,14 +782,8 @@ void ExportHumanoid(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Model model) /// /// /// - public static byte[] Export(GameObject go, gltfExporter.GetBytesWithMimeFromTexture2D getTextureBytes = null) + public static byte[] Export(GameObject go, ITextureSerializer textureSerializer = null) { - if (getTextureBytes == null) - { - // default for runtime export - getTextureBytes = TextureExporter.GetTextureBytesWithMime; - } - // ヒエラルキーからジオメトリーを収集 var converter = new UniVRM10.ModelExporter(); var model = converter.Export(go); @@ -791,11 +792,11 @@ public static byte[] Export(GameObject go, gltfExporter.GetBytesWithMimeFromText VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Vrm1); // Model と go から VRM-1.0 にExport - var exporter10 = new Vrm10Exporter(_ => false); + var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer()); var option = new VrmLib.ExportArgs { }; - exporter10.Export(go, model, converter, option, getTextureBytes); + exporter10.Export(go, model, converter, option); return exporter10.Storage.ToBytes(); } } diff --git a/Assets/VRM10/Tests/ApiSampleTests.cs b/Assets/VRM10/Tests/ApiSampleTests.cs index 336d397d6a..4e80f29a39 100644 --- a/Assets/VRM10/Tests/ApiSampleTests.cs +++ b/Assets/VRM10/Tests/ApiSampleTests.cs @@ -48,7 +48,7 @@ public void Sample() Debug.Log(go); // export - var vrmBytes = Vrm10Exporter.Export(go, AssetTextureUtil.GetTextureBytesWithMime); + var vrmBytes = Vrm10Exporter.Export(go, new EditorTextureSerializer()); Debug.Log($"export {vrmBytes.Length} bytes"); } diff --git a/Assets/VRMShaders/GLTF/IO/Editor/AssetTextureUtil.cs b/Assets/VRMShaders/GLTF/IO/Editor/EditorTextureSerializer.cs similarity index 81% rename from Assets/VRMShaders/GLTF/IO/Editor/AssetTextureUtil.cs rename to Assets/VRMShaders/GLTF/IO/Editor/EditorTextureSerializer.cs index b736e0d1cb..f4315ce81a 100644 --- a/Assets/VRMShaders/GLTF/IO/Editor/AssetTextureUtil.cs +++ b/Assets/VRMShaders/GLTF/IO/Editor/EditorTextureSerializer.cs @@ -1,53 +1,25 @@ using System.IO; using System.Reflection; +using UniGLTF; using UnityEditor; using UnityEngine; using ColorSpace = UniGLTF.ColorSpace; namespace VRMShaders { - public static class AssetTextureUtil + public sealed class EditorTextureSerializer : ITextureSerializer { - /// - /// TextureImporter.maxTextureSize が オリジナルの画像Sizeより小さいか - /// - /// - /// - public static bool IsMaxTextureSizeSmallerThanOriginalTextureSize(Texture2D src) - { - var path = AssetDatabase.GetAssetPath(src); - var textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; - - // private メソッド TextureImporter.GetWidthAndHeight を無理やり呼ぶ - var getSizeMethod = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance); - if (textureImporter != null && getSizeMethod != null) - { - var args = new object[2] { 0, 0 }; - getSizeMethod.Invoke(textureImporter, args); - var originalWidth = (int)args[0]; - var originalHeight = (int)args[1]; - var originalSize = Mathf.Max(originalWidth, originalHeight); - if (textureImporter.maxTextureSize < originalSize) - { - return true; - } - } - - return false; - } + private readonly RuntimeTextureSerializer m_runtimeSerializer = new RuntimeTextureSerializer(); /// /// Export するときに オリジナルのテクスチャーアセット(png/jpg)を使用するか否か。 /// 条件は、 - /// + /// /// * TextureAsset が存在する /// * TextureImporter の maxSize - /// + /// /// - /// - /// - /// - public static bool IsTextureEditorAsset(Texture texture) + public bool CanExportAsEditorAssetFile(Texture texture) { if (texture is Texture2D texture2D && !string.IsNullOrEmpty(UnityEditor.AssetDatabase.GetAssetPath(texture2D))) { @@ -70,13 +42,20 @@ public static bool IsTextureEditorAsset(Texture texture) return false; } + public (byte[] bytes, string mime) ExportBytesWithMime(Texture2D texture, ColorSpace textureColorSpace) + { + if (TryGetBytesWithMime(texture, out byte[] bytes, out string mime)) + { + return (bytes, mime); + } + + return m_runtimeSerializer.ExportBytesWithMime(texture, textureColorSpace); + } + /// /// Assetから画像のバイト列を得る /// - /// - /// - /// - public static bool TryGetBytesWithMime(Texture2D texture, out byte[] bytes, out string mime) + private bool TryGetBytesWithMime(Texture2D texture, out byte[] bytes, out string mime) { var path = AssetDatabase.GetAssetOrScenePath(texture); if (string.IsNullOrEmpty(path)) @@ -108,14 +87,30 @@ public static bool TryGetBytesWithMime(Texture2D texture, out byte[] bytes, out return false; } - public static (byte[], string) GetTextureBytesWithMime(Texture2D texture, ColorSpace colorSpace) + /// + /// TextureImporter.maxTextureSize が オリジナルの画像Sizeより小さいか + /// + private bool IsMaxTextureSizeSmallerThanOriginalTextureSize(Texture2D src) { - if (TryGetBytesWithMime(texture, out byte[] bytes, out string mime)) + var path = AssetDatabase.GetAssetPath(src); + var textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; + + // private メソッド TextureImporter.GetWidthAndHeight を無理やり呼ぶ + var getSizeMethod = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance); + if (textureImporter != null && getSizeMethod != null) { - return (bytes, mime); + var args = new object[2] { 0, 0 }; + getSizeMethod.Invoke(textureImporter, args); + var originalWidth = (int)args[0]; + var originalHeight = (int)args[1]; + var originalSize = Mathf.Max(originalWidth, originalHeight); + if (textureImporter.maxTextureSize < originalSize) + { + return true; + } } - return TextureExporter.GetTextureBytesWithMime(texture, colorSpace); + return false; } } } diff --git a/Assets/VRMShaders/GLTF/IO/Editor/AssetTextureUtil.cs.meta b/Assets/VRMShaders/GLTF/IO/Editor/EditorTextureSerializer.cs.meta similarity index 100% rename from Assets/VRMShaders/GLTF/IO/Editor/AssetTextureUtil.cs.meta rename to Assets/VRMShaders/GLTF/IO/Editor/EditorTextureSerializer.cs.meta diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs b/Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs new file mode 100644 index 0000000000..5d748c65d5 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace UniGLTF +{ + public interface ITextureSerializer + { + /// + /// Texture をファイルのバイト列そのまま出力してよいかどうか判断するデリゲート。 + /// + /// Runtime 出力では常に false が望ましい。 + /// + bool CanExportAsEditorAssetFile(Texture texture); + + /// + /// Texture2D から実際のバイト列を取得するデリゲート。 + /// + /// textureColorSpace はその Texture2D がアサインされる glTF プロパティの仕様が定める色空間を指定する。 + /// 具体的には Texture2D をコピーする際に、コピー先の Texture2D の色空間を決定するために使用する。 + /// + (byte[] bytes, string mime) ExportBytesWithMime(Texture2D texture, ColorSpace textureColorSpace); + } +} diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs.meta b/Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs.meta new file mode 100644 index 0000000000..6556309944 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/ITextureSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 949143040e6a4a9d987d405d90107d7c +timeCreated: 1621499560 \ No newline at end of file diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs b/Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs new file mode 100644 index 0000000000..0126c53954 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs @@ -0,0 +1,58 @@ +using System; +using UnityEngine; +using VRMShaders; + +namespace UniGLTF +{ + public sealed class RuntimeTextureSerializer : ITextureSerializer + { + public bool CanExportAsEditorAssetFile(Texture texture) + { + return false; + } + + public (byte[] bytes, string mime) ExportBytesWithMime(Texture2D texture, ColorSpace textureColorSpace) + { + try + { + var png = texture.EncodeToPNG(); + if (png != null) + { + return (png, "image/png"); + } + else + { + // Failed, because texture is compressed. + // ex. ".DDS" file, or Compression is enabled in Texture Import Settings. + return CopyTextureAndGetBytesWithMime(texture, textureColorSpace); + } + } + catch (ArgumentException ex) + { + // System.ArgumentException: not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings. + + // Failed, because texture is not readable. + Debug.LogWarning(ex); + + // 単純に EncodeToPNG できないため、コピーしてから EncodeToPNG する。 + return CopyTextureAndGetBytesWithMime(texture, textureColorSpace); + } + } + + private static (byte[] bytes, string mime) CopyTextureAndGetBytesWithMime(Texture2D texture, ColorSpace colorSpace) + { + var copiedTex = TextureConverter.CopyTexture(texture, colorSpace, null); + var bytes = copiedTex.EncodeToPNG(); + if (Application.isPlaying) + { + UnityEngine.Object.Destroy(copiedTex); + } + else + { + UnityEngine.Object.DestroyImmediate(copiedTex); + } + + return (bytes, "image/png"); + } + } +} diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs.meta b/Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs.meta new file mode 100644 index 0000000000..ec45b3e004 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/RuntimeTextureSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 57623966155c423ba30bf76d64a66760 +timeCreated: 1621500488 \ No newline at end of file diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs b/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs index 566a0aecc5..d52cdd5740 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using UniGLTF; using UnityEngine; using ColorSpace = UniGLTF.ColorSpace; @@ -12,11 +13,11 @@ namespace VRMShaders /// public class TextureExporter : IDisposable { - Func m_useAsset; + private ITextureSerializer m_textureSerializer; - public TextureExporter(Func useAsset) + public TextureExporter(ITextureSerializer textureSerializer) { - m_useAsset = useAsset; + m_textureSerializer = textureSerializer; } public void Dispose() @@ -94,9 +95,9 @@ public int ExportSRGB(Texture src) // get Texture2D index = Exported.Count; var texture2D = src as Texture2D; - if (m_useAsset(texture2D)) + if (m_textureSerializer.CanExportAsEditorAssetFile(texture2D)) { - // do nothing + // do nothing } else { @@ -119,7 +120,7 @@ public int ExportLinear(Texture src) { return -1; } - + var exportKey = new ExportKey(src, ConvertTypes.None); // search cache @@ -130,7 +131,7 @@ public int ExportLinear(Texture src) index = Exported.Count; var texture2d = src as Texture2D; - if (m_useAsset(texture2d)) + if (m_textureSerializer.CanExportAsEditorAssetFile(texture2d)) { // do nothing } @@ -208,7 +209,7 @@ public int ExportNormal(Texture src) // get Texture2D index = Exported.Count; var texture2D = src as Texture2D; - if (m_useAsset(texture2D)) + if (m_textureSerializer.CanExportAsEditorAssetFile(texture2D)) { // EditorAsset を使うので変換不要 } @@ -223,52 +224,5 @@ public int ExportNormal(Texture src) return index; } - - /// - /// 画像のバイト列を得る - /// - public static (byte[] bytes, string mime) GetTextureBytesWithMime(Texture2D texture, ColorSpace colorSpace) - { - try - { - var png = texture.EncodeToPNG(); - if (png != null) - { - return (png, "image/png"); - } - else - { - // Failed, because texture is compressed. - // ex. ".DDS" file, or Compression is enabled in Texture Import Settings. - return CopyTextureAndGetBytesWithMime(texture, colorSpace); - } - } - catch (ArgumentException ex) - { - // System.ArgumentException: not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings. - - // Failed, because texture is not readable. - Debug.LogWarning(ex); - - // 単純に EncodeToPNG できないため、コピーしてから EncodeToPNG する。 - return CopyTextureAndGetBytesWithMime(texture, colorSpace); - } - } - - private static (byte[] bytes, string mime) CopyTextureAndGetBytesWithMime(Texture2D texture, ColorSpace colorSpace) - { - var copiedTex = TextureConverter.CopyTexture(texture, colorSpace, null); - var bytes = copiedTex.EncodeToPNG(); - if (Application.isPlaying) - { - UnityEngine.Object.Destroy(copiedTex); - } - else - { - UnityEngine.Object.DestroyImmediate(copiedTex); - } - - return (bytes, "image/png"); - } } } diff --git a/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs b/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs index a0cca736a7..20164dc63c 100644 --- a/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs +++ b/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs @@ -93,20 +93,21 @@ public void ImportingColorTest() [Test] public void ExportMetallicSmoothnessOcclusion_Test() { + var textureSerializer = new EditorTextureSerializer(); var metallic = new Texture2D(4, 4, TextureFormat.ARGB32, false, true); var occlusion = new Texture2D(4, 4, TextureFormat.ARGB32, false, true); { - var exporter = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); + var exporter = new TextureExporter(new EditorTextureSerializer()); Assert.AreEqual(-1, exporter.ExportMetallicSmoothnessOcclusion(null, 0, null)); } { - var exporter = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); + var exporter = new TextureExporter(new EditorTextureSerializer()); Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion)); Assert.AreEqual(1, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null)); } { - var exporter = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); + var exporter = new TextureExporter(new EditorTextureSerializer()); Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, occlusion)); Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion)); Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null)); diff --git a/Assets/VRMShaders/GLTF/IO/Tests/TextureBytesTests.cs b/Assets/VRMShaders/GLTF/IO/Tests/TextureBytesTests.cs index f425ba3e02..6f51639859 100644 --- a/Assets/VRMShaders/GLTF/IO/Tests/TextureBytesTests.cs +++ b/Assets/VRMShaders/GLTF/IO/Tests/TextureBytesTests.cs @@ -14,7 +14,7 @@ public void NonReadablePng() { var nonReadableTex = AssetDatabase.LoadAssetAtPath($"{AssetPath}/4x4_non_readable.png"); Assert.False(nonReadableTex.isReadable); - var (bytes, mime) = AssetTextureUtil.GetTextureBytesWithMime(nonReadableTex, ColorSpace.sRGB); + var (bytes, mime) = new EditorTextureSerializer().ExportBytesWithMime(nonReadableTex, ColorSpace.sRGB); Assert.NotNull(bytes); } @@ -23,7 +23,7 @@ public void NonReadableDds() { var readonlyTexture = AssetDatabase.LoadAssetAtPath($"{AssetPath}/4x4_non_readable_compressed.dds"); Assert.False(readonlyTexture.isReadable); - var (bytes, mime) = AssetTextureUtil.GetTextureBytesWithMime(readonlyTexture, ColorSpace.sRGB); + var (bytes, mime) = new EditorTextureSerializer().ExportBytesWithMime(readonlyTexture, ColorSpace.sRGB); Assert.NotNull(bytes); } }