diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs new file mode 100644 index 000000000..cd285f2b6 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF +{ + public interface IMaterialValidator + { + /// + /// shaderName から glTF マテリアルタイプ を得る + /// + /// shaderName が エクスポートできるものでないときは null を返す(gltfデフォルトの pbr として処理される) + /// + /// + /// + string GetGltfMaterialTypeFromUnityShaderName(string shaderName); + + /// + /// テクスチャーを使うプロパティを列挙する + /// + /// + /// + /// + IEnumerable<(string propertyName, Texture texture)> EnumerateTextureProperties(Material m); + } + + public class DefaultMaterialValidator : IMaterialValidator + { + public virtual string GetGltfMaterialTypeFromUnityShaderName(string shaderName) + { + if (shaderName == "Standard") + { + return "pbr"; + } + if (MaterialExporter.IsUnlit(shaderName)) + { + return "unlit"; + } + return null; + } + + public virtual IEnumerable<(string propertyName, Texture texture)> EnumerateTextureProperties(Material m) + { + // main color + yield return (MaterialExporter.COLOR_TEXTURE_PROP, m.GetTexture(MaterialExporter.COLOR_TEXTURE_PROP)); + + if (GetGltfMaterialTypeFromUnityShaderName(m.shader.name) == "unlit") + { + yield break; + } + + // PBR + yield return (MaterialExporter.METALLIC_TEX_PROP, m.GetTexture(MaterialExporter.METALLIC_TEX_PROP)); + yield return (MaterialExporter.NORMAL_TEX_PROP, m.GetTexture(MaterialExporter.NORMAL_TEX_PROP)); + yield return (MaterialExporter.EMISSION_TEX_PROP, m.GetTexture(MaterialExporter.EMISSION_TEX_PROP)); + yield return (MaterialExporter.OCCLUSION_TEX_PROP, m.GetTexture(MaterialExporter.OCCLUSION_TEX_PROP)); + } + } +} diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs.meta new file mode 100644 index 000000000..d46f5c32a --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ba5723a5618eac438268641047d9549 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs index d3d94dc76..976a39ff4 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using UniGLTF.M17N; +using UnityEditor; using UnityEngine; namespace UniGLTF @@ -27,37 +27,24 @@ namespace UniGLTF return null; } - public List Meshes = new List(); + public MeshExportList Meshes = new MeshExportList(); public int ExpectedExportByteSize => Meshes.Where(x => x.IsRendererActive).Sum(x => x.ExportByteSize); public void SetRoot(GameObject ExportRoot, GltfExportSettings settings, IBlendShapeExportFilter blendShapeFilter) { - if(ExportRoot==null) + if (ExportRoot == null) { return; } - MeshExportInfo.GetInfo(ExportRoot.transform.Traverse().Skip(1), Meshes, settings); - foreach(var info in Meshes) + Meshes.GetInfo(ExportRoot.transform.Traverse().Skip(1), settings); + foreach (var info in Meshes) { info.CalcMeshSize(ExportRoot, info.Renderers[0].Item1, settings, blendShapeFilter); } } - public Func GltfMaterialFromUnityShaderName = DefaultGltfMaterialType; - - public static string DefaultGltfMaterialType(string shaderName) - { - if (shaderName == "Standard") - { - return "pbr"; - } - if (MaterialExporter.IsUnlit(shaderName)) - { - return "unlit"; - } - return null; - } + public IMaterialValidator MaterialValidator = new DefaultMaterialValidator(); public enum Messages { @@ -93,20 +80,47 @@ namespace UniGLTF } } - foreach (var m in Meshes.SelectMany(x => x.Materials).Distinct()) + foreach (var m in Meshes.GetUniqueMaterials()) { - if (m == null) - { - continue; - } - var gltfMaterial = GltfMaterialFromUnityShaderName(m.shader.name); + var gltfMaterial = MaterialValidator.GetGltfMaterialTypeFromUnityShaderName(m.shader.name); if (string.IsNullOrEmpty(gltfMaterial)) { yield return Validation.Warning($"{m}: unknown shader: {m.shader.name} => export as gltf default"); } - } - yield break; + var used = new HashSet(); + foreach (var (propName, texture) in MaterialValidator.EnumerateTextureProperties(m)) + { + if (texture == null) + { + continue; + } + var assetPath = AssetDatabase.GetAssetPath(texture); + if (!string.IsNullOrEmpty(assetPath)) + { + if (AssetImporter.GetAtPath(assetPath) is TextureImporter textureImporter) + { + switch (textureImporter.textureType) + { + case TextureImporterType.Default: + case TextureImporterType.NormalMap: + break; + + default: + // EditorTextureSerializer throw Exception + // エクスポート未実装 + if (used.Add(texture)) + { + yield return Validation.Error($"{texture}: unknown texture type: {textureImporter.textureType}", ValidationContext.Create(texture)); + } + break; + } + } + } + } + + yield break; + } } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs index 8711d43e4..14a14cec3 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs @@ -30,6 +30,12 @@ namespace UniGLTF return material; } + public const string COLOR_TEXTURE_PROP = "_MainTex"; + public const string METALLIC_TEX_PROP = "_MetallicGlossMap"; + public const string NORMAL_TEX_PROP = "_BumpMap"; + public const string EMISSION_TEX_PROP = "_EmissionMap"; + public const string OCCLUSION_TEX_PROP = "_OcclusionMap"; + static void Export_Color(Material m, ITextureExporter textureManager, glTFMaterial material) { if (m.HasProperty("_Color")) @@ -37,12 +43,12 @@ namespace UniGLTF material.pbrMetallicRoughness.baseColorFactor = m.GetColor("_Color").ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); } - if (m.HasProperty("_MainTex")) + if (m.HasProperty(COLOR_TEXTURE_PROP)) { // Don't export alpha channel if material was OPAQUE var unnecessaryAlpha = string.Equals(material.alphaMode, "OPAQUE", StringComparison.Ordinal); - var index = textureManager.RegisterExportingAsSRgb(m.GetTexture("_MainTex"), !unnecessaryAlpha); + var index = textureManager.RegisterExportingAsSRgb(m.GetTexture(COLOR_TEXTURE_PROP), !unnecessaryAlpha); if (index != -1) { material.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() @@ -67,20 +73,20 @@ namespace UniGLTF float smoothness = 1.0f; var textuerNames = m.GetTexturePropertyNames(); - if (textuerNames.Contains("_MetallicGlossMap")) + if (textuerNames.Contains(METALLIC_TEX_PROP)) { if (m.HasProperty("_GlossMapScale")) { smoothness = m.GetFloat("_GlossMapScale"); } - metallicSmoothTexture = m.GetTexture("_MetallicGlossMap"); + metallicSmoothTexture = m.GetTexture(METALLIC_TEX_PROP); } Texture occlusionTexture = default; var occlusionStrength = 1.0f; - if (textuerNames.Contains("_OcclusionMap")) + if (textuerNames.Contains(OCCLUSION_TEX_PROP)) { - occlusionTexture = m.GetTexture("_OcclusionMap"); + occlusionTexture = m.GetTexture(OCCLUSION_TEX_PROP); if (occlusionTexture != null && m.HasProperty("_OcclusionStrength")) { occlusionStrength = m.GetFloat("_OcclusionStrength"); @@ -128,9 +134,9 @@ namespace UniGLTF static void Export_Normal(Material m, ITextureExporter textureExporter, glTFMaterial material) { - if (m.HasProperty("_BumpMap")) + if (m.HasProperty(NORMAL_TEX_PROP)) { - var index = textureExporter.RegisterExportingAsNormal(m.GetTexture("_BumpMap")); + var index = textureExporter.RegisterExportingAsNormal(m.GetTexture(NORMAL_TEX_PROP)); if (index != -1) { material.normalTexture = new glTFMaterialNormalTextureInfo() @@ -174,9 +180,9 @@ namespace UniGLTF material.emissiveFactor = color.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); } - if (m.HasProperty("_EmissionMap")) + if (m.HasProperty(EMISSION_TEX_PROP)) { - var index = textureExporter.RegisterExportingAsSRgb(m.GetTexture("_EmissionMap"), needsAlpha: false); + var index = textureExporter.RegisterExportingAsSRgb(m.GetTexture(EMISSION_TEX_PROP), needsAlpha: false); if (index != -1) { material.emissiveTexture = new glTFMaterialEmissiveTextureInfo() @@ -191,7 +197,7 @@ namespace UniGLTF static void Export_MainTextureTransform(Material m, glTFTextureInfo textureInfo) { - Export_TextureTransform(m, textureInfo, "_MainTex"); + Export_TextureTransform(m, textureInfo, COLOR_TEXTURE_PROP); } static void Export_TextureTransform(Material m, glTFTextureInfo textureInfo, string propertyName) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs index 1e768fa08..0a52c8c29 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; @@ -50,7 +51,7 @@ namespace UniGLTF } } - public static bool TryGetSameMeshIndex(List meshWithRenderers, Mesh mesh, Material[] materials, out int meshIndex) + public static bool TryGetSameMeshIndex(IReadOnlyList meshWithRenderers, Mesh mesh, Material[] materials, out int meshIndex) { for (var i = 0; i < meshWithRenderers.Count; i++) { @@ -183,7 +184,7 @@ namespace UniGLTF public string Summary; #endregion - MeshExportInfo(Renderer renderer, GltfExportSettings settings) + public MeshExportInfo(Renderer renderer, GltfExportSettings settings) { if (renderer == null) { @@ -220,7 +221,7 @@ namespace UniGLTF PushRenderer(renderer); } - void PushRenderer(Renderer renderer) + public void PushRenderer(Renderer renderer) { if (renderer is SkinnedMeshRenderer smr) { @@ -261,53 +262,12 @@ namespace UniGLTF } } - public static MeshExportInfo Create(GameObject go) - { - var list = new List(); - GetInfo(go.transform.Traverse(), list, new GltfExportSettings()); - return list[0]; - } - - /// - /// ヒエラルキーからエクスポートする Mesh の情報を収集する - /// - /// - /// - /// - /// blendShape の export を filtering する - public static void GetInfo(IEnumerable nodes, List list, GltfExportSettings settings) - { - list.Clear(); - foreach (var node in nodes) - { - var renderer = node.GetComponent(); - if (renderer == null) - { - continue; - } - - var found = list.FirstOrDefault(x => x.IsSameMeshAndMaterials(renderer)); - if (found != null) - { - found.PushRenderer(renderer); - continue; - } - - var info = new MeshExportInfo(renderer, settings); - if (info.Mesh != null) - { - list.Add(info); - } - } - } - static bool TryGetMeshInfo() { return true; } - public void CalcMeshSize( GameObject root, Renderer renderer, @@ -409,4 +369,68 @@ namespace UniGLTF Summary = sb.ToString(); } } + + public class MeshExportList : IReadOnlyList + { + List m_list = new List(); + + public int Count => m_list.Count; + + public MeshExportInfo this[int index] => m_list[index]; + + public IEnumerator GetEnumerator() + { + return m_list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerable GetUniqueMaterials() + { + return m_list.SelectMany(x => x.Materials).Where(x => x != null).Distinct(); + } + + /// + /// ヒエラルキーからエクスポートする Mesh の情報を収集する + /// + /// + /// + /// + /// blendShape の export を filtering する + public void GetInfo(IEnumerable nodes, GltfExportSettings settings) + { + m_list.Clear(); + foreach (var node in nodes) + { + var renderer = node.GetComponent(); + if (renderer == null) + { + continue; + } + + var found = m_list.FirstOrDefault(x => x.IsSameMeshAndMaterials(renderer)); + if (found != null) + { + found.PushRenderer(renderer); + continue; + } + + var info = new MeshExportInfo(renderer, settings); + if (info.Mesh != null) + { + m_list.Add(info); + } + } + } + + public static MeshExportInfo Create(GameObject go) + { + var list = new MeshExportList(); + list.GetInfo(go.transform.Traverse(), new GltfExportSettings()); + return list.m_list[0]; + } + } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index 203fa6a97..0a9f650be 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -142,7 +142,7 @@ namespace UniGLTF } #region Export - static glTFNode ExportNode(Transform x, List nodes, List meshWithRenderers, List skins) + static glTFNode ExportNode(Transform x, List nodes, IReadOnlyList meshWithRenderers, List skins) { var node = new glTFNode { @@ -231,11 +231,11 @@ namespace UniGLTF .Skip(1) // exclude root object for the symmetry with the importer .ToList(); - var uniqueUnityMeshes = new List(); - MeshExportInfo.GetInfo(Nodes, uniqueUnityMeshes, meshExportSettings); + var uniqueUnityMeshes = new MeshExportList(); + uniqueUnityMeshes.GetInfo(Nodes, meshExportSettings); #region Materials and Textures - Materials = uniqueUnityMeshes.SelectMany(x => x.Materials).Where(x => x != null).Distinct().ToList(); + Materials = uniqueUnityMeshes.GetUniqueMaterials().ToList(); m_textureExporter = new TextureExporter(textureSerializer); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Validation/Validation.cs b/Assets/UniGLTF/Runtime/UniGLTF/Validation/Validation.cs index b6fa5ad92..be438bf3a 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Validation/Validation.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Validation/Validation.cs @@ -32,14 +32,14 @@ namespace UniGLTF /// Messageの発生個所にジャンプするための情報 /// public Type Type; - public UnityEngine.Component Context; + public UnityEngine.Object Context; /// /// DrawGUIから呼び出す。追加のGUIボタンなどを実装する /// public Action Extended; - public static ValidationContext Create(T c) where T : UnityEngine.Component + public static ValidationContext Create(T c) where T : UnityEngine.Object { return new ValidationContext { diff --git a/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs b/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs index dcfb007f3..d7f7a63b7 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs @@ -134,7 +134,7 @@ namespace UniGLTF }; var axisInverter = Axes.X.Create(); - var unityMesh = MeshExportInfo.Create(go); + var unityMesh = MeshExportList.Create(go); var (gltfMesh, blendShapeIndexMap) = meshExportSettings.DivideVertexBuffer ? MeshExporter_DividedVertexBuffer.Export(glTF, bufferIndex, unityMesh, Materials, axisInverter, meshExportSettings) : MeshExporter_SharedVertexBuffer.Export(glTF, bufferIndex, unityMesh, Materials,axisInverter, meshExportSettings) @@ -182,7 +182,7 @@ namespace UniGLTF }; var axisInverter = Axes.X.Create(); - var unityMesh = MeshExportInfo.Create(go); + var unityMesh = MeshExportList.Create(go); var (gltfMesh, blendShapeIndexMap) = meshExportSettings.DivideVertexBuffer ? MeshExporter_DividedVertexBuffer.Export(glTF, bufferIndex, unityMesh, Materials, axisInverter, meshExportSettings) : MeshExporter_SharedVertexBuffer.Export(glTF, bufferIndex, unityMesh, Materials,axisInverter, meshExportSettings) diff --git a/Assets/VRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/Editor/Format/VRMExporterWizard.cs index 2861af0c6..db6b5a9d6 100644 --- a/Assets/VRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/Editor/Format/VRMExporterWizard.cs @@ -124,14 +124,40 @@ namespace VRM m_meshes = null; } - static string GltfMaterialFromUnityShaderName(string shaderName) + /// + /// VRM0 + /// + class VRMMaterialValidator : DefaultMaterialValidator { - var name = VRMMaterialExporter.VrmMaterialName(shaderName); - if (!string.IsNullOrEmpty(name)) + public override string GetGltfMaterialTypeFromUnityShaderName(string shaderName) { - return name; + var name = VRMMaterialExporter.VrmMaterialName(shaderName); + if (!string.IsNullOrEmpty(name)) + { + return name; + } + return base.GetGltfMaterialTypeFromUnityShaderName(shaderName); + } + + public override IEnumerable<(string propertyName, Texture texture)> EnumerateTextureProperties(Material m) + { + if (m.shader.name != "VRM/MToon") + { + foreach (var x in base.EnumerateTextureProperties(m)) + { + yield return x; + } + } + + var prop = UniGLTF.ShaderPropExporter.PreShaderPropExporter.GetPropsForSupportedShader(m.shader.name); + foreach (var kv in prop.Properties) + { + if (kv.ShaderPropertyType == UniGLTF.ShaderPropExporter.ShaderPropertyType.TexEnv) + { + yield return (kv.Key, m.GetTexture(kv.Key)); + } + } } - return MeshExportValidator.DefaultGltfMaterialType(shaderName); } protected override IEnumerable ValidatorFactory() @@ -145,7 +171,7 @@ namespace VRM } // Mesh/Renderer のチェック - m_meshes.GltfMaterialFromUnityShaderName = GltfMaterialFromUnityShaderName; + m_meshes.MaterialValidator = new VRMMaterialValidator(); yield return m_meshes.Validate; // Humanoid のチェック diff --git a/Assets/VRM/Editor/VRM.Editor.asmdef b/Assets/VRM/Editor/VRM.Editor.asmdef index ebcd2e1c1..38a926c9d 100644 --- a/Assets/VRM/Editor/VRM.Editor.asmdef +++ b/Assets/VRM/Editor/VRM.Editor.asmdef @@ -6,7 +6,8 @@ "VRMShaders.GLTF.IO.Runtime", "VRMShaders.GLTF.IO.Editor", "UniGLTF", - "UniGLTF.Editor" + "UniGLTF.Editor", + "VRMShaders.VRM.IO.Runtime" ], "optionalUnityReferences": [], "includePlatforms": [