Merge pull request #1102 from ousttrue/feature/material_validator

EditorTextureSerializer で例外になるテクスチャを事前にエラーメッセージにする
This commit is contained in:
ousttrue
2021-07-19 12:02:21 +09:00
committed by GitHub
10 changed files with 237 additions and 97 deletions

View File

@@ -0,0 +1,58 @@
using System.Collections.Generic;
using UnityEngine;
namespace UniGLTF
{
public interface IMaterialValidator
{
/// <summary>
/// shaderName から glTF マテリアルタイプ を得る
///
/// shaderName が エクスポートできるものでないときは null を返す(gltfデフォルトの pbr として処理される)
/// </summary>
/// <param name="shaderName"></param>
/// <returns></returns>
string GetGltfMaterialTypeFromUnityShaderName(string shaderName);
/// <summary>
/// テクスチャーを使うプロパティを列挙する
/// </summary>
/// <param name="propertyName"></param>
/// <param name="m"></param>
/// <returns></returns>
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));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ba5723a5618eac438268641047d9549
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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<MeshExportInfo> Meshes = new List<MeshExportInfo>();
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<string, string> 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<Texture>();
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;
}
}
}
}

View File

@@ -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)

View File

@@ -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<MeshExportInfo> meshWithRenderers, Mesh mesh, Material[] materials, out int meshIndex)
public static bool TryGetSameMeshIndex(IReadOnlyList<MeshExportInfo> 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<MeshExportInfo>();
GetInfo(go.transform.Traverse(), list, new GltfExportSettings());
return list[0];
}
/// <summary>
/// ヒエラルキーからエクスポートする Mesh の情報を収集する
/// </summary>
/// <param name="root"></param>
/// <param name="list"></param>
/// <param name="settings"></param>
/// <param name="blendShapeFilter"> blendShape の export を filtering する </param>
public static void GetInfo(IEnumerable<Transform> nodes, List<MeshExportInfo> list, GltfExportSettings settings)
{
list.Clear();
foreach (var node in nodes)
{
var renderer = node.GetComponent<Renderer>();
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<MeshExportInfo>
{
List<MeshExportInfo> m_list = new List<MeshExportInfo>();
public int Count => m_list.Count;
public MeshExportInfo this[int index] => m_list[index];
public IEnumerator<MeshExportInfo> GetEnumerator()
{
return m_list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerable<Material> GetUniqueMaterials()
{
return m_list.SelectMany(x => x.Materials).Where(x => x != null).Distinct();
}
/// <summary>
/// ヒエラルキーからエクスポートする Mesh の情報を収集する
/// </summary>
/// <param name="root"></param>
/// <param name="list"></param>
/// <param name="settings"></param>
/// <param name="blendShapeFilter"> blendShape の export を filtering する </param>
public void GetInfo(IEnumerable<Transform> nodes, GltfExportSettings settings)
{
m_list.Clear();
foreach (var node in nodes)
{
var renderer = node.GetComponent<Renderer>();
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];
}
}
}

View File

@@ -142,7 +142,7 @@ namespace UniGLTF
}
#region Export
static glTFNode ExportNode(Transform x, List<Transform> nodes, List<MeshExportInfo> meshWithRenderers, List<SkinnedMeshRenderer> skins)
static glTFNode ExportNode(Transform x, List<Transform> nodes, IReadOnlyList<MeshExportInfo> meshWithRenderers, List<SkinnedMeshRenderer> 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>();
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);

View File

@@ -32,14 +32,14 @@ namespace UniGLTF
/// Messageの発生個所にジャンプするための情報
/// </summary>
public Type Type;
public UnityEngine.Component Context;
public UnityEngine.Object Context;
/// <summary>
/// DrawGUIから呼び出す。追加のGUIボタンなどを実装する
/// </summary>
public Action Extended;
public static ValidationContext Create<T>(T c) where T : UnityEngine.Component
public static ValidationContext Create<T>(T c) where T : UnityEngine.Object
{
return new ValidationContext
{

View File

@@ -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)

View File

@@ -124,14 +124,40 @@ namespace VRM
m_meshes = null;
}
static string GltfMaterialFromUnityShaderName(string shaderName)
/// <summary>
/// VRM0
/// </summary>
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<Validator> ValidatorFactory()
@@ -145,7 +171,7 @@ namespace VRM
}
// Mesh/Renderer のチェック
m_meshes.GltfMaterialFromUnityShaderName = GltfMaterialFromUnityShaderName;
m_meshes.MaterialValidator = new VRMMaterialValidator();
yield return m_meshes.Validate;
// Humanoid のチェック

View File

@@ -6,7 +6,8 @@
"VRMShaders.GLTF.IO.Runtime",
"VRMShaders.GLTF.IO.Editor",
"UniGLTF",
"UniGLTF.Editor"
"UniGLTF.Editor",
"VRMShaders.VRM.IO.Runtime"
],
"optionalUnityReferences": [],
"includePlatforms": [