Merge pull request #961 from Santarh/refactorTextureSerializer

Refactoring Serializing Textures
This commit is contained in:
ousttrue 2021-05-20 18:35:09 +09:00 committed by GitHub
commit c1930ca040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 199 additions and 171 deletions

View File

@ -36,7 +36,7 @@ namespace MeshUtility
return; 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); File.WriteAllBytes(path, tex);
Debug.Log($"save: {path}"); Debug.Log($"save: {path}");

View File

@ -125,7 +125,7 @@ namespace UniGLTF
UseSparseAccessorForMorphTarget = m_settings.Sparse, UseSparseAccessorForMorphTarget = m_settings.Sparse,
DivideVertexBuffer = m_settings.DivideVertexBuffer, DivideVertexBuffer = m_settings.DivideVertexBuffer,
}; };
exporter.Export(settings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(settings, new EditorTextureSerializer());
} }
if (isGlb) if (isGlb)

View File

@ -8,22 +8,22 @@ namespace UniGLTF
{ {
/// <summary> /// <summary>
/// gltf に texture を足す /// gltf に texture を足す
/// ///
/// * textures /// * textures
/// * samplers /// * samplers
/// * images /// * images
/// * bufferViews /// * bufferViews
/// ///
/// を更新し、textures の index を返す /// を更新し、textures の index を返す
/// ///
/// </summary> /// </summary>
/// <param name="gltf"></param> /// <param name="gltf"></param>
/// <param name="bufferIndex"></param> /// <param name="bufferIndex"></param>
/// <param name="texture"></param> /// <param name="texture"></param>
/// <returns>gltf texture index</returns> /// <returns>gltf texture index</returns>
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 // add view
var view = gltf.buffers[bufferIndex].Append(bytesWithMime.bytes, glBufferTarget.NONE); var view = gltf.buffers[bufferIndex].Append(bytesWithMime.bytes, glBufferTarget.NONE);

View File

@ -21,7 +21,7 @@ namespace UniGLTF
/// <summary> /// <summary>
/// Mesh毎に、元のBlendShapeIndex => ExportされたBlendShapeIndex の対応を記録する /// Mesh毎に、元のBlendShapeIndex => ExportされたBlendShapeIndex の対応を記録する
/// ///
/// BlendShape が空の場合にスキップするので /// BlendShape が空の場合にスキップするので
/// </summary> /// </summary>
/// <value></value> /// <value></value>
@ -148,7 +148,7 @@ namespace UniGLTF
if (x.gameObject.activeInHierarchy) if (x.gameObject.activeInHierarchy)
{ {
var meshRenderer = x.GetComponent<MeshRenderer>(); var meshRenderer = x.GetComponent<MeshRenderer>();
if (meshRenderer != null) if (meshRenderer != null)
{ {
var meshFilter = x.GetComponent<MeshFilter>(); var meshFilter = x.GetComponent<MeshFilter>();
@ -214,21 +214,12 @@ namespace UniGLTF
return false; return false;
} }
public virtual void ExportExtensions(GetBytesWithMimeFromTexture2D getTextureBytes) public virtual void ExportExtensions(ITextureSerializer textureSerializer)
{ {
// do nothing // do nothing
} }
/// <summary> public virtual void Export(MeshExportSettings meshExportSettings, ITextureSerializer textureSerializer)
/// Texture2D から実際のバイト列を取得するデリゲート。
///
/// textureColorSpace は Texture2D をコピーする際に用いる。
/// Texture2D 単体では、色空間を知ることができないため。
/// 一般には、その Texture2D がアサインされる glTF のプロパティの仕様が定める色空間と一致する。
/// </summary>
public delegate (byte[] bytes, string mime) GetBytesWithMimeFromTexture2D(Texture2D texture, ColorSpace textureColorSpace);
public virtual void Export(MeshExportSettings meshExportSettings, Func<Texture, bool> useAsset, GetBytesWithMimeFromTexture2D getTextureBytes)
{ {
var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]);
var bufferIndex = glTF.AddBuffer(bytesBuffer); var bufferIndex = glTF.AddBuffer(bytesBuffer);
@ -247,7 +238,7 @@ namespace UniGLTF
#region Materials and Textures #region Materials and Textures
Materials = uniqueUnityMeshes.SelectMany(x => x.Renderer.sharedMaterials).Where(x => x != null).Distinct().ToList(); Materials = uniqueUnityMeshes.SelectMany(x => x.Renderer.sharedMaterials).Where(x => x != null).Distinct().ToList();
TextureManager = new TextureExporter(useAsset); TextureManager = new TextureExporter(textureSerializer);
var materialExporter = CreateMaterialExporter(); var materialExporter = CreateMaterialExporter();
glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList(); glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList();
@ -366,13 +357,13 @@ namespace UniGLTF
#endregion #endregion
#endif #endif
ExportExtensions(getTextureBytes); ExportExtensions(textureSerializer);
// Extension で Texture が増える場合があるので最後に呼ぶ // Extension で Texture が増える場合があるので最後に呼ぶ
for (int i = 0; i < TextureManager.Exported.Count; ++i) for (int i = 0; i < TextureManager.Exported.Count; ++i)
{ {
var (unityTexture, colorSpace) = TextureManager.Exported[i]; var (unityTexture, colorSpace) = TextureManager.Exported[i];
glTF.PushGltfTexture(bufferIndex, unityTexture, colorSpace, getTextureBytes); glTF.PushGltfTexture(bufferIndex, unityTexture, colorSpace, textureSerializer);
} }
} }
#endregion #endregion

View File

@ -61,7 +61,7 @@ namespace UniGLTF
using (var exporter = new gltfExporter(gltf)) using (var exporter = new gltfExporter(gltf))
{ {
exporter.Prepare(root); exporter.Prepare(root);
exporter.Export(MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(MeshExportSettings.Default, new EditorTextureSerializer());
return gltf.ToGlbBytes(); return gltf.ToGlbBytes();
} }
} }
@ -102,7 +102,7 @@ namespace UniGLTF
if (Skip.Contains(gltf.Directory.Parent.Name)) if (Skip.Contains(gltf.Directory.Parent.Name))
{ {
// Export issue: // Export issue:
// skip // skip
return; return;
} }

View File

@ -18,7 +18,7 @@ namespace UniGLTF
filterMode = FilterMode.Bilinear, filterMode = FilterMode.Bilinear,
}; };
var textureManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); var textureManager = new TextureExporter(new EditorTextureSerializer());
var srcMaterial = new Material(Shader.Find("Standard")); var srcMaterial = new Material(Shader.Find("Standard"));
var offset = new Vector2(0.3f, 0.2f); var offset = new Vector2(0.3f, 0.2f);
@ -242,7 +242,7 @@ namespace UniGLTF
material.SetColor("_EmissionColor", new Color(0, 1, 2, 1)); material.SetColor("_EmissionColor", new Color(0, 1, 2, 1));
material.EnableKeyword("_EMISSION"); material.EnableKeyword("_EMISSION");
var materialExporter = new MaterialExporter(); var materialExporter = new MaterialExporter();
var textureExportManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); var textureExportManager = new TextureExporter(new EditorTextureSerializer());
var gltfMaterial = materialExporter.ExportMaterial(material, textureExportManager); var gltfMaterial = materialExporter.ExportMaterial(material, textureExportManager);
Assert.AreEqual(gltfMaterial.emissiveFactor, new float[] { 0, 0.5f, 1 }); Assert.AreEqual(gltfMaterial.emissiveFactor, new float[] { 0, 0.5f, 1 });

