From 2c3ec107ecfd3144960ed94aaf2661817f2aa5a8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 29 Mar 2021 14:35:30 +0900 Subject: [PATCH] MaterialImportParam --- .../Runtime/UniGLTF/IO/ImporterContext.cs | 24 +- .../IO/MaterialIO/GltfMaterialImporter.cs | 99 +++++++ ...m.cs.meta => GltfMaterialImporter.cs.meta} | 2 +- .../UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs | 213 +++++++++++++++ ...alItem.cs.meta => GltfPBRMaterial.cs.meta} | 0 .../IO/MaterialIO/GltfTextureEnumerator.cs | 8 +- .../IO/MaterialIO/GltfUnlitMaterial.cs | 88 +++++++ .../IO/MaterialIO/GltfUnlitMaterial.cs.meta} | 5 +- .../UniGLTF/IO/MaterialIO/MaterialFactory.cs | 246 ------------------ .../UniGLTF/IO/MaterialIO/PBRMaterialItem.cs | 244 ----------------- .../IO/MaterialIO/UnlitMaterialItem.cs | 80 ------ .../Runtime/UniGLTF/IO/MeshImporter.cs | 2 +- .../IO/TextureIO/GltfTextureImporter.cs | 2 - Assets/UniGLTF/Tests/UniGLTF/MaterialTests.cs | 45 ++-- .../Editor/Format/VRMEditorImporterContext.cs | 2 +- .../VRM/Runtime/IO/MToonMaterialImporter.cs | 107 ++++++++ .../Runtime/IO/MToonMaterialImporter.cs.meta | 11 + Assets/VRM/Runtime/IO/VRMImporterContext.cs | 2 +- Assets/VRM/Runtime/IO/VRMMaterialImporter.cs | 139 ---------- Assets/VRM/Tests/MToonTest.cs | 2 +- Assets/VRMShaders/Runtime/MaterialFactory.cs | 163 ++++++++++++ .../Runtime}/MaterialFactory.cs.meta | 0 .../VRMShaders/Runtime/MaterialImportParam.cs | 24 ++ .../Runtime/MaterialImportParam.cs.meta | 11 + 24 files changed, 766 insertions(+), 753 deletions(-) create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs rename Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/{UnlitMaterialItem.cs.meta => GltfMaterialImporter.cs.meta} (83%) create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPBRMaterial.cs rename Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/{PBRMaterialItem.cs.meta => GltfPBRMaterial.cs.meta} (100%) create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs rename Assets/{VRM/Runtime/IO/VRMMaterialImporter.cs.meta => UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta} (69%) delete mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs delete mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/PBRMaterialItem.cs delete mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs create mode 100644 Assets/VRM/Runtime/IO/MToonMaterialImporter.cs create mode 100644 Assets/VRM/Runtime/IO/MToonMaterialImporter.cs.meta delete mode 100644 Assets/VRM/Runtime/IO/VRMMaterialImporter.cs create mode 100644 Assets/VRMShaders/Runtime/MaterialFactory.cs rename Assets/{UniGLTF/Runtime/UniGLTF/IO/MaterialIO => VRMShaders/Runtime}/MaterialFactory.cs.meta (100%) create mode 100644 Assets/VRMShaders/Runtime/MaterialImportParam.cs create mode 100644 Assets/VRMShaders/Runtime/MaterialImportParam.cs.meta diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index d4a77b18e..5f7d6422b 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -36,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; @@ -46,7 +48,7 @@ namespace UniGLTF { m_parser = parser; m_textureFactory = new TextureFactory(externalObjectMap); - m_materialFactory = new MaterialFactory(m_parser, externalObjectMap); + m_materialFactory = new MaterialFactory(externalObjectMap); } #region Source @@ -111,7 +113,7 @@ namespace UniGLTF using (MeasureTime("LoadMaterials")) { - await m_materialFactory.LoadMaterialsAsync(m_awaitCaller, m_textureFactory.GetTextureAsync); + await LoadMaterialsAsync(); } var meshImporter = new MeshImporter(); @@ -171,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 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/MaterialIO/UnlitMaterialItem.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs.meta similarity index 83% rename from Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs.meta index 51b23e00a..31b02ec38 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/UnlitMaterialItem.cs.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImporter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 14bc3a4ce3e24924a9ae8bb1654a1b7b +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 5eff6a21c..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); + 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/VRMMaterialImporter.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta similarity index 69% rename from Assets/VRM/Runtime/IO/VRMMaterialImporter.cs.meta rename to Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta index e5ff70b77..c3911e8da 100644 --- a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterial.cs.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: 77db57076c0650c469c3ff0d4853ce21 -timeCreated: 1533624711 -licenseType: Free +guid: f9748317ec6964a47b0a1c4150fe62e8 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 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 322a4f04b..000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialFactory.cs +++ /dev/null @@ -1,246 +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権)を移譲する - /// - /// 所有権を移動する関数。 - /// - /// * 所有権が移動する。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 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 9cb3827f3..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 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) = MaterialFactory.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) = MaterialFactory.GetTextureOffsetAndScale(src.normalTexture); - 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 = (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(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(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(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(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 = GltfTextureImporter.CreateSRGB(parser, src.emissiveTexture.index, offset, scale); - var texture = await getTexture(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 42cb2e67c..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 = (_) => 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(GltfTextureImporter.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 248798737..fe0d1d278 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/TextureIO/GltfTextureImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs index 5f6ee9521..c23c4cd93 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs @@ -8,8 +8,6 @@ using VRMShaders; namespace UniGLTF { - public delegate Task GetTextureAsyncFunc(TextureImportParam param); - /// /// glTFTexture を TextureImportParam に変換する /// 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/MToonMaterialImporter.cs.meta b/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs.meta new file mode 100644 index 000000000..cfac19cb9 --- /dev/null +++ b/Assets/VRM/Runtime/IO/MToonMaterialImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35c90d5d3fa706b4f87a92ce4dc59008 +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 9fe29dbad..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 { diff --git a/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs b/Assets/VRM/Runtime/IO/VRMMaterialImporter.cs deleted file mode 100644 index 38e45ee1c..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 = MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1); - var texture = await getTexture(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/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: