diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorMaterial.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorMaterial.cs index c9d2e3ef0..6f0d0114b 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorMaterial.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorMaterial.cs @@ -57,17 +57,27 @@ namespace UniGLTF s_foldTextures = EditorGUILayout.Foldout(s_foldTextures, "Remapped Textures"); if (s_foldTextures) { - DrawRemapGUI(importer, GltfTextureEnumerator.Enumerate(parser).Select(x => - { - switch (x.TextureType) + var names = GltfTextureEnumerator.Enumerate(parser) + .Select(x => { - case TextureImportTypes.NormalMap: - return x.GltfName; + if (x.TextureType != TextureImportTypes.StandardMap && !string.IsNullOrEmpty(x.Uri)) + { + // GLTF の 無変換テクスチャーをスキップする + return null; + } - default: - return x.ConvertedName; - } - })); + switch (x.TextureType) + { + case TextureImportTypes.NormalMap: + return x.GltfName; + + default: + return x.ConvertedName; + } + }) + .Where(x => !string.IsNullOrEmpty(x)) + ; + DrawRemapGUI(importer, names); } if (GUILayout.Button("Clear")) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 4569d0c59..5f7d6422b 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 { @@ -35,6 +36,8 @@ namespace UniGLTF MaterialFactory m_materialFactory; public MaterialFactory MaterialFactory => m_materialFactory; + public readonly GltfMaterialImporter GltfMaterialImporter = new GltfMaterialImporter(); + TextureFactory m_textureFactory; public TextureFactory TextureFactory => m_textureFactory; @@ -44,8 +47,8 @@ namespace UniGLTF IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null) { m_parser = parser; - m_textureFactory = new TextureFactory(GLTF, Storage, externalObjectMap); - m_materialFactory = new MaterialFactory(m_parser, externalObjectMap); + m_textureFactory = new TextureFactory(externalObjectMap); + m_materialFactory = new MaterialFactory(externalObjectMap); } #region Source @@ -110,7 +113,7 @@ namespace UniGLTF using (MeasureTime("LoadMaterials")) { - await m_materialFactory.LoadMaterialsAsync(m_awaitCaller, m_textureFactory.GetTextureAsync); + await LoadMaterialsAsync(); } var meshImporter = new MeshImporter(); @@ -170,6 +173,24 @@ namespace UniGLTF await OnLoadModel(m_awaitCaller, MeasureTime); } + public async Task LoadMaterialsAsync() + { + if (m_parser.GLTF.materials == null || m_parser.GLTF.materials.Count == 0) + { + // no material. work around. + var param = GltfMaterialImporter.CreateParam(m_parser, 0); + var material = await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync); + } + else + { + for (int i = 0; i < m_parser.GLTF.materials.Count; ++i) + { + var param = GltfMaterialImporter.CreateParam(m_parser, i); + var material = await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync); + } + } + } + protected virtual Task OnLoadModel(IAwaitCaller awaitCaller, Func MeasureTime) { // do nothing @@ -283,7 +304,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/GltfMaterialImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs new file mode 100644 index 000000000..6981d96a0 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using UnityEngine; +using VRMShaders; + + +namespace UniGLTF +{ + public delegate bool TryCreateMaterialParamFromGltf(GltfParser parser, int i, out MaterialImportParam param); + + public class GltfMaterialImporter + { + /// + /// gltfMaterialを解釈する関数。 + /// 拡張するには、先頭に挿入するべし。 + /// + /// + /// + public readonly List GltfMaterialParamProcessors = new List(); + + public GltfMaterialImporter() + { + // unlit を試し + GltfMaterialParamProcessors.Add(GltfUnlitMaterial.TryCreateParam); + // PBR を作成する(失敗しない) + GltfMaterialParamProcessors.Add(GltfPBRMaterial.TryCreateParam); + } + + public static string MaterialName(int index, glTFMaterial src) + { + if (src != null && !string.IsNullOrEmpty(src.name)) + { + return src.name; + } + return $"material_{index:00}"; + } + + public MaterialImportParam CreateParam(GltfParser parser, int i) + { + foreach (var tryCreate in GltfMaterialParamProcessors) + { + if (tryCreate(parser, i, out MaterialImportParam param)) + { + return param; + } + } + + // fallback +#if VRM_DEVELOP + Debug.LogWarning($"material: {i} out of range. fallback"); +#endif + return new MaterialImportParam(MaterialName(i, null), GltfPBRMaterial.ShaderName); + } + + public static (Vector2, Vector2) GetTextureOffsetAndScale(glTFTextureInfo textureInfo) + { + Vector2 offset = new Vector2(0, 0); + Vector2 scale = new Vector2(1, 1); + if (glTF_KHR_texture_transform.TryGet(textureInfo, out glTF_KHR_texture_transform textureTransform)) + { + if (textureTransform.offset != null && textureTransform.offset.Length == 2) + { + offset = new Vector2(textureTransform.offset[0], textureTransform.offset[1]); + } + if (textureTransform.scale != null && textureTransform.scale.Length == 2) + { + scale = new Vector2(textureTransform.scale[0], textureTransform.scale[1]); + } + + offset.y = (offset.y + scale.y - 1.0f) * -1.0f; + } + return (offset, scale); + } + + + /// + /// for unittest + /// + public static glTF CreateMaterialForTest(glTFMaterial material) + { + return new glTF + { + materials = new System.Collections.Generic.List { + material + }, + textures = new List{ + new glTFTexture{ + name = "texture_0" + } + }, + images = new List{ + new glTFImage{ + name = "image_0", + mimeType = "image/png", + } + }, + }; + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs.meta similarity index 83% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs.meta index 0b34ae7e0..31b02ec38 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ab2b998b9235dc94a90ccaf2e40a50a6 +guid: 06d7ddbd9b8b38544a74013a6992210b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs new file mode 100644 index 000000000..aafb1befb --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs @@ -0,0 +1,213 @@ +using System.Threading.Tasks; +using UnityEngine; +using VRMShaders; + + +namespace UniGLTF +{ + /// + /// Gltf から MaterialImportParam に変換する + /// + /// StandardShader variables + /// + /// _Color + /// _MainTex + /// _Cutoff + /// _Glossiness + /// _Metallic + /// _MetallicGlossMap + /// _BumpScale + /// _BumpMap + /// _Parallax + /// _ParallaxMap + /// _OcclusionStrength + /// _OcclusionMap + /// _EmissionColor + /// _EmissionMap + /// _DetailMask + /// _DetailAlbedoMap + /// _DetailNormalMapScale + /// _DetailNormalMap + /// _UVSec + /// _EmissionScaleUI + /// _EmissionColorUI + /// _Mode + /// _SrcBlend + /// _DstBlend + /// _ZWrite + /// + /// + public static class GltfPBRMaterial + { + public const string ShaderName = "Standard"; + + private enum BlendMode + { + Opaque, + Cutout, + Fade, + Transparent + } + + public static TextureImportParam BaseColorTexture(GltfParser parser, glTFMaterial src) + { + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); + return GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale); + } + + public static TextureImportParam StandardTexture(GltfParser parser, glTFMaterial src) + { + var metallicFactor = 1.0f; + var roughnessFactor = 1.0f; + if (src.pbrMetallicRoughness != null) + { + metallicFactor = src.pbrMetallicRoughness.metallicFactor; + roughnessFactor = src.pbrMetallicRoughness.roughnessFactor; + } + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture); + return GltfTextureImporter.CreateStandard(parser, + src.pbrMetallicRoughness?.metallicRoughnessTexture?.index, + src.occlusionTexture?.index, + offset, scale, + metallicFactor, + roughnessFactor); + } + + public static TextureImportParam NormalTexture(GltfParser parser, glTFMaterial src) + { + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.normalTexture); + return GltfTextureImporter.CreateNormal(parser, src.normalTexture.index, offset, scale); + } + + public static bool TryCreateParam(GltfParser parser, int i, out MaterialImportParam param) + { + if (i < 0 || i >= parser.GLTF.materials.Count) + { + param = default; + return false; + } + + var src = parser.GLTF.materials[i]; + param = new MaterialImportParam(GltfMaterialImporter.MaterialName(i, src), ShaderName); + + var standardParam = default(TextureImportParam); + if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) + { + if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) + { + standardParam = StandardTexture(parser, src); + } + + if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) + { + var color = src.pbrMetallicRoughness.baseColorFactor; + param.Colors.Add("_Color", (new Color(color[0], color[1], color[2], color[3])).gamma); + } + + if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) + { + var textureParam = BaseColorTexture(parser, src); + param.TextureSlots.Add("_MainTex", textureParam); + } + + if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) + { + param.Actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP")); + param.TextureSlots.Add("_MetallicGlossMap", standardParam); + // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. + param.FloatValues.Add("_Metallic", 1.0f); + param.FloatValues.Add("_GlossMapScale", 1.0f); + } + else + { + param.FloatValues.Add("_Metallic", src.pbrMetallicRoughness.metallicFactor); + param.FloatValues.Add("_Glossiness", 1.0f - src.pbrMetallicRoughness.roughnessFactor); + } + } + + if (src.normalTexture != null && src.normalTexture.index != -1) + { + param.Actions.Add(material => material.EnableKeyword("_NORMALMAP")); + var textureParam = NormalTexture(parser, src); + param.TextureSlots.Add("_BumpMap", textureParam); + param.FloatValues.Add("_BumpScale", src.normalTexture.scale); + } + + if (src.occlusionTexture != null && src.occlusionTexture.index != -1) + { + param.TextureSlots.Add("_OcclusionMap", standardParam); + param.FloatValues.Add("_OcclusionStrength", src.occlusionTexture.strength); + } + + if (src.emissiveFactor != null + || (src.emissiveTexture != null && src.emissiveTexture.index != -1)) + { + param.Actions.Add(material => { + material.EnableKeyword("_EMISSION"); + material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; + }); + + if (src.emissiveFactor != null && src.emissiveFactor.Length == 3) + { + param.Colors.Add("_EmissionColor", new Color(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2])); + } + + if (src.emissiveTexture != null && src.emissiveTexture.index != -1) + { + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.emissiveTexture); + var textureParam = GltfTextureImporter.CreateSRGB(parser, src.emissiveTexture.index, offset, scale); + param.TextureSlots.Add("_EmissionMap", textureParam); + } + } + + param.Actions.Add(material => { + BlendMode blendMode = BlendMode.Opaque; + // https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980 + switch (src.alphaMode) + { + case "BLEND": + blendMode = BlendMode.Fade; + material.SetOverrideTag("RenderType", "Transparent"); + material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + material.SetInt("_ZWrite", 0); + material.DisableKeyword("_ALPHATEST_ON"); + material.EnableKeyword("_ALPHABLEND_ON"); + material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + material.renderQueue = 3000; + break; + + case "MASK": + blendMode = BlendMode.Cutout; + material.SetOverrideTag("RenderType", "TransparentCutout"); + material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); + material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); + material.SetInt("_ZWrite", 1); + material.SetFloat("_Cutoff", src.alphaCutoff); + material.EnableKeyword("_ALPHATEST_ON"); + material.DisableKeyword("_ALPHABLEND_ON"); + material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + material.renderQueue = 2450; + + break; + + default: // OPAQUE + blendMode = BlendMode.Opaque; + material.SetOverrideTag("RenderType", ""); + material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); + material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); + material.SetInt("_ZWrite", 1); + material.DisableKeyword("_ALPHATEST_ON"); + material.DisableKeyword("_ALPHABLEND_ON"); + material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + material.renderQueue = -1; + break; + } + + material.SetFloat("_Mode", (float)blendMode); + }); + + return true; + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs.meta similarity index 100% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs.meta diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs index 35506de87..3fb2e059c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfTextureEnumerator.cs @@ -42,7 +42,7 @@ namespace UniGLTF // base color if (m.pbrMetallicRoughness?.baseColorTexture != null) { - yield return PBRMaterialItem.BaseColorTexture(parser, m); + yield return GltfPBRMaterial.BaseColorTexture(parser, m); } // metallic roughness @@ -55,14 +55,14 @@ namespace UniGLTF // emission if (m.emissiveTexture != null) { - var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(m.emissiveTexture); - yield return TextureFactory.CreateSRGB(parser, m.emissiveTexture.index, offset, scale); + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(m.emissiveTexture); + yield return GltfTextureImporter.CreateSRGB(parser, m.emissiveTexture.index, offset, scale); } // normal if (m.normalTexture != null) { - yield return PBRMaterialItem.NormalTexture(parser, m); + yield return GltfPBRMaterial.NormalTexture(parser, m); } // occlusion @@ -75,7 +75,7 @@ namespace UniGLTF // metallicSmooth and occlusion if (metallicRoughnessTexture.HasValue || occlusionTexture.HasValue) { - yield return PBRMaterialItem.StandardTexture(parser, m); + yield return GltfPBRMaterial.StandardTexture(parser, m); } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs new file mode 100644 index 000000000..f37e5f741 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs @@ -0,0 +1,88 @@ +using UnityEngine; +using VRMShaders; + + +namespace UniGLTF +{ + public static class GltfUnlitMaterial + { + public const string ShaderName = "UniGLTF/UniUnlit"; + + public static bool TryCreateParam(GltfParser parser, int i, out MaterialImportParam param) + { + if (i < 0 || i >= parser.GLTF.materials.Count) + { + param = default; + return false; + } + + var src = parser.GLTF.materials[i]; + if (!glTF_KHR_materials_unlit.IsEnable(src)) + { + param = default; + return false; + } + + param = new MaterialImportParam(GltfMaterialImporter.MaterialName(i, src), ShaderName); + + // texture + if (src.pbrMetallicRoughness.baseColorTexture != null) + { + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); + var textureParam = GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale); + param.TextureSlots.Add("_MainTex", textureParam); + } + + // color + if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) + { + var color = src.pbrMetallicRoughness.baseColorFactor; + param.Colors.Add("_Color", (new Color(color[0], color[1], color[2], color[3])).gamma); + } + + //renderMode + param.Actions.Add(material => + { + if (src.alphaMode == "OPAQUE") + { + UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque); + } + else if (src.alphaMode == "BLEND") + { + UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Transparent); + } + else if (src.alphaMode == "MASK") + { + UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Cutout); + material.SetFloat("_Cutoff", src.alphaCutoff); + } + else + { + // default OPAQUE + UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque); + } + + // culling + if (src.doubleSided) + { + UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Off); + } + else + { + UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Back); + } + + // VColor + var hasVertexColor = parser.GLTF.MaterialHasVertexColor(i); + if (hasVertexColor) + { + UniUnlit.Utils.SetVColBlendMode(material, UniUnlit.UniUnlitVertexColorBlendOp.Multiply); + } + + UniUnlit.Utils.ValidateProperties(material, true); + }); + + return true; + } + } +} diff --git a/Assets/VRM/Runtime/IO/VRMTextureParam.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta similarity index 83% rename from Assets/VRM/Runtime/IO/VRMTextureParam.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta index 43d5a7e6d..c3911e8da 100644 --- a/Assets/VRM/Runtime/IO/VRMTextureParam.cs.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 58277bcba49b13142acfa67d40041970 +guid: f9748317ec6964a47b0a1c4150fe62e8 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs deleted file mode 100644 index 7e81d1522..000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using UnityEngine; - -namespace UniGLTF -{ - public class MaterialFactory : IDisposable - { - GltfParser m_parser; - Dictionary m_externalMap; - public bool TryGetExternal(int index, out Material external) - { - if (m_externalMap != null) - { - var gltfMaterial = m_parser.GLTF.materials[index]; - if (m_externalMap.TryGetValue(gltfMaterial.name, out external)) - { - return true; - } - } - - external = default; - return false; - } - - public MaterialFactory(GltfParser parser, IEnumerable<(string, UnityEngine.Object)> externalMap) - { - m_parser = parser; - if (externalMap != null) - { - m_externalMap = externalMap - .Select(kv => (kv.Item1, kv.Item2 as Material)) - .Where(kv => kv.Item2 != null) - .ToDictionary(kv => kv.Item1, kv => kv.Item2) - ; - } - } - - public delegate Task CreateMaterialAsyncFunc(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture); - CreateMaterialAsyncFunc m_createMaterialAsync; - public CreateMaterialAsyncFunc CreateMaterialAsync - { - set - { - m_createMaterialAsync = value; - } - get - { - if (m_createMaterialAsync == null) - { - m_createMaterialAsync = MaterialFactory.DefaultCreateMaterialAsync; - } - return m_createMaterialAsync; - } - } - - public struct MaterialLoadInfo - { - public readonly Material Asset; - public readonly bool UseExternal; - - public bool IsSubAsset => !UseExternal; - - public MaterialLoadInfo(Material asset, bool useExternal) - { - Asset = asset; - UseExternal = useExternal; - } - } - - List m_materials = new List(); - public IReadOnlyList Materials => m_materials; - void Remove(Material material) - { - var index = m_materials.FindIndex(x => x.Asset == material); - if (index >= 0) - { - m_materials.RemoveAt(index); - - } - } - - public void Dispose() - { - foreach (var x in m_materials) - { - if (!x.UseExternal) - { - // 外部の '.asset' からロードしていない -#if VRM_DEVELOP - // Debug.Log($"Destroy {x.Asset}"); -#endif - UnityEngine.Object.DestroyImmediate(x.Asset, false); - } - } - } - - /// - /// 所有権(Dispose権)を移譲する - /// - /// - public void TransferOwnership(TakeOwnershipFunc take) - { - var list = new List(); - foreach (var x in m_materials) - { - if (!x.UseExternal) - { - // 外部の '.asset' からロードしていない - if (take(x.Asset)) - { - list.Add(x.Asset); - } - } - } - foreach (var x in list) - { - Remove(x); - } - } - - public Material GetMaterial(int index) - { - if (index < 0) return null; - if (index >= m_materials.Count) return null; - return m_materials[index].Asset; - } - - /// - /// テクスチャ生成 - /// - /// - /// - public async Task LoadMaterialsAsync(IAwaitCaller awaitCaller, GetTextureAsyncFunc getTexture) - { - if (m_parser.GLTF.materials == null || m_parser.GLTF.materials.Count == 0) - { - // no material. work around. - var material = await CreateMaterialAsync(awaitCaller, m_parser, 0, getTexture); - m_materials.Add(new MaterialLoadInfo(material, false)); - return; - } - - for (int i = 0; i < m_parser.GLTF.materials.Count; ++i) - { - if (TryGetExternal(i, out Material material)) - { - m_materials.Add(new MaterialLoadInfo(material, true)); - continue; - } - - material = await CreateMaterialAsync(awaitCaller, m_parser, i, getTexture); - m_materials.Add(new MaterialLoadInfo(material, false)); - } - } - - public static string MaterialName(int index, glTFMaterial src) - { - if(src!=null && !string.IsNullOrEmpty(src.name)) - { - return src.name; - } - return $"material_{index:00}"; - } - - public static (Vector2, Vector2) GetTextureOffsetAndScale(glTFTextureInfo textureInfo) - { - Vector2 offset = new Vector2(0, 0); - Vector2 scale = new Vector2(1, 1); - if (glTF_KHR_texture_transform.TryGet(textureInfo, out glTF_KHR_texture_transform textureTransform)) - { - if (textureTransform.offset != null && textureTransform.offset.Length == 2) - { - offset = new Vector2(textureTransform.offset[0], textureTransform.offset[1]); - } - if (textureTransform.scale != null && textureTransform.scale.Length == 2) - { - scale = new Vector2(textureTransform.scale[0], textureTransform.scale[1]); - } - - offset.y = (offset.y + scale.y - 1.0f) * -1.0f; - } - return (offset, scale); - } - - public static void SetTextureOffsetAndScale(Material material, string propertyName, Vector2 offset, Vector2 scale) - { - material.SetTextureOffset(propertyName, offset); - material.SetTextureScale(propertyName, scale); - } - - public static Task DefaultCreateMaterialAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture) - { - if (i < 0 || i >= parser.GLTF.materials.Count) - { - UnityEngine.Debug.LogWarning("glTFMaterial is empty"); - return PBRMaterialItem.CreateAsync(awaitCaller, parser, i, getTexture); - } - var x = parser.GLTF.materials[i]; - - if (glTF_KHR_materials_unlit.IsEnable(x)) - { - var hasVertexColor = parser.GLTF.MaterialHasVertexColor(i); - return UnlitMaterialItem.CreateAsync(awaitCaller, parser, i, getTexture, hasVertexColor); - } - - return PBRMaterialItem.CreateAsync(awaitCaller, parser, i, getTexture); - } - - /// - /// for unittest - /// - /// - /// - /// - /// - public static Material CreateMaterialForTest(int i, glTFMaterial material) - { - var gltf = new glTF - { - materials = new System.Collections.Generic.List { material }, - textures = new List{ - new glTFTexture{ - name = "texture_0" - } - }, - images = new List{ - new glTFImage{ - name = "image_0", - mimeType = "image/png", - } - }, - }; - var task = DefaultCreateMaterialAsync(default(ImmediateCaller), new GltfParser{GLTF = gltf}, i, null); - return task.Result; - } - } -} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs deleted file mode 100644 index b17721f16..000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs +++ /dev/null @@ -1,244 +0,0 @@ - -using System.Threading.Tasks; -using UnityEngine; -using VRMShaders; - -namespace UniGLTF -{ - /// StandardShader variables - /// - /// _Color - /// _MainTex - /// _Cutoff - /// _Glossiness - /// _Metallic - /// _MetallicGlossMap - /// _BumpScale - /// _BumpMap - /// _Parallax - /// _ParallaxMap - /// _OcclusionStrength - /// _OcclusionMap - /// _EmissionColor - /// _EmissionMap - /// _DetailMask - /// _DetailAlbedoMap - /// _DetailNormalMapScale - /// _DetailNormalMap - /// _UVSec - /// _EmissionScaleUI - /// _EmissionColorUI - /// _Mode - /// _SrcBlend - /// _DstBlend - /// _ZWrite - public static class PBRMaterialItem - { - public const string ShaderName = "Standard"; - - private enum BlendMode - { - Opaque, - Cutout, - Fade, - Transparent - } - - 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); - } - - public static TextureImportParam StandardTexture(GltfParser parser, glTFMaterial src) - { - var metallicFactor = 1.0f; - var roughnessFactor = 1.0f; - if (src.pbrMetallicRoughness != null) - { - metallicFactor = src.pbrMetallicRoughness.metallicFactor; - roughnessFactor = src.pbrMetallicRoughness.roughnessFactor; - } - var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture); - return TextureFactory.CreateStandard(parser, - src.pbrMetallicRoughness?.metallicRoughnessTexture?.index, - src.occlusionTexture?.index, - offset, scale, - metallicFactor, - roughnessFactor); - } - - public static TextureImportParam NormalTexture(GltfParser parser, glTFMaterial src) - { - var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.normalTexture); - return TextureFactory.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); - } - - var material = new Material(Shader.Find(ShaderName)); - if (i < 0 || i >= parser.GLTF.materials.Count) - { - material.name = MaterialFactory.MaterialName(i, null); - return material; - } - - var src = parser.GLTF.materials[i]; - material.name = MaterialFactory.MaterialName(i, src); - var standardParam = default(TextureImportParam); - if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) - { - if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) - { - standardParam = StandardTexture(parser, src); - } - if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) - { - var color = src.pbrMetallicRoughness.baseColorFactor; - material.color = (new Color(color[0], color[1], color[2], color[3])).gamma; - } - - if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) - { - var param = BaseColorTexture(parser, src); - material.mainTexture = await getTexture(awaitCaller, parser.GLTF, param); - - // Texture Offset and Scale - MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", param.Offset, param.Scale); - } - - if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) - { - material.EnableKeyword("_METALLICGLOSSMAP"); - - var texture = await getTexture(awaitCaller, parser.GLTF, standardParam); - if (texture != null) - { - material.SetTexture(TextureImportParam.METALLIC_GLOSS_PROP, texture); - } - - material.SetFloat("_Metallic", 1.0f); - // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. - material.SetFloat("_GlossMapScale", 1.0f); - - // Texture Offset and Scale - var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture); - MaterialFactory.SetTextureOffsetAndScale(material, "_MetallicGlossMap", offset, scale); - } - else - { - material.SetFloat("_Metallic", src.pbrMetallicRoughness.metallicFactor); - material.SetFloat("_Glossiness", 1.0f - src.pbrMetallicRoughness.roughnessFactor); - } - } - - if (src.normalTexture != null && src.normalTexture.index != -1) - { - material.EnableKeyword("_NORMALMAP"); - var param = NormalTexture(parser, src); - var texture = await getTexture(awaitCaller, parser.GLTF, param); - if (texture != null) - { - material.SetTexture(TextureImportParam.NORMAL_PROP, texture); - material.SetFloat("_BumpScale", src.normalTexture.scale); - } - - // Texture Offset and Scale - MaterialFactory.SetTextureOffsetAndScale(material, "_BumpMap", param.Offset, param.Scale); - } - - if (src.occlusionTexture != null && src.occlusionTexture.index != -1) - { - var texture = await getTexture(awaitCaller, parser.GLTF, standardParam); - if (texture != null) - { - material.SetTexture(TextureImportParam.OCCLUSION_PROP, texture); - material.SetFloat("_OcclusionStrength", src.occlusionTexture.strength); - } - - // Texture Offset and Scale - var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.occlusionTexture); - MaterialFactory.SetTextureOffsetAndScale(material, "_OcclusionMap", offset, scale); - } - - if (src.emissiveFactor != null - || (src.emissiveTexture != null && src.emissiveTexture.index != -1)) - { - material.EnableKeyword("_EMISSION"); - material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; - - if (src.emissiveFactor != null && src.emissiveFactor.Length == 3) - { - material.SetColor("_EmissionColor", new Color(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2])); - } - - 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); - if (texture != null) - { - material.SetTexture("_EmissionMap", texture); - } - - // Texture Offset and Scale - - MaterialFactory.SetTextureOffsetAndScale(material, "_EmissionMap", param.Offset, param.Scale); - } - } - - BlendMode blendMode = BlendMode.Opaque; - // https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980 - switch (src.alphaMode) - { - case "BLEND": - blendMode = BlendMode.Fade; - material.SetOverrideTag("RenderType", "Transparent"); - material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); - material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - material.SetInt("_ZWrite", 0); - material.DisableKeyword("_ALPHATEST_ON"); - material.EnableKeyword("_ALPHABLEND_ON"); - material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); - material.renderQueue = 3000; - break; - - case "MASK": - blendMode = BlendMode.Cutout; - material.SetOverrideTag("RenderType", "TransparentCutout"); - material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); - material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); - material.SetInt("_ZWrite", 1); - material.SetFloat("_Cutoff", src.alphaCutoff); - material.EnableKeyword("_ALPHATEST_ON"); - material.DisableKeyword("_ALPHABLEND_ON"); - material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); - material.renderQueue = 2450; - - break; - - default: // OPAQUE - blendMode = BlendMode.Opaque; - material.SetOverrideTag("RenderType", ""); - material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); - material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); - material.SetInt("_ZWrite", 1); - material.DisableKeyword("_ALPHATEST_ON"); - material.DisableKeyword("_ALPHABLEND_ON"); - material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); - material.renderQueue = -1; - break; - } - - material.SetFloat("_Mode", (float)blendMode); - - return material; - } - } -} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs deleted file mode 100644 index 96b4f6d7c..000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs +++ /dev/null @@ -1,80 +0,0 @@ - -using System.Threading.Tasks; -using UnityEngine; - -namespace UniGLTF -{ - public static class UnlitMaterialItem - { - public const string ShaderName = "UniGLTF/UniUnlit"; - - public static async Task CreateAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture, bool hasVertexColor) - { - if (getTexture == null) - { - getTexture = (_x, _y, _z) => Task.FromResult(default); - } - - var src = parser.GLTF.materials[i]; - var material = new Material(Shader.Find(ShaderName)); - material.name = MaterialFactory.MaterialName(i, src); - - // texture - 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)); - - // Texture Offset and Scale - MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", offset, scale); - } - - // color - if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) - { - var color = src.pbrMetallicRoughness.baseColorFactor; - material.color = (new Color(color[0], color[1], color[2], color[3])).gamma; - } - - //renderMode - if (src.alphaMode == "OPAQUE") - { - UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque); - } - else if (src.alphaMode == "BLEND") - { - UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Transparent); - } - else if (src.alphaMode == "MASK") - { - UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Cutout); - material.SetFloat("_Cutoff", src.alphaCutoff); - } - else - { - // default OPAQUE - UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque); - } - - // culling - if (src.doubleSided) - { - UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Off); - } - else - { - UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Back); - } - - // VColor - if (hasVertexColor) - { - UniUnlit.Utils.SetVColBlendMode(material, UniUnlit.UniUnlitVertexColorBlendOp.Multiply); - } - - UniUnlit.Utils.ValidateProperties(material, true); - - return material; - } - } -} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs index 8d6a762c5..42c87fddd 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using UnityEngine; - +using VRMShaders; namespace UniGLTF { 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..c23c4cd93 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UnityEngine; +using VRMShaders; + + +namespace UniGLTF +{ + /// + /// 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/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs.meta similarity index 83% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs.meta index 51b23e00a..fd3606f57 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 14bc3a4ce3e24924a9ae8bb1654a1b7b +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/UniGLTF/Tests/UniGLTF/MaterialTests.cs b/Assets/UniGLTF/Tests/UniGLTF/MaterialTests.cs index aabad09b7..ebbc590e3 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/MaterialTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/MaterialTests.cs @@ -2,6 +2,7 @@ using UnityEngine; using UniJSON; using System.Linq; +using VRMShaders; namespace UniGLTF { @@ -31,12 +32,11 @@ namespace UniGLTF var gltfMaterial = materialExporter.ExportMaterial(srcMaterial, textureManager); gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions = gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions.Deserialize(); - var dstMaterial = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - - Assert.AreEqual(dstMaterial.mainTextureOffset.x, offset.x, 0.3f); - Assert.AreEqual(dstMaterial.mainTextureOffset.y, offset.y, 0.2f); - Assert.AreEqual(dstMaterial.mainTextureScale.x, scale.x, 0.5f); - Assert.AreEqual(dstMaterial.mainTextureScale.y, scale.y, 0.6f); + Assert.IsTrue(glTF_KHR_texture_transform.TryGet(gltfMaterial.pbrMetallicRoughness.baseColorTexture, out glTF_KHR_texture_transform t)); + Assert.AreEqual(t.offset[0], offset.x, 0.3f); + Assert.AreEqual(t.offset[1], offset.y, 0.2f); + Assert.AreEqual(t.scale[0], scale.x, 0.5f); + Assert.AreEqual(t.scale[1], scale.y, 0.6f); } [Test] @@ -79,8 +79,7 @@ namespace UniGLTF Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } } @@ -98,8 +97,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -116,8 +114,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -135,8 +132,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -150,8 +146,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -168,8 +163,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -187,8 +181,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -205,8 +198,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -224,8 +216,7 @@ namespace UniGLTF }, extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } { @@ -234,16 +225,14 @@ namespace UniGLTF { extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(), }; - var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial); - Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name); + Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial)); } } [Test] public void MaterialImportTest() { - var material = MaterialFactory.CreateMaterialForTest(0, new glTFMaterial { }); - Assert.AreEqual("Standard", material.shader.name); + Assert.IsFalse(glTF_KHR_materials_unlit.IsEnable(new glTFMaterial { })); } [Test] diff --git a/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs b/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs index 2828259a4..4ef829449 100644 --- a/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs +++ b/Assets/VRM/Editor/Format/VRMEditorImporterContext.cs @@ -125,7 +125,7 @@ namespace VRM // // convert images(metallic roughness, occlusion map) // - var task = m_context.MaterialFactory.LoadMaterialsAsync(default(ImmediateCaller), m_context.TextureFactory.GetTextureAsync); + var task = m_context.LoadMaterialsAsync(); if (!task.IsCompleted) { throw new Exception(); diff --git a/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs b/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs new file mode 100644 index 000000000..ae6bfaa5b --- /dev/null +++ b/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using UniGLTF; +using UnityEngine; +using VRMShaders; + + +namespace VRM +{ + public class MToonMaterialImporter + { + public static bool TryCreateParam(GltfParser parser, int i, glTF_VRM_Material vrmMaterial, out MaterialImportParam param) + { + if (vrmMaterial.shader == VRM.glTF_VRM_Material.VRM_USE_GLTFSHADER) + { + // fallback to gltf + param = default; + return false; + } + + // + // restore VRM material + // + // use material.name, because material name may renamed in GltfParser. + var name = parser.GLTF.materials[i].name; + param = new MaterialImportParam(name, vrmMaterial.shader); + + param.Actions.Add(material => material.renderQueue = vrmMaterial.renderQueue); + + foreach (var kv in vrmMaterial.floatProperties) + { + param.FloatValues.Add(kv.Key, kv.Value); + } + + var offsetScaleMap = new Dictionary(); + foreach (var kv in vrmMaterial.vectorProperties) + { + if (vrmMaterial.textureProperties.ContainsKey(kv.Key)) + { + // texture offset & scale + offsetScaleMap.Add(kv.Key, kv.Value); + } + else + { + // vector4 + var v = new Vector4(kv.Value[0], kv.Value[1], kv.Value[2], kv.Value[3]); + param.Vectors.Add(kv.Key, v); + } + } + + foreach (var kv in vrmMaterial.textureProperties) + { + var (offset, scale) = (Vector2.zero, Vector2.one); + if (offsetScaleMap.TryGetValue(kv.Key, out float[] value)) + { + offset = new Vector2(value[0], value[1]); + scale = new Vector2(value[2], value[3]); + } + + var textureParam = MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1); + param.TextureSlots.Add(kv.Key, textureParam); + } + + foreach (var kv in vrmMaterial.keywordMap) + { + if (kv.Value) + { + param.Actions.Add(material => material.EnableKeyword(kv.Key)); + } + else + { + param.Actions.Add(material => material.DisableKeyword(kv.Key)); + } + } + + foreach (var kv in vrmMaterial.tagMap) + { + param.Actions.Add(material => material.SetOverrideTag(kv.Key, kv.Value)); + } + + if (vrmMaterial.shader == MToon.Utils.ShaderName) + { + // TODO: Material拡張にMToonの項目が追加されたら旧バージョンのshaderPropから変換をかける + // インポート時にUniVRMに含まれるMToonのバージョンに上書きする + param.FloatValues[MToon.Utils.PropVersion] = MToon.Utils.VersionNumber; + } + + return true; + } + + List m_materials; + public MToonMaterialImporter(List materials) + { + m_materials = materials; + } + + public bool TryCreateParam(GltfParser parser, int i, out MaterialImportParam param) + { + if (TryCreateParam(parser, i, m_materials[i], out param)) + { + return true; + } + + param = default; + return false; + } + } +} diff --git a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs.meta b/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs.meta similarity index 69% rename from Assets/VRM/Runtime/IO/VRMMaterialImporter.cs.meta rename to Assets/VRM/Runtime/IO/MToonMaterialImporter.cs.meta index e5ff70b77..cfac19cb9 100644 --- a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs.meta +++ b/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: 77db57076c0650c469c3ff0d4853ce21 -timeCreated: 1533624711 -licenseType: Free +guid: 35c90d5d3fa706b4f87a92ce4dc59008 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 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/VRM/Runtime/IO/MToonTextureParam.cs.meta b/Assets/VRM/Runtime/IO/MToonTextureParam.cs.meta new file mode 100644 index 000000000..382c9f4ec --- /dev/null +++ b/Assets/VRM/Runtime/IO/MToonTextureParam.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7af3a3bafe41a64db660a18b1c25097 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index e85f9f42b..ef9d9c841 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -26,7 +26,7 @@ namespace VRM { VRM = vrm; // override material importer - MaterialFactory.CreateMaterialAsync = new VRMMaterialImporter(VRM.materialProperties).CreateMaterialAsync; + GltfMaterialImporter.GltfMaterialParamProcessors.Insert(0, new MToonMaterialImporter(VRM.materialProperties).TryCreateParam); } else { @@ -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 deleted file mode 100644 index 29496a5a5..000000000 --- a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System.Collections.Generic; -using UniGLTF; -using UnityEngine; -using System.Linq; -using System; -using System.Threading.Tasks; - -namespace VRM -{ - public static class MToonMaterialItem - { - static string[] VRM_SHADER_NAMES = - { - "Standard", - "VRM/MToon", - "UniGLTF/UniUnlit", - - "VRM/UnlitTexture", - "VRM/UnlitCutout", - "VRM/UnlitTransparent", - "VRM/UnlitTransparentZWrite", - }; - - public static async Task CreateAsync(IAwaitCaller awaitCaller, GltfParser parser, int m_index, glTF_VRM_Material vrmMaterial, GetTextureAsyncFunc getTexture) - { - var item = vrmMaterial; - var shaderName = item.shader; - var shader = Shader.Find(shaderName); - if (shader == null) - { - // - // no shader - // - if (VRM_SHADER_NAMES.Contains(shaderName)) - { - Debug.LogErrorFormat("shader {0} not found. set Assets/VRM/Shaders/VRMShaders to Edit - project setting - Graphics - preloaded shaders", shaderName); - } - else - { - // #if VRM_DEVELOP - // Debug.LogWarningFormat("unknown shader {0}.", shaderName); - // #endif - } - return await MaterialFactory.DefaultCreateMaterialAsync(awaitCaller, parser, m_index, getTexture); - } - - // - // restore VRM material - // - var material = new Material(shader); - // use material.name, because material name may renamed in GltfParser. - material.name = parser.GLTF.materials[m_index].name; - material.renderQueue = item.renderQueue; - - foreach (var kv in item.floatProperties) - { - material.SetFloat(kv.Key, kv.Value); - } - - var offsetScaleMap = new Dictionary(); - foreach (var kv in item.vectorProperties) - { - if (item.textureProperties.ContainsKey(kv.Key)) - { - // texture offset & scale - offsetScaleMap.Add(kv.Key, kv.Value); - } - else - { - // vector4 - var v = new Vector4(kv.Value[0], kv.Value[1], kv.Value[2], kv.Value[3]); - material.SetVector(kv.Key, v); - } - } - - foreach (var kv in item.textureProperties) - { - var (offset, scale) = (Vector2.zero, Vector2.one); - if (offsetScaleMap.TryGetValue(kv.Key, out float[] value)) - { - offset = new Vector2(value[0], value[1]); - 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); - if (texture != null) - { - material.SetTexture(kv.Key, texture); - MaterialFactory.SetTextureOffsetAndScale(material, kv.Key, offset, scale); - } - } - foreach (var kv in item.keywordMap) - { - if (kv.Value) - { - material.EnableKeyword(kv.Key); - } - else - { - material.DisableKeyword(kv.Key); - } - } - foreach (var kv in item.tagMap) - { - material.SetOverrideTag(kv.Key, kv.Value); - } - - if (shaderName == MToon.Utils.ShaderName) - { - // TODO: Material拡張にMToonの項目が追加されたら旧バージョンのshaderPropから変換をかける - // インポート時にUniVRMに含まれるMToonのバージョンに上書きする - material.SetFloat(MToon.Utils.PropVersion, MToon.Utils.VersionNumber); - } - - return material; - } - } - - public class VRMMaterialImporter - { - List m_materials; - public VRMMaterialImporter(List materials) - { - m_materials = materials; - } - - public Task CreateMaterialAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture) - { - if (i == 0 && m_materials.Count == 0) - { - // dummy - return MaterialFactory.DefaultCreateMaterialAsync(awaitCaller, parser, i, getTexture); - } - - return MToonMaterialItem.CreateAsync(awaitCaller, parser, i, m_materials[i], getTexture); - } - } -} 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/VRM/Tests/MToonTest.cs b/Assets/VRM/Tests/MToonTest.cs index 39daa4caf..551b29e5b 100644 --- a/Assets/VRM/Tests/MToonTest.cs +++ b/Assets/VRM/Tests/MToonTest.cs @@ -29,7 +29,7 @@ namespace VRM var vrmMaterial = VRMMaterialExporter.CreateFromMaterial(srcMaterial, textureManager); Assert.AreEqual(vrmMaterial.vectorProperties["_MainTex"], new float[]{0.3f, 0.2f, 0.5f, 0.6f}); - var materialImporter = new VRMMaterialImporter(new System.Collections.Generic.List{ vrmMaterial }); + var materialImporter = new MToonMaterialImporter(new System.Collections.Generic.List{ vrmMaterial }); } } } diff --git a/Assets/VRMShaders/Runtime/MaterialFactory.cs b/Assets/VRMShaders/Runtime/MaterialFactory.cs new file mode 100644 index 000000000..8ef4afe1b --- /dev/null +++ b/Assets/VRMShaders/Runtime/MaterialFactory.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UnityEngine; + + +namespace VRMShaders +{ + public delegate Task GetTextureAsyncFunc(TextureImportParam param); + + public class MaterialFactory : IDisposable + { + Dictionary m_externalMap; + + public MaterialFactory(IEnumerable<(string, UnityEngine.Object)> externalMap) + { + if (externalMap == null) + { + externalMap = Enumerable.Empty<(string, UnityEngine.Object)>(); + } + m_externalMap = externalMap + .Select(kv => (kv.Item1, kv.Item2 as Material)) + .Where(kv => kv.Item2 != null) + .ToDictionary(kv => kv.Item1, kv => kv.Item2) + ; + } + + public struct MaterialLoadInfo + { + public readonly Material Asset; + public readonly bool UseExternal; + + public bool IsSubAsset => !UseExternal; + + public MaterialLoadInfo(Material asset, bool useExternal) + { + Asset = asset; + UseExternal = useExternal; + } + } + + List m_materials = new List(); + public IReadOnlyList Materials => m_materials; + void Remove(Material material) + { + var index = m_materials.FindIndex(x => x.Asset == material); + if (index >= 0) + { + m_materials.RemoveAt(index); + + } + } + + public void Dispose() + { + foreach (var x in m_materials) + { + if (!x.UseExternal) + { + // 外部の '.asset' からロードしていない +#if VRM_DEVELOP + // Debug.Log($"Destroy {x.Asset}"); +#endif + UnityEngine.Object.DestroyImmediate(x.Asset, false); + } + } + } + + /// + /// 所有権(Dispose権)を移譲する + /// + /// 所有権を移動する関数。 + /// + /// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる + /// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる + /// + /// + /// + public void TransferOwnership(Func take) + { + var list = new List(); + foreach (var x in m_materials) + { + if (!x.UseExternal) + { + // 外部の '.asset' からロードしていない + if (take(x.Asset)) + { + list.Add(x.Asset); + } + } + } + foreach (var x in list) + { + Remove(x); + } + } + + public Material GetMaterial(int index) + { + if (index < 0) return null; + if (index >= m_materials.Count) return null; + return m_materials[index].Asset; + } + + public async Task LoadAsync(MaterialImportParam param, GetTextureAsyncFunc getTexture) + { + if (m_externalMap.TryGetValue(param.Name, out Material material)) + { + m_materials.Add(new MaterialLoadInfo(material, true)); + return material; + } + + if (getTexture == null) + { + getTexture = (_) => Task.FromResult(null); + } + + material = new Material(Shader.Find(param.ShaderName)); + material.name = param.Name; + + foreach(var kv in param.TextureSlots) + { + var texture = await getTexture(kv.Value); + if(texture!=null){ + material.SetTexture(kv.Key, texture); + SetTextureOffsetAndScale(material, kv.Key, kv.Value.Offset, kv.Value.Scale); + } + } + + foreach(var kv in param.Colors) + { + material.SetColor(kv.Key, kv.Value); + } + + foreach(var kv in param.Vectors) + { + material.SetVector(kv.Key, kv.Value); + } + + foreach(var kv in param.FloatValues) + { + material.SetFloat(kv.Key, kv.Value); + } + + foreach(var action in param.Actions) + { + action(material); + } + + m_materials.Add(new MaterialLoadInfo(material, false)); + + return material; + } + + public static void SetTextureOffsetAndScale(Material material, string propertyName, Vector2 offset, Vector2 scale) + { + material.SetTextureOffset(propertyName, offset); + material.SetTextureScale(propertyName, scale); + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs.meta b/Assets/VRMShaders/Runtime/MaterialFactory.cs.meta similarity index 100% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs.meta rename to Assets/VRMShaders/Runtime/MaterialFactory.cs.meta diff --git a/Assets/VRMShaders/Runtime/MaterialImportParam.cs b/Assets/VRMShaders/Runtime/MaterialImportParam.cs new file mode 100644 index 000000000..b0676f804 --- /dev/null +++ b/Assets/VRMShaders/Runtime/MaterialImportParam.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + + +namespace VRMShaders +{ + public class MaterialImportParam + { + public readonly string Name; + public readonly string ShaderName; + public readonly Dictionary TextureSlots = new Dictionary(); + public readonly Dictionary FloatValues = new Dictionary(); + public readonly Dictionary Colors = new Dictionary(); + public readonly Dictionary Vectors = new Dictionary(); + public readonly List> Actions = new List>(); + + public MaterialImportParam(string name, string shaderName) + { + Name = name; + ShaderName = shaderName; + } + } +} diff --git a/Assets/VRMShaders/Runtime/MaterialImportParam.cs.meta b/Assets/VRMShaders/Runtime/MaterialImportParam.cs.meta new file mode 100644 index 000000000..6f9e21a90 --- /dev/null +++ b/Assets/VRMShaders/Runtime/MaterialImportParam.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0844821341efaf644b91bff72f813a2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: 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