View File

@ -93,7 +93,7 @@ namespace UniGLTF
UseSparseAccessorForMorphTarget = false, UseSparseAccessorForMorphTarget = false,
DivideVertexBuffer = false, DivideVertexBuffer = false,
}; };
exporter.Export(settings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(settings, new EditorTextureSerializer());
} }
Assert.AreEqual(1, gltf.images.Count); Assert.AreEqual(1, gltf.images.Count);
var exportedImage = gltf.images[0]; var exportedImage = gltf.images[0];

View File

@ -18,7 +18,7 @@ namespace UniGLTF
wrapMode = TextureWrapMode.Clamp, wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear, filterMode = FilterMode.Trilinear,
}; };
var textureManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset); var textureManager = new TextureExporter(new EditorTextureSerializer());
var material = new Material(Shader.Find("Standard")); var material = new Material(Shader.Find("Standard"));
material.mainTexture = tex0; material.mainTexture = tex0;

View File

@ -106,7 +106,7 @@ namespace UniGLTF
using (var exporter = new gltfExporter(gltf)) using (var exporter = new gltfExporter(gltf))
{ {
exporter.Prepare(go); exporter.Prepare(go);
exporter.Export(MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(MeshExportSettings.Default, new EditorTextureSerializer());
// remove empty buffer // remove empty buffer
gltf.buffers.Clear(); gltf.buffers.Clear();
@ -298,7 +298,7 @@ namespace UniGLTF
using (var exporter = new gltfExporter(gltf)) using (var exporter = new gltfExporter(gltf))
{ {
exporter.Prepare(CreateSimpleScene()); exporter.Prepare(CreateSimpleScene());
exporter.Export(MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(MeshExportSettings.Default, new EditorTextureSerializer());
} }
var expected = gltf.ToJson().ParseAsJson(); var expected = gltf.ToJson().ParseAsJson();
@ -534,7 +534,7 @@ namespace UniGLTF
using (var exporter = new gltfExporter(gltf)) using (var exporter = new gltfExporter(gltf))
{ {
exporter.Prepare(go); exporter.Prepare(go);
exporter.Export(UniGLTF.MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(UniGLTF.MeshExportSettings.Default, new EditorTextureSerializer());
json = gltf.ToJson(); json = gltf.ToJson();
} }
@ -618,7 +618,7 @@ namespace UniGLTF
using (var exporter = new gltfExporter(gltf)) using (var exporter = new gltfExporter(gltf))
{ {
exporter.Prepare(go); exporter.Prepare(go);
exporter.Export(UniGLTF.MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(UniGLTF.MeshExportSettings.Default, new EditorTextureSerializer());
json = gltf.ToJson(); json = gltf.ToJson();
} }

View File

@ -170,7 +170,7 @@ namespace VRM.Samples
*/ */
importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride")); importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride"));
var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, context.Root, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); var vrm = VRMExporter.Export(UniGLTF.MeshExportSettings.Default, context.Root, new EditorTextureSerializer());
// TODO: Check contents in JSON // TODO: Check contents in JSON
/*var exportJson = */ /*var exportJson = */

View File

@ -11,7 +11,7 @@ namespace VRM.Samples
{ {
var material = Resources.Load<Material>(resourceName); var material = Resources.Load<Material>(resourceName);
var exporter = new VRMMaterialExporter(); var exporter = new VRMMaterialExporter();
var textureManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset ); var textureManager = new TextureExporter(new EditorTextureSerializer());
var exported = exporter.ExportMaterial(material, textureManager); var exported = exporter.ExportMaterial(material, textureManager);
// parse glTFExtensionExport to glTFExtensionImport // parse glTFExtensionExport to glTFExtensionImport

View File

@ -96,7 +96,7 @@ namespace VRM.Samples
return; 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(); var bytes = vrm.ToGlbBytes();
File.WriteAllBytes(path, bytes); File.WriteAllBytes(path, bytes);
Debug.LogFormat("export to {0}", path); Debug.LogFormat("export to {0}", path);

View File

@ -130,7 +130,7 @@ namespace VRM
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="path"></param> /// <param name="path"></param>
/// <param name="settings"></param> /// <param name="settings"></param>
@ -225,7 +225,7 @@ namespace VRM
using (var exporter = new VRMExporter(gltf)) using (var exporter = new VRMExporter(gltf))
{ {
exporter.Prepare(target); exporter.Prepare(target);
exporter.Export(settings.MeshExportSettings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); exporter.Export(settings.MeshExportSettings, new EditorTextureSerializer());
} }
var bytes = gltf.ToGlbBytes(); var bytes = gltf.ToGlbBytes();
Debug.LogFormat("Export elapsed {0}", sw.Elapsed); Debug.LogFormat("Export elapsed {0}", sw.Elapsed);

View File

@ -15,13 +15,13 @@ namespace VRM
return new VRMMaterialExporter(); return new VRMMaterialExporter();
} }
public static glTF Export(MeshExportSettings configuration, GameObject go, Func<Texture, bool> useAsset, GetBytesWithMimeFromTexture2D getTextureBytes) public static glTF Export(MeshExportSettings configuration, GameObject go, ITextureSerializer textureSerializer)
{ {
var gltf = new glTF(); var gltf = new glTF();
using (var exporter = new VRMExporter(gltf)) using (var exporter = new VRMExporter(gltf))
{ {
exporter.Prepare(go); exporter.Prepare(go);
exporter.Export(configuration, useAsset, getTextureBytes); exporter.Export(configuration, textureSerializer);
} }
return gltf; return gltf;
} }
@ -33,7 +33,7 @@ namespace VRM
gltf.extensionsUsed.Add(glTF_VRM_extensions.ExtensionName); gltf.extensionsUsed.Add(glTF_VRM_extensions.ExtensionName);
} }
public override void ExportExtensions(GetBytesWithMimeFromTexture2D getTextureBytes) public override void ExportExtensions(ITextureSerializer textureSerializer)
{ {
// avatar // avatar
var animator = Copy.GetComponent<Animator>(); var animator = Copy.GetComponent<Animator>();
@ -111,7 +111,7 @@ namespace VRM
VRM.meta.title = meta.Title; VRM.meta.title = meta.Title;
if (meta.Thumbnail != null) 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; VRM.meta.licenseType = meta.LicenseType;

View File

@ -18,7 +18,7 @@ namespace VRM
filterMode = FilterMode.Bilinear, filterMode = FilterMode.Bilinear,
}; };
var textureManager = new TextureExporter(AssetTextureUtil.IsTextureEditorAsset); var textureManager = new TextureExporter(new EditorTextureSerializer());
var srcMaterial = new Material(Shader.Find("VRM/MToon")); var srcMaterial = new Material(Shader.Find("VRM/MToon"));
var offset = new Vector2(0.3f, 0.2f); var offset = new Vector2(0.3f, 0.2f);

