diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs
index 4569d0c59..d4a77b18e 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using System.Text;
+using VRMShaders;
namespace UniGLTF
{
@@ -44,7 +45,7 @@ namespace UniGLTF
IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null)
{
m_parser = parser;
- m_textureFactory = new TextureFactory(GLTF, Storage, externalObjectMap);
+ m_textureFactory = new TextureFactory(externalObjectMap);
m_materialFactory = new MaterialFactory(m_parser, externalObjectMap);
}
@@ -283,7 +284,7 @@ namespace UniGLTF
/// Root ヒエラルキーで使っているリソース
///
///
- public virtual void TransferOwnership(TakeOwnershipFunc take)
+ public virtual void TransferOwnership(Func take)
{
var list = new List();
foreach (var mesh in Meshes)
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs
index 35506de87..5eff6a21c 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs
@@ -56,7 +56,7 @@ namespace UniGLTF
if (m.emissiveTexture != null)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(m.emissiveTexture);
- yield return TextureFactory.CreateSRGB(parser, m.emissiveTexture.index, offset, scale);
+ yield return GltfTextureImporter.CreateSRGB(parser, m.emissiveTexture.index, offset, scale);
}
// normal
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs
index 7e81d1522..322a4f04b 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs
@@ -99,9 +99,15 @@ namespace UniGLTF
///
/// 所有権(Dispose権)を移譲する
+ ///
+ /// 所有権を移動する関数。
+ ///
+ /// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
+ /// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
+ ///
///
///
- public void TransferOwnership(TakeOwnershipFunc take)
+ public void TransferOwnership(Func take)
{
var list = new List();
foreach (var x in m_materials)
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs
index b17721f16..9cb3827f3 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs
@@ -47,7 +47,7 @@ namespace UniGLTF
public static TextureImportParam BaseColorTexture(GltfParser parser, glTFMaterial src)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
- return TextureFactory.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
+ return GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
}
public static TextureImportParam StandardTexture(GltfParser parser, glTFMaterial src)
@@ -60,7 +60,7 @@ namespace UniGLTF
roughnessFactor = src.pbrMetallicRoughness.roughnessFactor;
}
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture);
- return TextureFactory.CreateStandard(parser,
+ return GltfTextureImporter.CreateStandard(parser,
src.pbrMetallicRoughness?.metallicRoughnessTexture?.index,
src.occlusionTexture?.index,
offset, scale,
@@ -71,14 +71,14 @@ namespace UniGLTF
public static TextureImportParam NormalTexture(GltfParser parser, glTFMaterial src)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.normalTexture);
- return TextureFactory.CreateNormal(parser, src.normalTexture.index, offset, scale);
+ return GltfTextureImporter.CreateNormal(parser, src.normalTexture.index, offset, scale);
}
public static async Task CreateAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture)
{
if (getTexture == null)
{
- getTexture = (IAwaitCaller _awaitCaller, glTF _gltf, TextureImportParam _param) => Task.FromResult(null);
+ getTexture = (TextureImportParam _param) => Task.FromResult(null);
}
var material = new Material(Shader.Find(ShaderName));
@@ -106,7 +106,7 @@ namespace UniGLTF
if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1)
{
var param = BaseColorTexture(parser, src);
- material.mainTexture = await getTexture(awaitCaller, parser.GLTF, param);
+ material.mainTexture = await getTexture(param);
// Texture Offset and Scale
MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", param.Offset, param.Scale);
@@ -116,7 +116,7 @@ namespace UniGLTF
{
material.EnableKeyword("_METALLICGLOSSMAP");
- var texture = await getTexture(awaitCaller, parser.GLTF, standardParam);
+ var texture = await getTexture(standardParam);
if (texture != null)
{
material.SetTexture(TextureImportParam.METALLIC_GLOSS_PROP, texture);
@@ -141,7 +141,7 @@ namespace UniGLTF
{
material.EnableKeyword("_NORMALMAP");
var param = NormalTexture(parser, src);
- var texture = await getTexture(awaitCaller, parser.GLTF, param);
+ var texture = await getTexture(param);
if (texture != null)
{
material.SetTexture(TextureImportParam.NORMAL_PROP, texture);
@@ -154,7 +154,7 @@ namespace UniGLTF
if (src.occlusionTexture != null && src.occlusionTexture.index != -1)
{
- var texture = await getTexture(awaitCaller, parser.GLTF, standardParam);
+ var texture = await getTexture(standardParam);
if (texture != null)
{
material.SetTexture(TextureImportParam.OCCLUSION_PROP, texture);
@@ -180,8 +180,8 @@ namespace UniGLTF
if (src.emissiveTexture != null && src.emissiveTexture.index != -1)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.emissiveTexture);
- var param = TextureFactory.CreateSRGB(parser, src.emissiveTexture.index, offset, scale);
- var texture = await getTexture(awaitCaller, parser.GLTF, param);
+ var param = GltfTextureImporter.CreateSRGB(parser, src.emissiveTexture.index, offset, scale);
+ var texture = await getTexture(param);
if (texture != null)
{
material.SetTexture("_EmissionMap", texture);
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs
index 96b4f6d7c..42cb2e67c 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs
@@ -12,7 +12,7 @@ namespace UniGLTF
{
if (getTexture == null)
{
- getTexture = (_x, _y, _z) => Task.FromResult(default);
+ getTexture = (_) => Task.FromResult(default);
}
var src = parser.GLTF.materials[i];
@@ -23,7 +23,7 @@ namespace UniGLTF
if (src.pbrMetallicRoughness.baseColorTexture != null)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
- material.mainTexture = await getTexture(awaitCaller, parser.GLTF, TextureFactory.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale));
+ material.mainTexture = await getTexture(GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale));
// Texture Offset and Scale
MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", offset, scale);
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs
deleted file mode 100644
index 4cb91856c..000000000
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace UniGLTF
-{
- ///
- /// 所有権を移動する関数。
- ///
- /// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
- /// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
- ///
- ///
- /// 対象のオブジェクト
- /// 所有権が移動したらtrue
- public delegate bool TakeOwnershipFunc(UnityEngine.Object o);
-}
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs
new file mode 100644
index 000000000..5f6ee9521
--- /dev/null
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using UnityEngine;
+using VRMShaders;
+
+
+namespace UniGLTF
+{
+ public delegate Task GetTextureAsyncFunc(TextureImportParam param);
+
+ ///
+ /// glTFTexture を TextureImportParam に変換する
+ ///
+ public static class GltfTextureImporter
+ {
+ static Byte[] ToArray(ArraySegment bytes)
+ {
+ if (bytes.Array == null)
+ {
+ return new byte[] { };
+ }
+ else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
+ {
+ return bytes.Array;
+ }
+ else
+ {
+ Byte[] result = new byte[bytes.Count];
+ Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
+ return result;
+ }
+ }
+
+ public static TextureImportParam CreateSRGB(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
+ {
+ var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.sRGB);
+ var sampler = CreateSampler(parser.GLTF, textureIndex);
+ GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
+ return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.sRGB, default, default, getTextureBytesAsync, default, default, default, default, default);
+ }
+
+ public static TextureImportParam CreateNormal(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
+ {
+ var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.NormalMap);
+ var sampler = CreateSampler(parser.GLTF, textureIndex);
+ GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
+ return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.NormalMap, default, default, getTextureBytesAsync, default, default, default, default, default);
+ }
+
+ public static TextureImportParam CreateStandard(GltfParser parser, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor)
+ {
+ TextureImportName name = default;
+
+ GetTextureBytesAsync getMetallicRoughnessAsync = default;
+ SamplerParam sampler = default;
+ if (metallicRoughnessTextureIndex.HasValue)
+ {
+ name = CreateNameExt(parser.GLTF, metallicRoughnessTextureIndex.Value, TextureImportTypes.StandardMap);
+ sampler = CreateSampler(parser.GLTF, metallicRoughnessTextureIndex.Value);
+ getMetallicRoughnessAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, metallicRoughnessTextureIndex.Value)));
+ }
+
+ GetTextureBytesAsync getOcclusionAsync = default;
+ if (occlusionTextureIndex.HasValue)
+ {
+ if (string.IsNullOrEmpty(name.GltfName))
+ {
+ name = CreateNameExt(parser.GLTF, occlusionTextureIndex.Value, TextureImportTypes.StandardMap);
+ }
+ sampler = CreateSampler(parser.GLTF, occlusionTextureIndex.Value);
+ getOcclusionAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, occlusionTextureIndex.Value)));
+ }
+
+ return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.StandardMap, metallicFactor, roughnessFactor, getMetallicRoughnessAsync, getOcclusionAsync, default, default, default, default);
+ }
+
+ public static TextureImportName CreateNameExt(glTF gltf, int textureIndex, TextureImportTypes textureType)
+ {
+ if (textureIndex < 0 || textureIndex >= gltf.textures.Count)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ var gltfTexture = gltf.textures[textureIndex];
+ if (gltfTexture.source < 0 || gltfTexture.source >= gltf.images.Count)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ var gltfImage = gltf.images[gltfTexture.source];
+ return new TextureImportName(textureType, gltfTexture.name, gltfImage.GetExt(), gltfImage.uri);
+ }
+
+ public static SamplerParam CreateSampler(glTF gltf, int index)
+ {
+ var gltfTexture = gltf.textures[index];
+ if (gltfTexture.sampler < 0 || gltfTexture.sampler >= gltf.samplers.Count)
+ {
+ // default
+ return new SamplerParam
+ {
+ FilterMode = FilterMode.Bilinear,
+ WrapModes = new (SamplerWrapType, TextureWrapMode)[] { },
+ };
+ }
+
+ var gltfSampler = gltf.samplers[gltfTexture.sampler];
+ return new SamplerParam
+ {
+ WrapModes = GetUnityWrapMode(gltfSampler).ToArray(),
+ FilterMode = ImportFilterMode(gltfSampler.minFilter),
+ };
+ }
+
+ public static IEnumerable<(SamplerWrapType, TextureWrapMode)> GetUnityWrapMode(glTFTextureSampler sampler)
+ {
+ if (sampler.wrapS == sampler.wrapT)
+ {
+ switch (sampler.wrapS)
+ {
+ case glWrap.NONE: // default
+ yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
+ break;
+
+ case glWrap.CLAMP_TO_EDGE:
+ yield return (SamplerWrapType.All, TextureWrapMode.Clamp);
+ break;
+
+ case glWrap.REPEAT:
+ yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
+ break;
+
+ case glWrap.MIRRORED_REPEAT:
+ yield return (SamplerWrapType.All, TextureWrapMode.Mirror);
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ else
+ {
+ switch (sampler.wrapS)
+ {
+ case glWrap.NONE: // default
+ yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
+ break;
+
+ case glWrap.CLAMP_TO_EDGE:
+ yield return (SamplerWrapType.U, TextureWrapMode.Clamp);
+ break;
+
+ case glWrap.REPEAT:
+ yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
+ break;
+
+ case glWrap.MIRRORED_REPEAT:
+ yield return (SamplerWrapType.U, TextureWrapMode.Mirror);
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ switch (sampler.wrapT)
+ {
+ case glWrap.NONE: // default
+ yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
+ break;
+
+ case glWrap.CLAMP_TO_EDGE:
+ yield return (SamplerWrapType.V, TextureWrapMode.Clamp);
+ break;
+
+ case glWrap.REPEAT:
+ yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
+ break;
+
+ case glWrap.MIRRORED_REPEAT:
+ yield return (SamplerWrapType.V, TextureWrapMode.Mirror);
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+
+ public static FilterMode ImportFilterMode(glFilter filterMode)
+ {
+ switch (filterMode)
+ {
+ case glFilter.NEAREST:
+ case glFilter.NEAREST_MIPMAP_LINEAR:
+ case glFilter.NEAREST_MIPMAP_NEAREST:
+ return FilterMode.Point;
+
+ case glFilter.NONE:
+ case glFilter.LINEAR:
+ case glFilter.LINEAR_MIPMAP_NEAREST:
+ return FilterMode.Bilinear;
+
+ case glFilter.LINEAR_MIPMAP_LINEAR:
+ return FilterMode.Trilinear;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/VRM/Runtime/IO/VRMTextureParam.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs.meta
similarity index 83%
rename from Assets/VRM/Runtime/IO/VRMTextureParam.cs.meta
rename to Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs.meta
index 43d5a7e6d..fd3606f57 100644
--- a/Assets/VRM/Runtime/IO/VRMTextureParam.cs.meta
+++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 58277bcba49b13142acfa67d40041970
+guid: c9128dde9a44e1f43a808330ebfba145
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/TextureFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/TextureFactory.cs
deleted file mode 100644
index 29cbc287c..000000000
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/TextureFactory.cs
+++ /dev/null
@@ -1,447 +0,0 @@
-using System;
-using System.Collections.Generic;
-using UnityEngine;
-using System.Linq;
-using System.Threading.Tasks;
-using VRMShaders;
-
-
-namespace UniGLTF
-{
- [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 bool IsSubAsset => IsUsed && !IsExternal;
-
- 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 Task GetTextureAsyncFunc(IAwaitCaller awaitCaller, glTF gltf, TextureImportParam param);
- public class TextureFactory : IDisposable
- {
- glTF m_gltf;
- IStorage m_storage;
-
- public readonly Dictionary ExternalMap;
-
- public TextureFactory(glTF gltf, IStorage storage, IEnumerable<(string, UnityEngine.Object)> externalMap)
- {
- m_gltf = gltf;
- m_storage = storage;
-
- if (externalMap != null)
- {
- ExternalMap = externalMap
- .Select(kv => (kv.Item1, kv.Item2 as Texture2D))
- .Where(kv => kv.Item2 != null)
- .ToDictionary(kv => kv.Item1, kv => kv.Item2);
- }
- }
-
- public void Dispose()
- {
- Action destroy = UnityResourceDestroyer.DestroyResource();
- foreach (var kv in m_textureCache)
- {
- if (!kv.Value.IsExternal)
- {
-#if VRM_DEVELOP
- // Debug.Log($"Destroy {kv.Value.Texture}");
-#endif
- destroy(kv.Value.Texture);
- }
- }
- m_textureCache.Clear();
- }
-
- ///
- /// 所有権(Dispose権)を移譲する
- ///
- ///
- public void TransferOwnership(TakeOwnershipFunc take)
- {
- var keys = new List();
- foreach (var x in m_textureCache)
- {
- if (x.Value.IsUsed && !x.Value.IsExternal)
- {
- // マテリアルから参照されていて
- // 外部のAssetからロードしていない。
- if (take(x.Value.Texture))
- {
- keys.Add(x.Key);
- }
- }
- }
- foreach (var x in keys)
- {
- m_textureCache.Remove(x);
- }
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- Dictionary m_textureCache = new Dictionary();
-
- public IEnumerable Textures => m_textureCache.Values;
-
- static Byte[] ToArray(ArraySegment bytes)
- {
- if (bytes.Array == null)
- {
- return new byte[] { };
- }
- else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
- {
- return bytes.Array;
- }
- else
- {
- Byte[] result = new byte[bytes.Count];
- Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
- return result;
- }
- }
-
- async Task GetOrCreateBaseTexture(IAwaitCaller awaitCaller, TextureImportParam param, GetTextureBytesAsync getTextureBytesAsync, RenderTextureReadWrite colorSpace, bool used)
- {
- var name = param.GltfName;
- if (m_textureCache.TryGetValue(name, out TextureLoadInfo cacheInfo))
- {
- return cacheInfo;
- }
-
- // not found. load new
- var imageBytes = await getTextureBytesAsync();
-
- //
- // texture from image(png etc) bytes
- //
- var texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, colorSpace == RenderTextureReadWrite.Linear);
- texture.name = name;
- if (imageBytes != null)
- {
- texture.LoadImage(imageBytes);
- }
-
- SetSampler(texture, param);
-
- cacheInfo = new TextureLoadInfo(texture, used, false);
- m_textureCache.Add(name, cacheInfo);
- return cacheInfo;
- }
-
- public static void SetSampler(Texture2D texture, TextureImportParam param)
- {
- if (texture == null)
- {
- return;
- }
-
- foreach (var (key, value) in param.Sampler.WrapModes)
- {
- switch (key)
- {
- case SamplerWrapType.All:
- texture.wrapMode = value;
- break;
-
- case SamplerWrapType.U:
- texture.wrapModeU = value;
- break;
-
- case SamplerWrapType.V:
- texture.wrapModeV = value;
- break;
-
- case SamplerWrapType.W:
- texture.wrapModeW = value;
- break;
-
- default:
- throw new NotImplementedException();
- }
- }
-
- texture.filterMode = param.Sampler.FilterMode;
- }
-
- ///
- /// テクスチャーをロード、必要であれば変換して返す。
- /// 同じものはキャッシュを返す
- ///
- /// 変換の有無を判断する: METALLIC_GLOSS_PROP
- /// METALLIC_GLOSS_PROPの追加パラメーター
- /// gltf の texture index
- ///
- public async Task GetTextureAsync(IAwaitCaller awaitCaller, glTF gltf, TextureImportParam param)
- {
- //
- // ExtractKey で External とのマッチングを試みる
- //
- // Normal => GltfName
- // Standard => ConvertedName
- // sRGB => GltfName
- // Linear => GltfName
- //
- if (param.Index0 != null && ExternalMap != null)
- {
- if (ExternalMap.TryGetValue(param.ExtractKey, out Texture2D external))
- {
- return external;
- }
- }
-
- switch (param.TextureType)
- {
- case TextureImportTypes.NormalMap:
- // Runtime/SubAsset 用に変換する
- {
- if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
- {
- var baseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index0, RenderTextureReadWrite.Linear, false);
- var converted = NormalConverter.Import(baseTexture.Texture);
- converted.name = param.ConvertedName;
- info = new TextureLoadInfo(converted, true, false);
- m_textureCache.Add(converted.name, info);
- }
- return info.Texture;
- }
-
- case TextureImportTypes.StandardMap:
- // 変換する
- {
- if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
- {
- TextureLoadInfo baseTexture = default;
- if (param.Index0!=null)
- {
- baseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index0, RenderTextureReadWrite.Linear, false);
- }
- TextureLoadInfo occlusionBaseTexture = default;
- if (param.Index1!=null)
- {
- occlusionBaseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index1, RenderTextureReadWrite.Linear, false);
- }
- var converted = OcclusionMetallicRoughnessConverter.Import(baseTexture.Texture, param.MetallicFactor, param.RoughnessFactor, occlusionBaseTexture.Texture);
- converted.name = param.ConvertedName;
- info = new TextureLoadInfo(converted, true, false);
- m_textureCache.Add(converted.name, info);
- }
- return info.Texture;
- }
-
- default:
- {
- var baseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index0, RenderTextureReadWrite.sRGB, true);
- return baseTexture.Texture;
- }
- }
-
- throw new NotImplementedException();
- }
-
- public static TextureImportParam CreateSRGB(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
- {
- var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.sRGB);
- var sampler = CreateSampler(parser.GLTF, textureIndex);
- GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
- return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.sRGB, default, default, getTextureBytesAsync, default, default, default, default, default);
- }
-
- public static TextureImportParam CreateNormal(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
- {
- var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.NormalMap);
- var sampler = CreateSampler(parser.GLTF, textureIndex);
- GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
- return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.NormalMap, default, default, getTextureBytesAsync, default, default, default, default, default);
- }
-
- public static TextureImportParam CreateStandard(GltfParser parser, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor)
- {
- TextureImportName name = default;
-
- GetTextureBytesAsync getMetallicRoughnessAsync = default;
- SamplerParam sampler = default;
- if (metallicRoughnessTextureIndex.HasValue)
- {
- name = CreateNameExt(parser.GLTF, metallicRoughnessTextureIndex.Value, TextureImportTypes.StandardMap);
- sampler = CreateSampler(parser.GLTF, metallicRoughnessTextureIndex.Value);
- getMetallicRoughnessAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, metallicRoughnessTextureIndex.Value)));
- }
-
- GetTextureBytesAsync getOcclusionAsync = default;
- if (occlusionTextureIndex.HasValue)
- {
- if(string.IsNullOrEmpty(name.GltfName)){
- name = CreateNameExt(parser.GLTF, occlusionTextureIndex.Value, TextureImportTypes.StandardMap);
- }
- sampler = CreateSampler(parser.GLTF, occlusionTextureIndex.Value);
- getOcclusionAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, occlusionTextureIndex.Value)));
- }
-
- return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.StandardMap, metallicFactor, roughnessFactor, getMetallicRoughnessAsync, getOcclusionAsync, default, default, default, default);
- }
-
- public static TextureImportName CreateNameExt(glTF gltf, int textureIndex, TextureImportTypes textureType)
- {
- if (textureIndex < 0 || textureIndex >= gltf.textures.Count)
- {
- throw new ArgumentOutOfRangeException();
- }
- var gltfTexture = gltf.textures[textureIndex];
- if (gltfTexture.source < 0 || gltfTexture.source >= gltf.images.Count)
- {
- throw new ArgumentOutOfRangeException();
- }
- var gltfImage = gltf.images[gltfTexture.source];
- return new TextureImportName(textureType, gltfTexture.name, gltfImage.GetExt(), gltfImage.uri);
- }
-
- public static SamplerParam CreateSampler(glTF gltf, int index)
- {
- var gltfTexture = gltf.textures[index];
- if (gltfTexture.sampler < 0 || gltfTexture.sampler >= gltf.samplers.Count)
- {
- // default
- return new SamplerParam
- {
- FilterMode = FilterMode.Bilinear,
- WrapModes = new (SamplerWrapType, TextureWrapMode)[] { },
- };
- }
-
- var gltfSampler = gltf.samplers[gltfTexture.sampler];
- return new SamplerParam
- {
- WrapModes = GetUnityWrapMode(gltfSampler).ToArray(),
- FilterMode = ImportFilterMode(gltfSampler.minFilter),
- };
- }
-
- public static IEnumerable<(SamplerWrapType, TextureWrapMode)> GetUnityWrapMode(glTFTextureSampler sampler)
- {
- if (sampler.wrapS == sampler.wrapT)
- {
- switch (sampler.wrapS)
- {
- case glWrap.NONE: // default
- yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
- break;
-
- case glWrap.CLAMP_TO_EDGE:
- yield return (SamplerWrapType.All, TextureWrapMode.Clamp);
- break;
-
- case glWrap.REPEAT:
- yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
- break;
-
- case glWrap.MIRRORED_REPEAT:
- yield return (SamplerWrapType.All, TextureWrapMode.Mirror);
- break;
-
- default:
- throw new NotImplementedException();
- }
- }
- else
- {
- switch (sampler.wrapS)
- {
- case glWrap.NONE: // default
- yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
- break;
-
- case glWrap.CLAMP_TO_EDGE:
- yield return (SamplerWrapType.U, TextureWrapMode.Clamp);
- break;
-
- case glWrap.REPEAT:
- yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
- break;
-
- case glWrap.MIRRORED_REPEAT:
- yield return (SamplerWrapType.U, TextureWrapMode.Mirror);
- break;
-
- default:
- throw new NotImplementedException();
- }
- switch (sampler.wrapT)
- {
- case glWrap.NONE: // default
- yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
- break;
-
- case glWrap.CLAMP_TO_EDGE:
- yield return (SamplerWrapType.V, TextureWrapMode.Clamp);
- break;
-
- case glWrap.REPEAT:
- yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
- break;
-
- case glWrap.MIRRORED_REPEAT:
- yield return (SamplerWrapType.V, TextureWrapMode.Mirror);
- break;
-
- default:
- throw new NotImplementedException();
- }
- }
- }
-
- public static FilterMode ImportFilterMode(glFilter filterMode)
- {
- switch (filterMode)
- {
- case glFilter.NEAREST:
- case glFilter.NEAREST_MIPMAP_LINEAR:
- case glFilter.NEAREST_MIPMAP_NEAREST:
- return FilterMode.Point;
-
- case glFilter.NONE:
- case glFilter.LINEAR:
- case glFilter.LINEAR_MIPMAP_NEAREST:
- return FilterMode.Bilinear;
-
- case glFilter.LINEAR_MIPMAP_LINEAR:
- return FilterMode.Trilinear;
-
- default:
- throw new NotImplementedException();
- }
- }
-
- }
-}
diff --git a/Assets/VRM/Runtime/IO/VRMTextureParam.cs b/Assets/VRM/Runtime/IO/MToonTextureParam.cs
similarity index 72%
rename from Assets/VRM/Runtime/IO/VRMTextureParam.cs
rename to Assets/VRM/Runtime/IO/MToonTextureParam.cs
index 666fb2ba4..17c1aad79 100644
--- a/Assets/VRM/Runtime/IO/VRMTextureParam.cs
+++ b/Assets/VRM/Runtime/IO/MToonTextureParam.cs
@@ -3,19 +3,20 @@ using UniGLTF;
using UnityEngine;
using VRMShaders;
+
namespace VRM
{
- public static class VRMTextureParam
+ public static class MToonTextureParam
{
public static TextureImportParam Create(GltfParser parser, int index, Vector2 offset, Vector2 scale, string prop, float metallicFactor, float roughnessFactor)
{
switch (prop)
{
case TextureImportParam.NORMAL_PROP:
- return TextureFactory.CreateNormal(parser, index, offset, scale);
+ return GltfTextureImporter.CreateNormal(parser, index, offset, scale);
default:
- return TextureFactory.CreateSRGB(parser, index, offset, scale);
+ return GltfTextureImporter.CreateSRGB(parser, index, offset, scale);
case TextureImportParam.OCCLUSION_PROP:
case TextureImportParam.METALLIC_GLOSS_PROP:
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta b/Assets/VRM/Runtime/IO/MToonTextureParam.cs.meta
similarity index 83%
rename from Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta
rename to Assets/VRM/Runtime/IO/MToonTextureParam.cs.meta
index 0b34ae7e0..382c9f4ec 100644
--- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta
+++ b/Assets/VRM/Runtime/IO/MToonTextureParam.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: ab2b998b9235dc94a90ccaf2e40a50a6
+guid: a7af3a3bafe41a64db660a18b1c25097
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs
index e85f9f42b..9fe29dbad 100644
--- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs
+++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs
@@ -297,7 +297,7 @@ namespace VRM
meta.Title = gltfMeta.title;
if (gltfMeta.texture >= 0)
{
- meta.Thumbnail = await TextureFactory.GetTextureAsync(awaitCaller, GLTF, TextureFactory.CreateSRGB(Parser, gltfMeta.texture, Vector2.zero, Vector2.one));
+ meta.Thumbnail = await TextureFactory.GetTextureAsync(GltfTextureImporter.CreateSRGB(Parser, gltfMeta.texture, Vector2.zero, Vector2.one));
}
meta.AllowedUser = gltfMeta.allowedUser;
meta.ViolentUssage = gltfMeta.violentUssage;
@@ -311,7 +311,7 @@ namespace VRM
return meta;
}
- public override void TransferOwnership(TakeOwnershipFunc take)
+ public override void TransferOwnership(Func take)
{
// VRM 固有のリソース(ScriptableObject)
if (take(HumanoidAvatar))
diff --git a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs b/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs
index 29496a5a5..38e45ee1c 100644
--- a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs
+++ b/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs
@@ -82,8 +82,8 @@ namespace VRM
scale = new Vector2(value[2], value[3]);
}
- var param = VRMTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1);
- var texture = await getTexture(awaitCaller, parser.GLTF, param);
+ var param = MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1);
+ var texture = await getTexture(param);
if (texture != null)
{
material.SetTexture(kv.Key, texture);
diff --git a/Assets/VRM/Runtime/IO/VRMTextureEnumerator.cs b/Assets/VRM/Runtime/IO/VRMTextureEnumerator.cs
index 31d0da25d..20ed7f39d 100644
--- a/Assets/VRM/Runtime/IO/VRMTextureEnumerator.cs
+++ b/Assets/VRM/Runtime/IO/VRMTextureEnumerator.cs
@@ -35,7 +35,7 @@ namespace VRM
}
// SRGB color or normalmap
- yield return VRMTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, default, default);
+ yield return MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, default, default);
}
}
@@ -72,7 +72,7 @@ namespace VRM
// thumbnail
if (m_vrm.meta != null && m_vrm.meta.texture != -1)
{
- var textureInfo = TextureFactory.CreateSRGB(parser, m_vrm.meta.texture, Vector2.zero, Vector2.one);
+ var textureInfo = GltfTextureImporter.CreateSRGB(parser, m_vrm.meta.texture, Vector2.zero, Vector2.one);
if (used.Add(textureInfo.ExtractKey))
{
yield return textureInfo;
diff --git a/Assets/VRMShaders/Runtime/TextureFactory.cs b/Assets/VRMShaders/Runtime/TextureFactory.cs
new file mode 100644
index 000000000..06e2ac35c
--- /dev/null
+++ b/Assets/VRMShaders/Runtime/TextureFactory.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using System.Linq;
+using System.Threading.Tasks;
+
+
+namespace VRMShaders
+{
+ [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 bool IsSubAsset => IsUsed && !IsExternal;
+
+ 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 class TextureFactory : IDisposable
+ {
+ public readonly Dictionary ExternalMap;
+
+ public TextureFactory(IEnumerable<(string, UnityEngine.Object)> externalMap)
+ {
+ if (externalMap != null)
+ {
+ ExternalMap = externalMap
+ .Select(kv => (kv.Item1, kv.Item2 as Texture2D))
+ .Where(kv => kv.Item2 != null)
+ .ToDictionary(kv => kv.Item1, kv => kv.Item2);
+ }
+ }
+
+ public static Action DestroyResource()
+ {
+ Action des = (UnityEngine.Object o) => UnityEngine.Object.Destroy(o);
+ Action desi = (UnityEngine.Object o) => UnityEngine.Object.DestroyImmediate(o);
+ Action func = Application.isPlaying
+ ? des
+ : desi
+ ;
+ return func;
+ }
+
+ public void Dispose()
+ {
+ Action destroy = DestroyResource();
+ foreach (var kv in m_textureCache)
+ {
+ if (!kv.Value.IsExternal)
+ {
+#if VRM_DEVELOP
+ // Debug.Log($"Destroy {kv.Value.Texture}");
+#endif
+ destroy(kv.Value.Texture);
+ }
+ }
+ m_textureCache.Clear();
+ }
+
+ ///
+ /// 所有権(Dispose権)を移譲する
+ ///
+ ///
+ public void TransferOwnership(Func take)
+ {
+ var keys = new List();
+ foreach (var x in m_textureCache)
+ {
+ if (x.Value.IsUsed && !x.Value.IsExternal)
+ {
+ // マテリアルから参照されていて
+ // 外部のAssetからロードしていない。
+ if (take(x.Value.Texture))
+ {
+ keys.Add(x.Key);
+ }
+ }
+ }
+ foreach (var x in keys)
+ {
+ m_textureCache.Remove(x);
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Dictionary m_textureCache = new Dictionary();
+
+ public IEnumerable Textures => m_textureCache.Values;
+
+
+ async Task GetOrCreateBaseTexture(TextureImportParam param, GetTextureBytesAsync getTextureBytesAsync, RenderTextureReadWrite colorSpace, bool used)
+ {
+ var name = param.GltfName;
+ if (m_textureCache.TryGetValue(name, out TextureLoadInfo cacheInfo))
+ {
+ return cacheInfo;
+ }
+
+ // not found. load new
+ var imageBytes = await getTextureBytesAsync();
+
+ //
+ // texture from image(png etc) bytes
+ //
+ var texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, colorSpace == RenderTextureReadWrite.Linear);
+ texture.name = name;
+ if (imageBytes != null)
+ {
+ texture.LoadImage(imageBytes);
+ }
+
+ SetSampler(texture, param);
+
+ cacheInfo = new TextureLoadInfo(texture, used, false);
+ m_textureCache.Add(name, cacheInfo);
+ return cacheInfo;
+ }
+
+ public static void SetSampler(Texture2D texture, TextureImportParam param)
+ {
+ if (texture == null)
+ {
+ return;
+ }
+
+ foreach (var (key, value) in param.Sampler.WrapModes)
+ {
+ switch (key)
+ {
+ case SamplerWrapType.All:
+ texture.wrapMode = value;
+ break;
+
+ case SamplerWrapType.U:
+ texture.wrapModeU = value;
+ break;
+
+ case SamplerWrapType.V:
+ texture.wrapModeV = value;
+ break;
+
+ case SamplerWrapType.W:
+ texture.wrapModeW = value;
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ texture.filterMode = param.Sampler.FilterMode;
+ }
+
+ ///
+ /// テクスチャーをロード、必要であれば変換して返す。
+ /// 同じものはキャッシュを返す
+ ///
+ /// 変換の有無を判断する: METALLIC_GLOSS_PROP
+ /// METALLIC_GLOSS_PROPの追加パラメーター
+ /// gltf の texture index
+ ///
+ public async Task GetTextureAsync(TextureImportParam param)
+ {
+ //
+ // ExtractKey で External とのマッチングを試みる
+ //
+ // Normal => GltfName
+ // Standard => ConvertedName
+ // sRGB => GltfName
+ // Linear => GltfName
+ //
+ if (param.Index0 != null && ExternalMap != null)
+ {
+ if (ExternalMap.TryGetValue(param.ExtractKey, out Texture2D external))
+ {
+ return external;
+ }
+ }
+
+ switch (param.TextureType)
+ {
+ case TextureImportTypes.NormalMap:
+ // Runtime/SubAsset 用に変換する
+ {
+ if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
+ {
+ var baseTexture = await GetOrCreateBaseTexture(param, param.Index0, RenderTextureReadWrite.Linear, false);
+ var converted = NormalConverter.Import(baseTexture.Texture);
+ converted.name = param.ConvertedName;
+ info = new TextureLoadInfo(converted, true, false);
+ m_textureCache.Add(converted.name, info);
+ }
+ return info.Texture;
+ }
+
+ case TextureImportTypes.StandardMap:
+ // 変換する
+ {
+ if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
+ {
+ TextureLoadInfo baseTexture = default;
+ if (param.Index0!=null)
+ {
+ baseTexture = await GetOrCreateBaseTexture(param, param.Index0, RenderTextureReadWrite.Linear, false);
+ }
+ TextureLoadInfo occlusionBaseTexture = default;
+ if (param.Index1!=null)
+ {
+ occlusionBaseTexture = await GetOrCreateBaseTexture(param, param.Index1, RenderTextureReadWrite.Linear, false);
+ }
+ var converted = OcclusionMetallicRoughnessConverter.Import(baseTexture.Texture, param.MetallicFactor, param.RoughnessFactor, occlusionBaseTexture.Texture);
+ converted.name = param.ConvertedName;
+ info = new TextureLoadInfo(converted, true, false);
+ m_textureCache.Add(converted.name, info);
+ }
+ return info.Texture;
+ }
+
+ default:
+ {
+ var baseTexture = await GetOrCreateBaseTexture(param, param.Index0, RenderTextureReadWrite.sRGB, true);
+ return baseTexture.Texture;
+ }
+ }
+
+ throw new NotImplementedException();
+ }
+
+
+ }
+}
diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/TextureFactory.cs.meta b/Assets/VRMShaders/Runtime/TextureFactory.cs.meta
similarity index 100%
rename from Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/TextureFactory.cs.meta
rename to Assets/VRMShaders/Runtime/TextureFactory.cs.meta