Merge pull request #1005 from ousttrue/fix/mesh_export_info

MeshWithRenderer を MeshExportInfo に統合
This commit is contained in:
ousttrue
2021-06-03 21:11:53 +09:00
committed by GitHub
22 changed files with 494 additions and 418 deletions

View File

@@ -1,18 +0,0 @@
using System.Linq;
using UnityEngine;
namespace UniGLTF
{
public static class ExporterExtensions
{
public static bool EnableForExport(this Component mono)
{
if (mono.transform.Ancestors().Any(x => !x.gameObject.activeSelf))
{
// 自分か祖先に !activeSelf がいる
return false;
}
return true;
}
}
}

View File

@@ -73,7 +73,7 @@ namespace UniGLTF
protected override void OnLayout()
{
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings);
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings, new DefualtBlendShapeExportFilter());
}
protected override bool DoGUI(bool isValid)

View File

@@ -31,148 +31,12 @@ namespace UniGLTF
public int ExpectedExportByteSize => Meshes.Where(x => x.IsRendererActive).Sum(x => x.ExportByteSize);
public MeshExportSettings Settings;
public virtual bool UseBlendShape(int index, string relativePath) => true;
public virtual void CalcMeshSize(ref MeshExportInfo info,
string relativePath)
public void SetRoot(GameObject ExportRoot, MeshExportSettings settings, IBlendShapeExportFilter blendShapeFilter)
{
var sb = new StringBuilder();
if (!info.IsRendererActive)
MeshExportInfo.GetInfo(ExportRoot.transform.Traverse().Skip(1), Meshes, settings);
foreach(var info in Meshes)
{
sb.Append("[NotActive]");
}
info.VertexCount = info.Mesh.vertexCount;
info.ExportVertexSize = 0;
info.TotalBlendShapeCount = 0;
info.ExportBlendShapeCount = 0;
// float4 x 3
// vertices
sb.Append($"(Pos");
if (info.HasNormal)
{
sb.Append("+Nom");
info.ExportVertexSize += 4 * 3;
}
if (info.HasUV)
{
sb.Append("+UV");
info.ExportVertexSize += 4 * 2;
}
if (info.HasVertexColor)
{
sb.Append("+Col");
info.ExportVertexSize += 4 * 4;
}
if (info.HasSkinning)
{
// short, float x 4 weights
sb.Append("+Skin");
info.ExportVertexSize += (2 + 4) * 4;
}
// indices
info.IndexCount = info.Mesh.triangles.Length;
// postion + normal ?. always tangent is ignored
info.TotalBlendShapeCount = info.Mesh.blendShapeCount;
info.ExportBlendShapeVertexSize = Settings.ExportOnlyBlendShapePosition ? 4 * 3 : 4 * (3 + 3);
for (var i = 0; i < info.Mesh.blendShapeCount; ++i)
{
if (!UseBlendShape(i, relativePath))
{
continue;
}
++info.ExportBlendShapeCount;
}
if (info.ExportBlendShapeCount > 0)
{
sb.Append($"+Morph x {info.ExportBlendShapeCount}");
}
sb.Append($") x {info.Mesh.vertexCount}");
switch (info.VertexColor)
{
case VertexColorState.ExistsAndIsUsed:
case VertexColorState.ExistsAndMixed: // エクスポートする
sb.Insert(0, "[use vcolor]");
break;
case VertexColorState.ExistsButNotUsed:
sb.Insert(0, "[remove vcolor]");
break;
}
if (info.ExportBlendShapeCount > 0 && !info.HasSkinning)
{
sb.Insert(0, "[morph without skin]");
}
// total bytes
sb.Insert(0, $"{info.ExportByteSize:#,0} Bytes = ");
info.Summary = sb.ToString();
}
bool TryGetMeshInfo(GameObject root, Renderer renderer, out MeshExportInfo info)
{
info = default;
if (root == null)
{
info.Summary = "";
return false;
}
if (renderer == null)
{
info.Summary = "no Renderer";
return false;
}
info.Renderer = renderer;
if (renderer is SkinnedMeshRenderer smr)
{
info.Skinned = true;
info.Mesh = smr.sharedMesh;
info.IsRendererActive = smr.EnableForExport();
}
else if (renderer is MeshRenderer mr)
{
var filter = mr.GetComponent<MeshFilter>();
if (filter != null)
{
info.Mesh = filter.sharedMesh;
}
info.IsRendererActive = mr.EnableForExport();
}
else
{
info.Summary = "no Mesh";
return false;
}
info.VertexColor = VertexColorUtility.DetectVertexColor(info.Mesh, info.Renderer.sharedMaterials);
var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, root.transform);
CalcMeshSize(ref info, relativePath);
return true;
}
public void SetRoot(GameObject ExportRoot, MeshExportSettings settings)
{
Settings = settings;
Meshes.Clear();
if (ExportRoot == null)
{
return;
}
foreach (var renderer in ExportRoot.GetComponentsInChildren<Renderer>(true))
{
if (TryGetMeshInfo(ExportRoot, renderer, out MeshExportInfo info))
{
Meshes.Add(info);
}
info.CalcMeshSize(ExportRoot, info.Renderers[0].Item1, settings, blendShapeFilter);
}
}
@@ -204,28 +68,28 @@ namespace UniGLTF
foreach (var info in Meshes)
{
// invalid materials.len
if (info.Renderer.sharedMaterials.Length < info.Mesh.subMeshCount)
if (info.Materials.Length < info.Mesh.subMeshCount)
{
// submesh より material の方が少ない
yield return Validation.Error(Messages.MATERIALS_LESS_THAN_SUBMESH_COUNT.Msg());
}
else
{
if (info.Renderer.sharedMaterials.Length > info.Mesh.subMeshCount)
if (info.Materials.Length > info.Mesh.subMeshCount)
{
// submesh より material の方が多い
yield return Validation.Warning(Messages.MATERIALS_GREATER_THAN_SUBMESH_COUNT.Msg());
}
if (info.Renderer.sharedMaterials.Take(info.Mesh.subMeshCount).Any(x => x == null))
if (info.Materials.Take(info.Mesh.subMeshCount).Any(x => x == null))
{
// material に null が含まれる(unity で magenta になっているはず)
yield return Validation.Error($"{info.Renderer}: {Messages.MATERIALS_CONTAINS_NULL.Msg()}");
yield return Validation.Error($"{info.Renderers}: {Messages.MATERIALS_CONTAINS_NULL.Msg()}");
}
}
}
foreach (var m in Meshes.SelectMany(x => x.Renderer.sharedMaterials).Distinct())
foreach (var m in Meshes.SelectMany(x => x.Materials).Distinct())
{
if (m == null)
{

View File

@@ -40,12 +40,15 @@ namespace UniGLTF
var (left, right) = LeftRight(r.x, r.y, col0, r.width - col0, EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(left, $"{i,3}");
GUI.enabled = false;
EditorGUI.ObjectField(right, info.Renderer, info.Renderer.GetType(), true);
right.y += EditorGUIUtility.singleLineHeight;
EditorGUI.ObjectField(right, info.Mesh, info.Renderer.GetType(), true);
GUI.enabled = true;
using (new EditorGUI.DisabledScope(false))
{
foreach (var (renderer, _) in info.Renderers)
{
EditorGUI.ObjectField(right, renderer, info.Renderers.GetType(), true);
}
right.y += EditorGUIUtility.singleLineHeight;
EditorGUI.ObjectField(right, info.Mesh, info.Renderers.GetType(), true);
}
right.y += EditorGUIUtility.singleLineHeight;
EditorGUI.LabelField(right, info.Summary);

View File

@@ -213,7 +213,7 @@ namespace UniGLTF
{
var current = self;
var split = path.Split(new [] {'/'}, StringSplitOptions.RemoveEmptyEntries);
var split = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var childName in split)
{
@@ -334,5 +334,15 @@ namespace UniGLTF
}
return go.AddComponent<T>();
}
public static bool EnableForExport(this Component mono)
{
if (mono.transform.Ancestors().Any(x => !x.gameObject.activeSelf))
{
// 自分か祖先に !activeSelf がいる
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,18 @@
namespace UniGLTF
{
public interface IBlendShapeExportFilter
{
bool UseBlendShape(int blendShapeIndex, string relativePath);
}
public class DefualtBlendShapeExportFilter : IBlendShapeExportFilter
{
/// <summary>
/// Export all blendshape
/// </summary>
/// <param name="blendShapeIndex"></param>
/// <param name="relativePath"></param>
/// <returns></returns>
public bool UseBlendShape(int blendShapeIndex, string relativePath) => true;
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 18a610aab46d5034cb787ab237e3dea2
guid: d962c03c08e3d3a4eb5c52f5b4e0c93f
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,25 +1,154 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace UniGLTF
{
[Serializable]
public struct MeshExportInfo
public class MeshExportInfo
{
public Renderer Renderer;
#region gltf mesh Unique
public Mesh Mesh;
public bool IsRendererActive;
public bool Skinned;
public Material[] Materials;
public bool IsSameMeshAndMaterials(MeshExportInfo other)
{
return IsSameMeshAndMaterials(other.Mesh, other.Materials);
}
public bool IsSameMeshAndMaterials(Mesh mesh, Material[] materials)
{
if (Mesh != mesh) return false;
if (Materials.Length != materials.Length) return false;
for (var i = 0; i < Materials.Length; i++)
{
if (Materials[i] != materials[i]) return false;
}
return true;
}
public bool IsSameMeshAndMaterials(Renderer r)
{
if (r is SkinnedMeshRenderer smr)
{
return IsSameMeshAndMaterials(smr.sharedMesh, smr.sharedMaterials);
}
else if (r is MeshRenderer mr)
{
var filter = r.GetComponent<MeshFilter>();
if (filter == null)
{
return false;
}
return IsSameMeshAndMaterials(filter.sharedMesh, mr.sharedMaterials);
}
else
{
throw new NotImplementedException();
}
}
public static bool TryGetSameMeshIndex(List<MeshExportInfo> meshWithRenderers, Mesh mesh, Material[] materials, out int meshIndex)
{
for (var i = 0; i < meshWithRenderers.Count; i++)
{
if (meshWithRenderers[i].IsSameMeshAndMaterials(mesh, materials))
{
meshIndex = i;
return true;
}
}
meshIndex = -1;
return false;
}
public bool CanExport
{
get
{
if (Mesh == null)
{
return false;
}
if (Mesh.vertexCount == 0)
{
return false;
}
if (Materials == null)
{
return false;
}
if (Materials.Length == 0)
{
return false;
}
return true;
}
}
#endregion
/// <summary>
/// ひとつの Mesh を複数の Renderer が共有することがありうる
/// </summary>
List<(Renderer, Transform[] UniqueBones)> _renderers;
public IReadOnlyList<(Renderer, Transform[] UniqueBones)> Renderers => _renderers;
public bool IsRendererActive => Renderers.Any(x => x.Item1.EnableForExport());
#region SkinnedMeshRenderer
public bool Skinned;
int[] JointIndexMap;
/// <summary>
/// glTF は skinning の boneList の重複を許可しない
/// (unity は ok)
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public int GetJointIndex(int index)
{
if (index < 0)
{
return index;
}
if (JointIndexMap != null)
{
return JointIndexMap[index];
}
else
{
return index;
}
}
public IEnumerable<Matrix4x4> GetBindPoses()
{
var used = new HashSet<int>();
for (int i = 0; i < JointIndexMap.Length; ++i)
{
var index = JointIndexMap[i];
if (used.Add(index))
{
yield return Mesh.bindposes[i];
}
}
}
#endregion
#region VertexAttribute
public bool HasNormal => Mesh != null && Mesh.normals != null && Mesh.normals.Length == Mesh.vertexCount;
public bool HasUV => Mesh != null && Mesh.uv != null && Mesh.uv.Length == Mesh.vertexCount;
public bool HasVertexColor => Mesh.colors != null && Mesh.colors.Length == Mesh.vertexCount
public bool HasVertexColor => Mesh != null && Mesh.colors != null && Mesh.colors.Length == Mesh.vertexCount
&& VertexColor == VertexColorState.ExistsAndIsUsed
|| VertexColor == VertexColorState.ExistsAndMixed // Export する
;
public bool HasSkinning => Mesh.boneWeights != null && Mesh.boneWeights.Length == Mesh.vertexCount;
public bool HasSkinning => Mesh != null && Mesh.boneWeights != null && Mesh.boneWeights.Length == Mesh.vertexCount;
public VertexColorState VertexColor;
@@ -31,20 +160,253 @@ namespace UniGLTF
/// [SkinningWeight]
/// </summary>
public int ExportVertexSize;
#endregion
#region Triangles
public int IndexCount;
// int 決め打ち
public int IndicesSize => IndexCount * 4;
#endregion
#region BlendShape
public int ExportBlendShapeVertexSize;
public int TotalBlendShapeCount;
public int ExportBlendShapeCount;
#endregion
#region Summary
public int ExportByteSize => ExportVertexSize * VertexCount + IndicesSize + ExportBlendShapeCount * ExportBlendShapeVertexSize * VertexCount;
public string Summary;
#endregion
MeshExportInfo(Renderer renderer, MeshExportSettings settings)
{
if (renderer == null)
{
throw new ArgumentNullException();
}
Materials = renderer.sharedMaterials;
_renderers = new List<(Renderer, Transform[])>();
if (renderer is SkinnedMeshRenderer smr)
{
Skinned = true;
Mesh = smr.sharedMesh;
}
else if (renderer is MeshRenderer mr)
{
var filter = mr.GetComponent<MeshFilter>();
if (filter != null)
{
Mesh = filter.sharedMesh;
}
}
else
{
throw new NotImplementedException();
}
if (Mesh == null)
{
Summary = "no mesh";
}
VertexColor = VertexColorUtility.DetectVertexColor(Mesh, Materials);
PushRenderer(renderer);
}
void PushRenderer(Renderer renderer)
{
if (renderer is SkinnedMeshRenderer smr)
{
if (smr.bones != null && smr.bones.Length > 0)
{
var uniqueBones = smr.bones.Distinct().ToArray();
var jointIndexMap = new int[smr.bones.Length];
var bones = smr.bones;
for (int i = 0; i < bones.Length; ++i)
{
jointIndexMap[i] = Array.IndexOf(uniqueBones, bones[i]);
}
_renderers.Add((smr, uniqueBones));
if (JointIndexMap != null)
{
if (!JointIndexMap.SequenceEqual(jointIndexMap))
{
// edge case
throw new NotImplementedException("different jointIndexMap is not supported");
}
}
JointIndexMap = jointIndexMap;
}
else
{
// maybe blendshape only SkinnedMeshRenderer
_renderers.Add((smr, null));
}
}
else if (renderer is MeshRenderer mr)
{
_renderers.Add((mr, null));
}
else
{
throw new NotImplementedException();
}
}
public static MeshExportInfo Create(GameObject go)
{
var list = new List<MeshExportInfo>();
GetInfo(go.transform.Traverse(), list, MeshExportSettings.Default);
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, MeshExportSettings 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,
MeshExportSettings settings,
IBlendShapeExportFilter blendShapeFilter
)
{
var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, root.transform);
CalcMeshSize(relativePath, settings, blendShapeFilter);
}
public void CalcMeshSize(
string relativePath,
MeshExportSettings settings,
IBlendShapeExportFilter blendShapeFilter
)
{
var sb = new StringBuilder();
if (!IsRendererActive)
{
sb.Append("[NotActive]");
}
if (Mesh == null)
{
sb.Append("[NoMesh]");
}
else
{
VertexCount = Mesh.vertexCount;
ExportVertexSize = 0;
TotalBlendShapeCount = 0;
ExportBlendShapeCount = 0;
// float4 x 3
// vertices
sb.Append($"(Pos");
if (HasNormal)
{
sb.Append("+Nom");
ExportVertexSize += 4 * 3;
}
if (HasUV)
{
sb.Append("+UV");
ExportVertexSize += 4 * 2;
}
if (HasVertexColor)
{
sb.Append("+Col");
ExportVertexSize += 4 * 4;
}
if (HasSkinning)
{
// short, float x 4 weights
sb.Append("+Skin");
ExportVertexSize += (2 + 4) * 4;
}
// indices
IndexCount = Mesh.triangles.Length;
// postion + normal ?. always tangent is ignored
TotalBlendShapeCount = Mesh.blendShapeCount;
ExportBlendShapeVertexSize = settings.ExportOnlyBlendShapePosition ? 4 * 3 : 4 * (3 + 3);
for (var i = 0; i < Mesh.blendShapeCount; ++i)
{
if (!blendShapeFilter.UseBlendShape(i, relativePath))
{
continue;
}
++ExportBlendShapeCount;
}
if (ExportBlendShapeCount > 0)
{
sb.Append($"+Morph x {ExportBlendShapeCount}");
}
sb.Append($") x {Mesh.vertexCount}");
switch (VertexColor)
{
case VertexColorState.ExistsAndIsUsed:
case VertexColorState.ExistsAndMixed: // エクスポートする
sb.Insert(0, "[use vcolor]");
break;
case VertexColorState.ExistsButNotUsed:
sb.Insert(0, "[remove vcolor]");
break;
}
if (ExportBlendShapeCount > 0 && !HasSkinning)
{
sb.Insert(0, "[morph without skin]");
}
// total bytes
sb.Insert(0, $"{ExportByteSize:#,0} Bytes = ");
}
Summary = sb.ToString();
}
}
}

View File

@@ -8,7 +8,7 @@ namespace UniGLTF
public static class MeshExporter_DividedVertexBuffer
{
public static (glTFMesh, Dictionary<int, int>) Export(glTF gltf, int bufferIndex,
MeshWithRenderer unityMesh, List<Material> unityMaterials,
MeshExportInfo unityMesh, List<Material> unityMaterials,
IAxisInverter axisInverter, MeshExportSettings settings)
{
var mesh = unityMesh.Mesh;
@@ -58,7 +58,7 @@ namespace UniGLTF
}
}
var material = unityMesh.Renderer.sharedMaterials[i];
var material = unityMesh.Materials[i];
var materialIndex = -1;
if (material != null)
{

View File

@@ -24,11 +24,11 @@ namespace UniGLTF
/// <param name="settings"></param>
/// <returns></returns>
public static (glTFMesh, Dictionary<int, int> blendShapeIndexMap) Export(glTF gltf, int bufferIndex,
MeshWithRenderer unityMesh, List<Material> unityMaterials,
MeshExportInfo unityMesh, List<Material> unityMaterials,
IAxisInverter axisInverter, MeshExportSettings settings)
{
var mesh = unityMesh.Mesh;
var materials = unityMesh.Renderer.sharedMaterials;
var materials = unityMesh.Materials;
var positions = mesh.vertices.Select(axisInverter.InvertVector3).ToArray();
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);
gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
@@ -135,7 +135,7 @@ namespace UniGLTF
if (j >= materials.Length)
{
Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Renderer.name);
Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Mesh.name);
break;
}

View File

@@ -1,112 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UniGLTF
{
public struct MeshWithRenderer
{
public readonly Mesh Mesh;
public readonly Renderer Renderer;
public readonly Transform[] UniqueBones;
readonly int[] JointIndexMap;
public MeshWithRenderer(Transform x)
{
Mesh = x.GetSharedMesh();
Renderer = x.GetComponent<Renderer>();
if (Renderer is SkinnedMeshRenderer skin && skin.bones != null && skin.bones.Length > 0)
{
// has joints
var uniqueBones = skin.bones.Distinct().ToArray();
UniqueBones = uniqueBones;
JointIndexMap = new int[skin.bones.Length];
var bones = skin.bones;
for (int i = 0; i < bones.Length; ++i)
{
JointIndexMap[i] = Array.IndexOf(uniqueBones, bones[i]);
}
}
else
{
UniqueBones = null;
JointIndexMap = null;
}
}
/// <summary>
/// glTF は skinning の boneList の重複を許可しない
/// (unity は ok)
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public int GetJointIndex(int index)
{
if (index < 0)
{
return index;
}
if (JointIndexMap != null)
{
return JointIndexMap[index];
}
else
{
return index;
}
}
public IEnumerable<Matrix4x4> GetBindPoses()
{
var used = new HashSet<int>();
for (int i = 0; i < JointIndexMap.Length; ++i)
{
var index = JointIndexMap[i];
if (used.Add(index))
{
yield return Mesh.bindposes[i];
}
}
}
public static IEnumerable<MeshWithRenderer> FromNodes(IEnumerable<Transform> nodes)
{
foreach (var node in nodes)
{
var x = new MeshWithRenderer(node);
if (x.Mesh == null)
{
continue; ;
}
if (x.Renderer == null
|| x.Renderer.sharedMaterials == null
|| x.Renderer.sharedMaterials.Length == 0)
{
continue;
}
yield return x;
}
}
public bool IsSameMeshAndMaterials(MeshWithRenderer other)
{
return IsSameMeshAndMaterials(other.Mesh, other.Renderer.sharedMaterials);
}
public bool IsSameMeshAndMaterials(Mesh mesh, Material[] materials)
{
if (Mesh != mesh) return false;
if (Renderer.sharedMaterials.Length != materials.Length) return false;
for (var i = 0; i < Renderer.sharedMaterials.Length; i++)
{
if (Renderer.sharedMaterials[i] != materials[i]) return false;
}
return true;
}
}
}

View File

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

View File

@@ -138,7 +138,7 @@ namespace UniGLTF
}
#region Export
static glTFNode ExportNode(Transform x, List<Transform> nodes, List<MeshWithRenderer> meshWithRenderers, List<SkinnedMeshRenderer> skins)
static glTFNode ExportNode(Transform x, List<Transform> nodes, List<MeshExportInfo> meshWithRenderers, List<SkinnedMeshRenderer> skins)
{
var node = new glTFNode
{
@@ -160,7 +160,7 @@ namespace UniGLTF
{
var mesh = meshFilter.sharedMesh;
var materials = meshRenderer.sharedMaterials;
if (TryGetSameMeshIndex(meshWithRenderers, mesh, materials, out int meshIndex))
if (MeshExportInfo.TryGetSameMeshIndex(meshWithRenderers, mesh, materials, out int meshIndex))
{
node.mesh = meshIndex;
}
@@ -182,7 +182,7 @@ namespace UniGLTF
{
var mesh = skinnedMeshRenderer.sharedMesh;
var materials = skinnedMeshRenderer.sharedMaterials;
if (TryGetSameMeshIndex(meshWithRenderers, mesh, materials, out int meshIndex))
if (MeshExportInfo.TryGetSameMeshIndex(meshWithRenderers, mesh, materials, out int meshIndex))
{
node.mesh = meshIndex;
node.skin = skins.IndexOf(skinnedMeshRenderer);
@@ -203,21 +203,6 @@ namespace UniGLTF
return node;
}
private static bool TryGetSameMeshIndex(List<MeshWithRenderer> meshWithRenderers, Mesh mesh, Material[] materials, out int meshIndex)
{
for (var i = 0; i < meshWithRenderers.Count; i++)
{
if (meshWithRenderers[i].IsSameMeshAndMaterials(mesh, materials))
{
meshIndex = i;
return true;
}
}
meshIndex = -1;
return false;
}
public virtual void ExportExtensions(ITextureSerializer textureSerializer)
{
// do nothing
@@ -232,15 +217,11 @@ namespace UniGLTF
.Skip(1) // exclude root object for the symmetry with the importer
.ToList();
var unityMeshes = MeshWithRenderer.FromNodes(Nodes).Where(x => x.Mesh.vertices.Any()).ToList();
var uniqueUnityMeshes = new List<MeshWithRenderer>();
foreach (var um in unityMeshes)
{
if (!uniqueUnityMeshes.Any(x => x.IsSameMeshAndMaterials(um))) uniqueUnityMeshes.Add(um);
}
var uniqueUnityMeshes = new List<MeshExportInfo>();
MeshExportInfo.GetInfo(Nodes, uniqueUnityMeshes, meshExportSettings);
#region Materials and Textures
Materials = uniqueUnityMeshes.SelectMany(x => x.Renderer.sharedMaterials).Where(x => x != null).Distinct().ToList();
Materials = uniqueUnityMeshes.SelectMany(x => x.Materials).Where(x => x != null).Distinct().ToList();
TextureExporter = new TextureExporter(textureSerializer);
@@ -267,10 +248,17 @@ namespace UniGLTF
#endregion
#region Nodes and Skins
var unitySkins = uniqueUnityMeshes
.Where(x => x.UniqueBones != null)
.ToList();
glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, uniqueUnityMeshes, unitySkins.Select(y => y.Renderer as SkinnedMeshRenderer).ToList())).ToList();
var skins = uniqueUnityMeshes
.SelectMany(x => x.Renderers)
.Where(x => x.Item1 is SkinnedMeshRenderer && x.UniqueBones != null)
.Select(x => x.Item1 as SkinnedMeshRenderer)
.ToList()
;
foreach (var node in Nodes)
{
var gltfNode = ExportNode(node, Nodes, uniqueUnityMeshes, skins);
glTF.nodes.Add(gltfNode);
}
glTF.scenes = new List<gltfScene>
{
new gltfScene
@@ -279,26 +267,30 @@ namespace UniGLTF
}
};
foreach (var x in unitySkins)
foreach (var x in uniqueUnityMeshes)
{
var matrices = x.GetBindPoses().Select(m_axisInverter.InvertMat4).ToArray();
var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE);
var renderer = x.Renderer as SkinnedMeshRenderer;
var skin = new glTFSkin
foreach (var (renderer, uniqueBones) in x.Renderers)
{
inverseBindMatrices = accessor,
joints = x.UniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(),
skeleton = Nodes.IndexOf(renderer.rootBone),
};
var skinIndex = glTF.skins.Count;
glTF.skins.Add(skin);
if (uniqueBones != null && renderer is SkinnedMeshRenderer smr)
{
var matrices = x.GetBindPoses().Select(m_axisInverter.InvertMat4).ToArray();
var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE);
var skin = new glTFSkin
{
inverseBindMatrices = accessor,
joints = uniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(),
skeleton = Nodes.IndexOf(smr.rootBone),
};
var skinIndex = glTF.skins.Count;
glTF.skins.Add(skin);
foreach (var z in Nodes.Where(y => y.Has(x.Renderer)))
{
var nodeIndex = Nodes.IndexOf(z);
var node = glTF.nodes[nodeIndex];
node.skin = skinIndex;
foreach (var z in Nodes.Where(y => y.Has(renderer)))
{
var nodeIndex = Nodes.IndexOf(z);
var node = glTF.nodes[nodeIndex];
node.skin = skinIndex;
}
}
}
}
#endregion

View File

@@ -26,7 +26,7 @@ namespace UniGLTF
try
{
validator.SetRoot(root, MeshExportSettings.Default);
validator.SetRoot(root, MeshExportSettings.Default, new DefualtBlendShapeExportFilter());
var vs = validator.Validate(root);
Assert.False(vs.All(x => x.CanExport));
}
@@ -46,7 +46,7 @@ namespace UniGLTF
try
{
validator.SetRoot(root, MeshExportSettings.Default);
validator.SetRoot(root, MeshExportSettings.Default, new DefualtBlendShapeExportFilter());
var vs = validator.Validate(root);
Assert.False(vs.All(x => x.CanExport));
}
@@ -66,7 +66,7 @@ namespace UniGLTF
try
{
validator.SetRoot(root, MeshExportSettings.Default);
validator.SetRoot(root, MeshExportSettings.Default, new DefualtBlendShapeExportFilter());
var vs = validator.Validate(root);
Assert.False(vs.All(x => x.CanExport));
}
@@ -90,7 +90,7 @@ namespace UniGLTF
// remove MeshFilter
Component.DestroyImmediate(child.GetComponent<MeshFilter>());
validator.SetRoot(root, MeshExportSettings.Default);
validator.SetRoot(root, MeshExportSettings.Default, new DefualtBlendShapeExportFilter());
var vs = validator.Validate(root);
Assert.True(vs.All(x => x.CanExport));
}
@@ -114,7 +114,7 @@ namespace UniGLTF
// set null
child.GetComponent<MeshFilter>().sharedMesh = null;
validator.SetRoot(root, MeshExportSettings.Default);
validator.SetRoot(root, MeshExportSettings.Default, new DefualtBlendShapeExportFilter());
var vs = validator.Validate(root);
Assert.True(vs.All(x => x.CanExport));
}

View File

@@ -134,7 +134,7 @@ namespace UniGLTF
};
var axisInverter = Axes.X.Create();
var unityMesh = new MeshWithRenderer(go.transform);
var unityMesh = MeshExportInfo.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 = new MeshWithRenderer(go.transform);
var unityMesh = MeshExportInfo.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