View File

@ -106,7 +106,7 @@ namespace VRM
try try
{ {
// export // 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 // re import
if (vrm != null) if (vrm != null)

View File

@ -49,12 +49,12 @@ namespace VRM
/// <summary> /// <summary>
/// positions: [ /// positions: [
/// {1, 1, 0} /// {1, 1, 0}
/// {1, 1, 1} /// {1, 1, 1}
/// {1, 1, 2} /// {1, 1, 2}
/// {1, 1, 3} /// {1, 1, 3}
/// {1, 1, 4} /// {1, 1, 4}
/// {1, 1, 5} /// {1, 1, 5}
/// ] /// ]
/// submesh /// submesh
/// 0 1 2 /// 0 1 2
@ -73,7 +73,7 @@ namespace VRM
ExportOnlyBlendShapePosition = true, ExportOnlyBlendShapePosition = true,
ExportTangents = false, ExportTangents = false,
UseSparseAccessorForMorphTarget = true, UseSparseAccessorForMorphTarget = true,
}, loaded, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); }, loaded, new EditorTextureSerializer());
var bytes = exported.ToGlbBytes(); var bytes = exported.ToGlbBytes();
var divided = Load(bytes, path); var divided = Load(bytes, path);

View File

@ -166,7 +166,7 @@ namespace UniVRM10
protected override void OnLayout() protected override void OnLayout()
{ {
// m_settings, m_meshes.Meshes // m_settings, m_meshes.Meshes
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings); m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings);
} }
@ -297,9 +297,9 @@ namespace UniVRM10
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false); model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
// export vrm-1.0 // export vrm-1.0
var exporter = new UniVRM10.Vrm10Exporter(AssetTextureUtil.IsTextureEditorAsset); var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer());
var option = new VrmLib.ExportArgs(); 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(); var exportedBytes = exporter.Storage.ToBytes();

