mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-24 19:45:37 -05:00
Merge pull request #550 from ousttrue/feature/exporter_calc_size
Export Dialog の更新
This commit is contained in:
@@ -16,6 +16,7 @@ namespace VRM
|
||||
if (r.Renderer == null)
|
||||
{
|
||||
yield return Validation.Error($"[VRMFirstPerson]{self.name}.Renderers[{i}].Renderer is null");
|
||||
continue;
|
||||
}
|
||||
if (!hierarchy.Contains(r.Renderer.transform))
|
||||
{
|
||||
|
||||
410
Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs
Normal file
410
Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs
Normal file
@@ -0,0 +1,410 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
public class VRMExporterValidator
|
||||
{
|
||||
// Allows you to enable and disable the wizard create button, so that the user can not click it.
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
var hasError = m_validations.Any(x => !x.CanExport);
|
||||
return !hasError && !MetaHasError;
|
||||
}
|
||||
}
|
||||
|
||||
bool MetaHasError = false;
|
||||
|
||||
List<Validation> m_validations = new List<Validation>();
|
||||
public IEnumerable<Validation> Validations => m_validations;
|
||||
|
||||
public int ExpectedByteSize = 0;
|
||||
|
||||
/// <summary>
|
||||
/// ボーン名の重複を確認
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool DuplicateBoneNameExists(GameObject ExportRoot)
|
||||
{
|
||||
if (ExportRoot == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var bones = ExportRoot.transform.GetComponentsInChildren<Transform>();
|
||||
var duplicates = bones
|
||||
.GroupBy(p => p.name)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(g => g.Key);
|
||||
|
||||
return (duplicates.Any());
|
||||
}
|
||||
|
||||
public static bool IsFileNameLengthTooLong(string fileName)
|
||||
{
|
||||
return fileName.Length > 64;
|
||||
}
|
||||
|
||||
public static bool HasRotationOrScale(GameObject root)
|
||||
{
|
||||
foreach (var t in root.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
if (t.localRotation != Quaternion.identity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t.localScale != Vector3.one)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static Vector3 GetForward(Transform l, Transform r)
|
||||
{
|
||||
if (l == null || r == null)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
var lr = (r.position - l.position).normalized;
|
||||
return Vector3.Cross(lr, Vector3.up);
|
||||
}
|
||||
|
||||
static string Msg(VRMExporterWizardMessages key)
|
||||
{
|
||||
return M17N.Getter.Msg(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExportDialogを表示する前に確認する。
|
||||
/// </summary>
|
||||
/// <param name="ExportRoot"></param>
|
||||
/// <param name="m_settings"></param>
|
||||
/// <returns></returns>
|
||||
public bool RootAndHumanoidCheck(GameObject ExportRoot, VRMExportSettings m_settings)
|
||||
{
|
||||
//
|
||||
// root
|
||||
//
|
||||
if (ExportRoot == null)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.ROOT_EXISTS)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
if (ExportRoot.transform.parent != null)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_PARENT)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
|
||||
var renderers = ExportRoot.GetComponentsInChildren<Renderer>();
|
||||
if (renderers.All(x => !x.EnableForExport()))
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_ACTIVE_MESH)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasRotationOrScale(ExportRoot))
|
||||
{
|
||||
if (m_settings.PoseFreeze)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Root OK", MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Validation.Warning(Msg(VRMExporterWizardMessages.ROTATION_OR_SCALEING_INCLUDED_IN_NODE)).DrawGUI();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_settings.PoseFreeze)
|
||||
{
|
||||
Validation.Warning(Msg(VRMExporterWizardMessages.IS_POSE_FREEZE_DONE)).DrawGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Root OK", MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// animator
|
||||
//
|
||||
var animator = ExportRoot.GetComponent<Animator>();
|
||||
if (animator == null)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_ANIMATOR)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
|
||||
var avatar = animator.avatar;
|
||||
if (avatar == null)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_AVATAR_IN_ANIMATOR)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
if (!avatar.isValid)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.AVATAR_IS_NOT_VALID)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
if (!avatar.isHuman)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.AVATAR_IS_NOT_HUMANOID)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
{
|
||||
var l = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg);
|
||||
var r = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg);
|
||||
var f = GetForward(l, r);
|
||||
if (Vector3.Dot(f, Vector3.forward) < 0.8f)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.FACE_Z_POSITIVE_DIRECTION)).DrawGUI();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw);
|
||||
if (jaw != null)
|
||||
{
|
||||
Validation.Warning(Msg(VRMExporterWizardMessages.JAW_BONE_IS_INCLUDED)).DrawGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Animator OK", MessageType.Info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// エクスポート可能か検証する
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void Validate(GameObject ExportRoot, VRMExportSettings m_settings, VRMMetaObject meta)
|
||||
{
|
||||
m_validations.Clear();
|
||||
if (ExportRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_validations.AddRange(_Validate(ExportRoot, m_settings));
|
||||
if (ExportRoot != null)
|
||||
{
|
||||
m_validations.AddRange(VRMSpringBoneValidator.Validate(ExportRoot));
|
||||
var firstPerson = ExportRoot.GetComponent<VRMFirstPerson>();
|
||||
if (firstPerson != null)
|
||||
{
|
||||
m_validations.AddRange(firstPerson.Validate());
|
||||
}
|
||||
}
|
||||
MetaHasError = meta.Validate().Any();
|
||||
|
||||
// サイズ の 計算
|
||||
var proxy = ExportRoot.GetComponent<VRMBlendShapeProxy>();
|
||||
var clips = new List<BlendShapeClip>();
|
||||
if (proxy != null && proxy.BlendShapeAvatar != null)
|
||||
{
|
||||
clips.AddRange(proxy.BlendShapeAvatar.Clips);
|
||||
}
|
||||
|
||||
ExpectedByteSize = 0;
|
||||
foreach (var renderer in ExportRoot.GetComponentsInChildren<Renderer>())
|
||||
{
|
||||
var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, ExportRoot.transform);
|
||||
var mesh = GetMesh(renderer);
|
||||
ExpectedByteSize += CalcMeshSize(relativePath, mesh, m_settings, clips);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ClipsContainsName(List<BlendShapeClip> clips, bool onlyPreset, BlendShapeBinding binding)
|
||||
{
|
||||
foreach (var c in clips)
|
||||
{
|
||||
if (onlyPreset)
|
||||
{
|
||||
if (c.Preset == BlendShapePreset.Unknown)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var b in c.Values)
|
||||
{
|
||||
if (b.RelativePath == binding.RelativePath && b.Index == binding.Index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int CalcMeshSize(string relativePath, Mesh m, VRMExportSettings m_settings, List<BlendShapeClip> clips)
|
||||
{
|
||||
int size = 0;
|
||||
// vertices
|
||||
size += m.vertexCount * 4 * 3; // vector3
|
||||
if (m.normals != null)
|
||||
{
|
||||
size += m.vertexCount * 4 * 3;
|
||||
}
|
||||
if (m.uv != null)
|
||||
{
|
||||
size += m.vertexCount * 4 * 2;
|
||||
}
|
||||
if (m.colors != null)
|
||||
{
|
||||
size += m.vertexCount * 4 * 4;
|
||||
}
|
||||
// indices
|
||||
size += m.triangles.Length * 4; // int ?
|
||||
// blendshapes
|
||||
for (var i = 0; i < m.blendShapeCount; ++i)
|
||||
{
|
||||
// var name = m.GetBlendShapeName(i);
|
||||
if (m_settings.ReduceBlendshape)
|
||||
{
|
||||
if (!ClipsContainsName(clips, m_settings.ReduceBlendshapeClip, new BlendShapeBinding
|
||||
{
|
||||
Index = i,
|
||||
RelativePath = relativePath,
|
||||
}))
|
||||
{
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
size += m.vertexCount * 4 * (3 + 3);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static Mesh GetMesh(Renderer r)
|
||||
{
|
||||
if (r is SkinnedMeshRenderer smr)
|
||||
{
|
||||
return smr.sharedMesh;
|
||||
}
|
||||
if (r is MeshRenderer)
|
||||
{
|
||||
MeshFilter f = r.GetComponent<MeshFilter>();
|
||||
if (f != null)
|
||||
{
|
||||
return f.sharedMesh;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerable<Validation> _Validate(GameObject ExportRoot, VRMExportSettings m_settings)
|
||||
{
|
||||
if (ExportRoot == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (DuplicateBoneNameExists(ExportRoot))
|
||||
{
|
||||
yield return Validation.Warning(Msg(VRMExporterWizardMessages.DUPLICATE_BONE_NAME_EXISTS));
|
||||
}
|
||||
|
||||
if (m_settings.ReduceBlendshape && ExportRoot.GetComponent<VRMBlendShapeProxy>() == null)
|
||||
{
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.NEEDS_VRM_BLENDSHAPE_PROXY));
|
||||
}
|
||||
|
||||
var vertexColor = ExportRoot.GetComponentsInChildren<SkinnedMeshRenderer>().Any(x => x.sharedMesh.colors.Length > 0);
|
||||
if (vertexColor)
|
||||
{
|
||||
yield return Validation.Warning(Msg(VRMExporterWizardMessages.VERTEX_COLOR_IS_INCLUDED));
|
||||
}
|
||||
|
||||
var renderers = ExportRoot.GetComponentsInChildren<Renderer>();
|
||||
var materials = renderers.SelectMany(x => x.sharedMaterials).Distinct();
|
||||
foreach (var material in materials)
|
||||
{
|
||||
if (material.shader.name == "Standard")
|
||||
{
|
||||
// standard
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VRMMaterialExporter.UseUnlit(material.shader.name))
|
||||
{
|
||||
// unlit
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VRMMaterialExporter.VRMExtensionShaders.Contains(material.shader.name))
|
||||
{
|
||||
// VRM supported
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return Validation.Warning($"Material: {material.name}. Unknown Shader: \"{material.shader.name}\" is used. {Msg(VRMExporterWizardMessages.UNKNOWN_SHADER)}");
|
||||
}
|
||||
|
||||
foreach (var material in materials)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(material.name))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + material.name);
|
||||
}
|
||||
|
||||
var textureNameList = new List<string>();
|
||||
foreach (var material in materials)
|
||||
{
|
||||
var shader = material.shader;
|
||||
int propertyCount = ShaderUtil.GetPropertyCount(shader);
|
||||
for (int i = 0; i < propertyCount; i++)
|
||||
{
|
||||
if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
|
||||
{
|
||||
if ((material.GetTexture(ShaderUtil.GetPropertyName(shader, i)) != null))
|
||||
{
|
||||
var textureName = material.GetTexture(ShaderUtil.GetPropertyName(shader, i)).name;
|
||||
if (!textureNameList.Contains(textureName))
|
||||
textureNameList.Add(textureName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var textureName in textureNameList)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(textureName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + textureName);
|
||||
}
|
||||
|
||||
var vrmMeta = ExportRoot.GetComponent<VRMMeta>();
|
||||
if (vrmMeta != null && vrmMeta.Meta != null && vrmMeta.Meta.Thumbnail != null)
|
||||
{
|
||||
var thumbnailName = vrmMeta.Meta.Thumbnail.name;
|
||||
if (IsFileNameLengthTooLong(thumbnailName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + thumbnailName);
|
||||
}
|
||||
|
||||
var meshFilters = ExportRoot.GetComponentsInChildren<MeshFilter>();
|
||||
var meshesName = meshFilters.Select(x => x.sharedMesh.name).Distinct();
|
||||
foreach (var meshName in meshesName)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(meshName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + meshName);
|
||||
}
|
||||
|
||||
var skinnedmeshRenderers = ExportRoot.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
var skinnedmeshesName = skinnedmeshRenderers.Select(x => x.sharedMesh.name).Distinct();
|
||||
foreach (var skinnedmeshName in skinnedmeshesName)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(skinnedmeshName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + skinnedmeshName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs.meta
Normal file
11
Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc233cbadb897eb4886de9927bee9fc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -32,7 +31,11 @@ namespace VRM
|
||||
get { return m_meta; }
|
||||
set
|
||||
{
|
||||
if (m_meta == value) return;
|
||||
if (m_meta == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_requireValidation = true;
|
||||
if (m_metaEditor != null)
|
||||
{
|
||||
UnityEditor.Editor.DestroyImmediate(m_metaEditor);
|
||||
@@ -42,27 +45,13 @@ namespace VRM
|
||||
}
|
||||
}
|
||||
|
||||
bool MetaHasError
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Meta != null)
|
||||
{
|
||||
return Meta.Validate().Any();
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_tmpMeta.Validate().Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateRoot(GameObject root)
|
||||
{
|
||||
if (root == ExportRoot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_requireValidation = true;
|
||||
ExportRoot = root;
|
||||
UnityEditor.Editor.DestroyImmediate(m_metaEditor);
|
||||
m_metaEditor = null;
|
||||
@@ -74,7 +63,7 @@ namespace VRM
|
||||
else
|
||||
{
|
||||
// default setting
|
||||
m_settings.PoseFreeze = HasRotationOrScale(ExportRoot);
|
||||
m_settings.PoseFreeze = VRMExporterValidator.HasRotationOrScale(ExportRoot);
|
||||
|
||||
var meta = ExportRoot.GetComponent<VRMMeta>();
|
||||
if (meta != null)
|
||||
@@ -88,178 +77,13 @@ namespace VRM
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ボーン名の重複を確認
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool DuplicateBoneNameExists()
|
||||
{
|
||||
if (ExportRoot == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var bones = ExportRoot.transform.GetComponentsInChildren<Transform>();
|
||||
var duplicates = bones
|
||||
.GroupBy(p => p.name)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(g => g.Key);
|
||||
|
||||
return (duplicates.Any());
|
||||
}
|
||||
|
||||
public static bool IsFileNameLengthTooLong(string fileName)
|
||||
{
|
||||
return fileName.Length > 64;
|
||||
}
|
||||
|
||||
public static bool HasRotationOrScale(GameObject root)
|
||||
{
|
||||
foreach (var t in root.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
if (t.localRotation != Quaternion.identity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t.localScale != Vector3.one)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static Vector3 GetForward(Transform l, Transform r)
|
||||
{
|
||||
if (l == null || r == null)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
var lr = (r.position - l.position).normalized;
|
||||
return Vector3.Cross(lr, Vector3.up);
|
||||
}
|
||||
|
||||
static string Msg(VRMExporterWizardMessages key)
|
||||
{
|
||||
return M17N.Getter.Msg(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// エクスポート可能か検証する
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Validation> Validate()
|
||||
{
|
||||
if (ExportRoot == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (DuplicateBoneNameExists())
|
||||
{
|
||||
yield return Validation.Warning(Msg(VRMExporterWizardMessages.DUPLICATE_BONE_NAME_EXISTS));
|
||||
}
|
||||
|
||||
if (m_settings.ReduceBlendshape && ExportRoot.GetComponent<VRMBlendShapeProxy>() == null)
|
||||
{
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.NEEDS_VRM_BLENDSHAPE_PROXY));
|
||||
}
|
||||
|
||||
var vertexColor = ExportRoot.GetComponentsInChildren<SkinnedMeshRenderer>().Any(x => x.sharedMesh.colors.Length > 0);
|
||||
if (vertexColor)
|
||||
{
|
||||
yield return Validation.Warning(Msg(VRMExporterWizardMessages.VERTEX_COLOR_IS_INCLUDED));
|
||||
}
|
||||
|
||||
var renderers = ExportRoot.GetComponentsInChildren<Renderer>();
|
||||
var materials = renderers.SelectMany(x => x.sharedMaterials).Distinct();
|
||||
foreach (var material in materials)
|
||||
{
|
||||
if (material.shader.name == "Standard")
|
||||
{
|
||||
// standard
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VRMMaterialExporter.UseUnlit(material.shader.name))
|
||||
{
|
||||
// unlit
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VRMMaterialExporter.VRMExtensionShaders.Contains(material.shader.name))
|
||||
{
|
||||
// VRM supported
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return Validation.Warning($"Material: {material.name}. Unknown Shader: \"{material.shader.name}\" is used. {Msg(VRMExporterWizardMessages.UNKNOWN_SHADER)}");
|
||||
}
|
||||
|
||||
foreach (var material in materials)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(material.name))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + material.name);
|
||||
}
|
||||
|
||||
var textureNameList = new List<string>();
|
||||
foreach (var material in materials)
|
||||
{
|
||||
var shader = material.shader;
|
||||
int propertyCount = ShaderUtil.GetPropertyCount(shader);
|
||||
for (int i = 0; i < propertyCount; i++)
|
||||
{
|
||||
if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
|
||||
{
|
||||
if ((material.GetTexture(ShaderUtil.GetPropertyName(shader, i)) != null))
|
||||
{
|
||||
var textureName = material.GetTexture(ShaderUtil.GetPropertyName(shader, i)).name;
|
||||
if (!textureNameList.Contains(textureName))
|
||||
textureNameList.Add(textureName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var textureName in textureNameList)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(textureName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + textureName);
|
||||
}
|
||||
|
||||
var vrmMeta = ExportRoot.GetComponent<VRMMeta>();
|
||||
if (vrmMeta != null && vrmMeta.Meta != null && vrmMeta.Meta.Thumbnail != null)
|
||||
{
|
||||
var thumbnailName = vrmMeta.Meta.Thumbnail.name;
|
||||
if (IsFileNameLengthTooLong(thumbnailName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + thumbnailName);
|
||||
}
|
||||
|
||||
var meshFilters = ExportRoot.GetComponentsInChildren<MeshFilter>();
|
||||
var meshesName = meshFilters.Select(x => x.sharedMesh.name).Distinct();
|
||||
foreach (var meshName in meshesName)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(meshName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + meshName);
|
||||
}
|
||||
|
||||
var skinnedmeshRenderers = ExportRoot.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
var skinnedmeshesName = skinnedmeshRenderers.Select(x => x.sharedMesh.name).Distinct();
|
||||
foreach (var skinnedmeshName in skinnedmeshesName)
|
||||
{
|
||||
if (IsFileNameLengthTooLong(skinnedmeshName))
|
||||
yield return Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + skinnedmeshName);
|
||||
}
|
||||
}
|
||||
|
||||
VRMMetaObject m_tmpMeta;
|
||||
|
||||
Editor m_metaEditor;
|
||||
Editor m_Inspector;
|
||||
|
||||
private bool m_IsValid = true;
|
||||
|
||||
List<Validation> m_validations = new List<Validation>();
|
||||
VRMExporterValidator m_validator = new VRMExporterValidator();
|
||||
bool m_requireValidation = true;
|
||||
|
||||
private Vector2 m_ScrollPosition;
|
||||
private string m_CreateButton = "Create";
|
||||
@@ -351,109 +175,40 @@ namespace VRM
|
||||
UpdateRoot(root);
|
||||
}
|
||||
|
||||
//
|
||||
// ここでも validate している。ここで失敗して return した場合は Export UI を表示しない
|
||||
//
|
||||
|
||||
//
|
||||
// root
|
||||
//
|
||||
if (ExportRoot == null)
|
||||
if (Event.current.type == EventType.Layout)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.ROOT_EXISTS)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
if (ExportRoot.transform.parent != null)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_PARENT)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
|
||||
var renderers = ExportRoot.GetComponentsInChildren<Renderer>();
|
||||
if (renderers.All(x => !x.EnableForExport()))
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_ACTIVE_MESH)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasRotationOrScale(ExportRoot))
|
||||
{
|
||||
if (m_settings.PoseFreeze)
|
||||
// ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint Aborting
|
||||
if (m_requireValidation)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Root OK", MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Validation.Warning(Msg(VRMExporterWizardMessages.ROTATION_OR_SCALEING_INCLUDED_IN_NODE)).DrawGUI();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_settings.PoseFreeze)
|
||||
{
|
||||
Validation.Warning(Msg(VRMExporterWizardMessages.IS_POSE_FREEZE_DONE)).DrawGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Root OK", MessageType.Info);
|
||||
m_validator.Validate(ExportRoot, m_settings, Meta != null ? Meta : m_tmpMeta);
|
||||
m_requireValidation = false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// animator
|
||||
// 事前チェック。ここで失敗する場合は Export UI を表示しない
|
||||
//
|
||||
var animator = ExportRoot.GetComponent<Animator>();
|
||||
if (animator == null)
|
||||
if (!m_validator.RootAndHumanoidCheck(ExportRoot, m_settings))
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_ANIMATOR)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
|
||||
var avatar = animator.avatar;
|
||||
if (avatar == null)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.NO_AVATAR_IN_ANIMATOR)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
if (!avatar.isValid)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.AVATAR_IS_NOT_VALID)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
if (!avatar.isHuman)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.AVATAR_IS_NOT_HUMANOID)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
{
|
||||
var l = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg);
|
||||
var r = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg);
|
||||
var f = GetForward(l, r);
|
||||
if (Vector3.Dot(f, Vector3.forward) < 0.8f)
|
||||
{
|
||||
Validation.Error(Msg(VRMExporterWizardMessages.FACE_Z_POSITIVE_DIRECTION)).DrawGUI();
|
||||
return;
|
||||
}
|
||||
}
|
||||
var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw);
|
||||
if (jaw != null)
|
||||
{
|
||||
Validation.Warning(Msg(VRMExporterWizardMessages.JAW_BONE_IS_INCLUDED)).DrawGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Animator OK", MessageType.Info);
|
||||
}
|
||||
EditorGUILayout.HelpBox($"Mesh size: {m_validator.ExpectedByteSize / 1000000.0f:0.0} MByte", MessageType.Info);
|
||||
|
||||
// validation
|
||||
foreach (var v in m_validations)
|
||||
{
|
||||
v.DrawGUI();
|
||||
}
|
||||
_tab = TabBar.OnGUI(_tab, TabButtonStyle, TabButtonSize);
|
||||
|
||||
// Render contents using Generic Inspector GUI
|
||||
m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box");
|
||||
GUIUtility.GetControlID(645789, FocusType.Passive);
|
||||
|
||||
//
|
||||
// その他の Validation
|
||||
//
|
||||
foreach (var v in m_validator.Validations)
|
||||
{
|
||||
v.DrawGUI();
|
||||
}
|
||||
|
||||
bool modified = DrawWizardGUI();
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
@@ -466,7 +221,7 @@ namespace VRM
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUI.enabled = m_IsValid;
|
||||
GUI.enabled = m_validator.IsValid;
|
||||
|
||||
const BindingFlags kInstanceInvokeFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
|
||||
if (m_OtherButton != "" && GUILayout.Button(m_OtherButton, GUILayout.MinWidth(100)))
|
||||
@@ -499,6 +254,12 @@ namespace VRM
|
||||
}
|
||||
|
||||
GUILayout.Space(8);
|
||||
|
||||
if (modified)
|
||||
{
|
||||
m_requireValidation = true;
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
enum Tabs
|
||||
@@ -522,7 +283,6 @@ namespace VRM
|
||||
}
|
||||
|
||||
// tabbar
|
||||
_tab = TabBar.OnGUI(_tab, TabButtonStyle, TabButtonSize);
|
||||
switch (_tab)
|
||||
{
|
||||
case Tabs.Meta:
|
||||
@@ -626,13 +386,6 @@ namespace VRM
|
||||
}
|
||||
}
|
||||
|
||||
// Allows you to enable and disable the wizard create button, so that the user can not click it.
|
||||
public bool isValid
|
||||
{
|
||||
get { return m_IsValid; }
|
||||
set { m_IsValid = value; }
|
||||
}
|
||||
|
||||
const string EXTENSION = ".vrm";
|
||||
|
||||
private static string m_lastExportDir;
|
||||
@@ -648,7 +401,7 @@ namespace VRM
|
||||
|
||||
if (go != null)
|
||||
{
|
||||
wiz.m_settings.PoseFreeze = HasRotationOrScale(go);
|
||||
wiz.m_settings.PoseFreeze = VRMExporterValidator.HasRotationOrScale(go);
|
||||
}
|
||||
|
||||
wiz.OnWizardUpdate();
|
||||
@@ -681,23 +434,7 @@ namespace VRM
|
||||
void OnWizardUpdate()
|
||||
{
|
||||
UpdateRoot(ExportRoot);
|
||||
|
||||
m_validations.Clear();
|
||||
m_validations.AddRange(Validate());
|
||||
|
||||
if (ExportRoot != null)
|
||||
{
|
||||
m_validations.AddRange(VRMSpringBoneValidator.Validate(ExportRoot));
|
||||
var firstPerson = ExportRoot.GetComponent<VRMFirstPerson>();
|
||||
if (firstPerson != null)
|
||||
{
|
||||
m_validations.AddRange(firstPerson.Validate());
|
||||
}
|
||||
}
|
||||
|
||||
var hasError = m_validations.Any(x => !x.CanExport);
|
||||
m_IsValid = !hasError && !MetaHasError;
|
||||
|
||||
m_requireValidation = true;
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace VRM
|
||||
[TestCase("AliciaAliciaAliciaAliciaAliciaAliciaAliciaAliciaAliciaAliciaAliciaAlicia", true)]
|
||||
public void DetectFileNameLength(string fileName, bool isIllegal)
|
||||
{
|
||||
var result = VRMExporterWizard.IsFileNameLengthTooLong(fileName);
|
||||
var result = VRMExporterValidator.IsFileNameLengthTooLong(fileName);
|
||||
Assert.AreEqual(result, isIllegal);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user