@@ -5,14 +5,7 @@ using UnityEngine;
namespace VRM
{
/// <summary>
/// Export時にMeshを一覧する。
///
/// Mesh関連の Validation する。
/// Meshのエクスポートサイズを試算する。
/// </summary>
[Serializable]
public class VRMMeshExportValidator : MeshExportValidator
public class VRMBlendShapeExportFilter : IBlendShapeExportFilter
{
static bool ClipsContainsName(IReadOnlyList<BlendShapeClip> clips, bool onlyPreset, BlendShapeBinding binding)
{
@@ -40,7 +33,24 @@ namespace VRM
public VRMExportSettings VRMExportSettings;
public List<BlendShapeClip> Clips;
public override bool UseBlendShape(int index, string relativePath)
public VRMBlendShapeExportFilter(GameObject exportRoot, VRMExportSettings settings)
{
VRMExportSettings = settings;
Clips = new List<BlendShapeClip>();
if (exportRoot != null)
{
var proxy = exportRoot.GetComponent<VRMBlendShapeProxy>();
if (proxy != null)
{
if (proxy.BlendShapeAvatar != null)
{
Clips.AddRange(proxy.BlendShapeAvatar.Clips);
}
}
}
}
public bool UseBlendShape(int index, string relativePath)
{
if (VRMExportSettings.ReduceBlendshape)
{
@@ -57,24 +67,5 @@ namespace VRM
return true;
}
public void SetRoot(GameObject ExportRoot, VRMExportSettings settings)
{
VRMExportSettings = settings;
Clips = new List<BlendShapeClip>();
if (ExportRoot != null)
{
var proxy = ExportRoot.GetComponent<VRMBlendShapeProxy>();
if (proxy != null)
{
if (proxy.BlendShapeAvatar != null)
{
Clips.AddRange(proxy.BlendShapeAvatar.Clips);
}
}
}
SetRoot(ExportRoot, settings.MeshExportSettings);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f76ebfda1e249cb48890de41cc221889
guid: d634cf68918e2f947b7ea0288d52a720
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -36,7 +36,7 @@ namespace VRM
Editor m_settingsInspector;
VRMMeshExportValidator m_meshes;
MeshExportValidator m_meshes;
Editor m_meshesInspector;
@@ -69,7 +69,7 @@ namespace VRM
m_settings = ScriptableObject.CreateInstance<VRMExportSettings>();
m_settingsInspector = Editor.CreateEditor(m_settings);
m_meshes = ScriptableObject.CreateInstance<VRMMeshExportValidator>();
m_meshes = ScriptableObject.CreateInstance<MeshExportValidator>();
m_meshesInspector = Editor.CreateEditor(m_meshes);
State.ExportRootChanged += (root) =>
@@ -179,7 +179,7 @@ namespace VRM
protected override void OnLayout()
{
m_meshes.SetRoot(State.ExportRoot, m_settings);
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings, new VRMBlendShapeExportFilter(State.ExportRoot, m_settings));
}
static bool s_foldT = true;
@@ -259,7 +259,7 @@ namespace VRM
switch (meshInfo.VertexColor)
{
case UniGLTF.VertexColorState.ExistsAndMixed:
Validation.Warning($"{meshInfo.Renderer}: Both vcolor.multiply and not multiply unlit materials exist").DrawGUI();
Validation.Warning($"{meshInfo.Renderers}: Both vcolor.multiply and not multiply unlit materials exist").DrawGUI();
break;
}
}

View File

@@ -1,10 +0,0 @@
using UniGLTF;
using UnityEditor;
namespace VRM
{
[CustomEditor(typeof(VRMMeshExportValidator))]
public class VRMExportMeshesEditor : MeshExportValidatorEditor
{
}
}

View File

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

View File

@@ -2,19 +2,17 @@
"name": "VRM",
"references": [
"UniHumanoid",
"MeshUtility",
"UniGLTF",
"VRMShaders.GLTF.IO.Runtime",
"VRMShaders.VRM.IO.Runtime",
"MToon"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
"defineConstraints": []
}

View File

@@ -168,7 +168,7 @@ namespace UniVRM10
protected override void OnLayout()
{
// m_settings, m_meshes.Meshes
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings);
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings, new DefualtBlendShapeExportFilter());
}
protected override bool DoGUI(bool isValid)