View File

@ -15,10 +15,16 @@ namespace UniVRM10
public readonly string VrmExtensionName = "VRMC_vrm"; public readonly string VrmExtensionName = "VRMC_vrm";
ITextureSerializer m_textureSerializer;
TextureExporter m_textureExporter; TextureExporter m_textureExporter;
public Vrm10Exporter(Func<Texture, bool> 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_materials_unlit.ExtensionName);
Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName); Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName); Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName);
@ -30,7 +36,8 @@ namespace UniVRM10
}); });
m_textureExporter = new TextureExporter(useAsset); m_textureSerializer = textureSerializer;
m_textureExporter = new TextureExporter(m_textureSerializer);
} }
public void Dispose() public void Dispose()
@ -127,7 +134,7 @@ namespace UniVRM10
return new float[] { -v.x, v.y, v.z }; 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); ExportAsset(model);
@ -181,7 +188,7 @@ namespace UniVRM10
for (int i = 0; i < m_textureExporter.Exported.Count; ++i) for (int i = 0; i < m_textureExporter.Exported.Count; ++i)
{ {
var (unityTexture, texColorSpace) = m_textureExporter.Exported[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) if (thumbnailTextureIndex.HasValue)
@ -631,7 +638,7 @@ namespace UniVRM10
vrm.Meta.CopyrightInformation = meta.CopyrightInformation; vrm.Meta.CopyrightInformation = meta.CopyrightInformation;
vrm.Meta.ContactInformation = meta.ContactInformation; vrm.Meta.ContactInformation = meta.ContactInformation;
vrm.Meta.References = meta.References.ToList(); vrm.Meta.References = meta.References.ToList();
// vrm.Meta.ThirdPartyLicenses = // vrm.Meta.ThirdPartyLicenses =
vrm.Meta.AvatarPermission = meta.AllowedUser; vrm.Meta.AvatarPermission = meta.AllowedUser;
vrm.Meta.AllowExcessivelyViolentUsage = meta.ViolentUsage; vrm.Meta.AllowExcessivelyViolentUsage = meta.ViolentUsage;
vrm.Meta.AllowExcessivelySexualUsage = meta.SexualUsage; vrm.Meta.AllowExcessivelySexualUsage = meta.SexualUsage;
@ -775,14 +782,8 @@ namespace UniVRM10
/// <param name="go"></param> /// <param name="go"></param>
/// <param name="getTextureBytes"></param> /// <param name="getTextureBytes"></param>
/// <returns></returns> /// <returns></returns>
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 converter = new UniVRM10.ModelExporter();
var model = converter.Export(go); var model = converter.Export(go);
@ -791,11 +792,11 @@ namespace UniVRM10
VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Vrm1); VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Vrm1);
// Model と go から VRM-1.0 にExport // Model と go から VRM-1.0 にExport
var exporter10 = new Vrm10Exporter(_ => false); var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer());
var option = new VrmLib.ExportArgs var option = new VrmLib.ExportArgs
{ {
}; };
exporter10.Export(go, model, converter, option, getTextureBytes); exporter10.Export(go, model, converter, option);
return exporter10.Storage.ToBytes(); return exporter10.Storage.ToBytes();
} }
} }

View File

@ -48,7 +48,7 @@ namespace UniVRM10.Test
Debug.Log(go); Debug.Log(go);
// export // export
var vrmBytes = Vrm10Exporter.Export(go, AssetTextureUtil.GetTextureBytesWithMime); var vrmBytes = Vrm10Exporter.Export(go, new EditorTextureSerializer());
Debug.Log($"export {vrmBytes.Length} bytes"); Debug.Log($"export {vrmBytes.Length} bytes");
} }

View File

@ -1,53 +1,25 @@
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using UniGLTF;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace; using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders namespace VRMShaders
{ {
public static class AssetTextureUtil public sealed class EditorTextureSerializer : ITextureSerializer
{ {
/// <summary> private readonly RuntimeTextureSerializer m_runtimeSerializer = new RuntimeTextureSerializer();
/// TextureImporter.maxTextureSize が オリジナルの画像Sizeより小さいか
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
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;
}
/// <summary> /// <summary>
/// Export するときに オリジナルのテクスチャーアセット(png/jpg)を使用するか否か。 /// Export するときに オリジナルのテクスチャーアセット(png/jpg)を使用するか否か。
/// 条件は、 /// 条件は、
/// ///
/// * TextureAsset が存在する /// * TextureAsset が存在する
/// * TextureImporter の maxSize /// * TextureImporter の maxSize
/// ///
/// </summary> /// </summary>
/// <param name="src"></param> public bool CanExportAsEditorAssetFile(Texture texture)
/// <param name="texture2D"></param>
/// <returns></returns>
public static bool IsTextureEditorAsset(Texture texture)
{ {
if (texture is Texture2D texture2D && !string.IsNullOrEmpty(UnityEditor.AssetDatabase.GetAssetPath(texture2D))) if (texture is Texture2D texture2D && !string.IsNullOrEmpty(UnityEditor.AssetDatabase.GetAssetPath(texture2D)))
{ {
@ -70,13 +42,20 @@ namespace VRMShaders
return false; 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);
}
/// <summary> /// <summary>
/// Assetから画像のバイト列を得る /// Assetから画像のバイト列を得る
/// </summary> /// </summary>
/// <param name="bytes"></param> private bool TryGetBytesWithMime(Texture2D texture, out byte[] bytes, out string mime)
/// <param name="texture"></param>
/// <returns></returns>
public static bool TryGetBytesWithMime(Texture2D texture, out byte[] bytes, out string mime)
{ {
var path = AssetDatabase.GetAssetOrScenePath(texture); var path = AssetDatabase.GetAssetOrScenePath(texture);
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(path))
@ -108,14 +87,30 @@ namespace VRMShaders
return false; return false;
} }
public static (byte[], string) GetTextureBytesWithMime(Texture2D texture, ColorSpace colorSpace) /// <summary>
/// TextureImporter.maxTextureSize が オリジナルの画像Sizeより小さいか
/// </summary>
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;
} }
} }
} }

View File

@ -0,0 +1,22 @@
using UnityEngine;
namespace UniGLTF
{
public interface ITextureSerializer
{
/// <summary>
/// Texture をファイルのバイト列そのまま出力してよいかどうか判断するデリゲート。
///
/// Runtime 出力では常に false が望ましい。
/// </summary>
bool CanExportAsEditorAssetFile(Texture texture);
/// <summary>
/// Texture2D から実際のバイト列を取得するデリゲート。
///
/// textureColorSpace はその Texture2D がアサインされる glTF プロパティの仕様が定める色空間を指定する。
/// 具体的には Texture2D をコピーする際に、コピー先の Texture2D の色空間を決定するために使用する。
/// </summary>
(byte[] bytes, string mime) ExportBytesWithMime(Texture2D texture, ColorSpace textureColorSpace);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 949143040e6a4a9d987d405d90107d7c
timeCreated: 1621499560

View File

@ -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");
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 57623966155c423ba30bf76d64a66760
timeCreated: 1621500488

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UniGLTF;
using UnityEngine; using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace; using ColorSpace = UniGLTF.ColorSpace;
@ -12,11 +13,11 @@ namespace VRMShaders
/// </summary> /// </summary>
public class TextureExporter : IDisposable public class TextureExporter : IDisposable
{ {
Func<Texture, bool> m_useAsset; private ITextureSerializer m_textureSerializer;
public TextureExporter(Func<Texture, bool> useAsset) public TextureExporter(ITextureSerializer textureSerializer)
{ {
m_useAsset = useAsset; m_textureSerializer = textureSerializer;
} }
public void Dispose() public void Dispose()
@ -94,9 +95,9 @@ namespace VRMShaders
// get Texture2D // get Texture2D
index = Exported.Count; index = Exported.Count;
var texture2D = src as Texture2D; var texture2D = src as Texture2D;
if (m_useAsset(texture2D)) if (m_textureSerializer.CanExportAsEditorAssetFile(texture2D))
{ {
// do nothing // do nothing
} }
else else
{ {
@ -119,7 +120,7 @@ namespace VRMShaders
{ {
return -1; return -1;
} }
var exportKey = new ExportKey(src, ConvertTypes.None); var exportKey = new ExportKey(src, ConvertTypes.None);
// search cache // search cache
@ -130,7 +131,7 @@ namespace VRMShaders
index = Exported.Count; index = Exported.Count;
var texture2d = src as Texture2D; var texture2d = src as Texture2D;
if (m_useAsset(texture2d)) if (m_textureSerializer.CanExportAsEditorAssetFile(texture2d))
{ {
// do nothing // do nothing
} }
@ -208,7 +209,7 @@ namespace VRMShaders
// get Texture2D // get Texture2D
index = Exported.Count; index = Exported.Count;
var texture2D = src as Texture2D; var texture2D = src as Texture2D;
if (m_useAsset(texture2D)) if (m_textureSerializer.CanExportAsEditorAssetFile(texture2D))
{ {
// EditorAsset を使うので変換不要 // EditorAsset を使うので変換不要
} }
@ -223,52 +224,5 @@ namespace VRMShaders
return index; return index;
} }
/// <summary>
/// 画像のバイト列を得る
/// </summary>
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");
}
} }
} }

View File

@ -93,20 +93,21 @@ namespace VRMShaders
[Test] [Test]
public void ExportMetallicSmoothnessOcclusion_Test() public void ExportMetallicSmoothnessOcclusion_Test()
{ {
var textureSerializer = new EditorTextureSerializer();
var metallic = new Texture2D(4, 4, TextureFormat.ARGB32, false, true); var metallic = new Texture2D(4, 4, TextureFormat.ARGB32, false, true);
var occlusion = 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)); 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(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion));
Assert.AreEqual(1, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null)); 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(metallic, 0, occlusion));
Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion)); Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion));
Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null)); Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null));

View File

@ -14,7 +14,7 @@ namespace VRMShaders
{ {
var nonReadableTex = AssetDatabase.LoadAssetAtPath<Texture2D>($"{AssetPath}/4x4_non_readable.png"); var nonReadableTex = AssetDatabase.LoadAssetAtPath<Texture2D>($"{AssetPath}/4x4_non_readable.png");
Assert.False(nonReadableTex.isReadable); Assert.False(nonReadableTex.isReadable);
var (bytes, mime) = AssetTextureUtil.GetTextureBytesWithMime(nonReadableTex, ColorSpace.sRGB); var (bytes, mime) = new EditorTextureSerializer().ExportBytesWithMime(nonReadableTex, ColorSpace.sRGB);
Assert.NotNull(bytes); Assert.NotNull(bytes);
} }
@ -23,7 +23,7 @@ namespace VRMShaders
{ {
var readonlyTexture = AssetDatabase.LoadAssetAtPath<Texture2D>($"{AssetPath}/4x4_non_readable_compressed.dds"); var readonlyTexture = AssetDatabase.LoadAssetAtPath<Texture2D>($"{AssetPath}/4x4_non_readable_compressed.dds");
Assert.False(readonlyTexture.isReadable); Assert.False(readonlyTexture.isReadable);
var (bytes, mime) = AssetTextureUtil.GetTextureBytesWithMime(readonlyTexture, ColorSpace.sRGB); var (bytes, mime) = new EditorTextureSerializer().ExportBytesWithMime(readonlyTexture, ColorSpace.sRGB);
Assert.NotNull(bytes); Assert.NotNull(bytes);
} }
} }