From cc5a04a308576a67a8f8b85ad42242096237e3a5 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2020 15:54:50 +0900 Subject: [PATCH 1/5] =?UTF-8?q?VRMExporterVaildator.cs=20=E3=81=AB?= =?UTF-8?q?=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Editor/Format/VRMExporterVaildator.cs | 307 +++++++++++++++++ .../Format/VRMExporterVaildator.cs.meta | 11 + .../UniVRM/Editor/Format/VRMExporterWizard.cs | 325 ++---------------- .../Editor/Tests/InvalidFileNameTest.cs | 2 +- 4 files changed, 348 insertions(+), 297 deletions(-) create mode 100644 Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs create mode 100644 Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs.meta diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs new file mode 100644 index 000000000..9182dbf50 --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs @@ -0,0 +1,307 @@ +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 m_validations = new List(); + public IEnumerable Validations => m_validations; + + + /// + /// ボーン名の重複を確認 + /// + /// + bool DuplicateBoneNameExists(GameObject ExportRoot) + { + if (ExportRoot == null) + { + return false; + } + var bones = ExportRoot.transform.GetComponentsInChildren(); + 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()) + { + 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); + } + + /// + /// ExportDialogを表示する前に確認する。 + /// + /// + /// + /// + 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(); + 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(); + 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; + } + + /// + /// エクスポート可能か検証する + /// + /// + public void Validate(GameObject ExportRoot, VRMExportSettings m_settings, VRMMetaObject meta) + { + m_validations.Clear(); + m_validations.AddRange(_Validate(ExportRoot, m_settings)); + if (ExportRoot != null) + { + m_validations.AddRange(VRMSpringBoneValidator.Validate(ExportRoot)); + var firstPerson = ExportRoot.GetComponent(); + if (firstPerson != null) + { + m_validations.AddRange(firstPerson.Validate()); + } + } + MetaHasError = meta.Validate().Any(); + } + + IEnumerable _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() == null) + { + yield return Validation.Error(Msg(VRMExporterWizardMessages.NEEDS_VRM_BLENDSHAPE_PROXY)); + } + + var vertexColor = ExportRoot.GetComponentsInChildren().Any(x => x.sharedMesh.colors.Length > 0); + if (vertexColor) + { + yield return Validation.Warning(Msg(VRMExporterWizardMessages.VERTEX_COLOR_IS_INCLUDED)); + } + + var renderers = ExportRoot.GetComponentsInChildren(); + 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(); + 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(); + 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(); + 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(); + 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); + } + } + } +} diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs.meta b/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs.meta new file mode 100644 index 000000000..c28dfe80f --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc233cbadb897eb4886de9927bee9fc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs index 7e8ec4fa9..3afefe04d 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs @@ -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(); if (meta != null) @@ -88,178 +77,13 @@ namespace VRM } } - /// - /// ボーン名の重複を確認 - /// - /// - bool DuplicateBoneNameExists() - { - if (ExportRoot == null) - { - return false; - } - var bones = ExportRoot.transform.GetComponentsInChildren(); - 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()) - { - 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); - } - - /// - /// エクスポート可能か検証する - /// - /// - public IEnumerable Validate() - { - if (ExportRoot == null) - { - yield break; - } - - if (DuplicateBoneNameExists()) - { - yield return Validation.Warning(Msg(VRMExporterWizardMessages.DUPLICATE_BONE_NAME_EXISTS)); - } - - if (m_settings.ReduceBlendshape && ExportRoot.GetComponent() == null) - { - yield return Validation.Error(Msg(VRMExporterWizardMessages.NEEDS_VRM_BLENDSHAPE_PROXY)); - } - - var vertexColor = ExportRoot.GetComponentsInChildren().Any(x => x.sharedMesh.colors.Length > 0); - if (vertexColor) - { - yield return Validation.Warning(Msg(VRMExporterWizardMessages.VERTEX_COLOR_IS_INCLUDED)); - } - - var renderers = ExportRoot.GetComponentsInChildren(); - 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(); - 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(); - 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(); - 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(); - 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 m_validations = new List(); + VRMExporterValidator m_validator = new VRMExporterValidator(); + bool m_requireValidation = true; private Vector2 m_ScrollPosition; private string m_CreateButton = "Create"; @@ -351,102 +175,28 @@ 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(); - 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(); - 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); - } - - // validation - foreach (var v in m_validations) + // + // その他の Validation + // + foreach (var v in m_validator.Validations) { v.DrawGUI(); } @@ -466,7 +216,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 +249,12 @@ namespace VRM } GUILayout.Space(8); + + if (modified) + { + m_requireValidation = true; + Repaint(); + } } enum Tabs @@ -626,13 +382,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 +397,7 @@ namespace VRM if (go != null) { - wiz.m_settings.PoseFreeze = HasRotationOrScale(go); + wiz.m_settings.PoseFreeze = VRMExporterValidator.HasRotationOrScale(go); } wiz.OnWizardUpdate(); @@ -681,23 +430,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(); - if (firstPerson != null) - { - m_validations.AddRange(firstPerson.Validate()); - } - } - - var hasError = m_validations.Any(x => !x.CanExport); - m_IsValid = !hasError && !MetaHasError; - + m_requireValidation = true; Repaint(); } } diff --git a/Assets/VRM/UniVRM/Editor/Tests/InvalidFileNameTest.cs b/Assets/VRM/UniVRM/Editor/Tests/InvalidFileNameTest.cs index d7727ce78..003027f5f 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/InvalidFileNameTest.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/InvalidFileNameTest.cs @@ -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); } From 70f62853e0c29ece9f9d5b00e9f773a70ccf5d76 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2020 16:00:35 +0900 Subject: [PATCH 2/5] =?UTF-8?q?Scroll=E3=82=A8=E3=83=AA=E3=82=A2=E3=81=ABV?= =?UTF-8?q?alidation=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC=E3=82=B8=E3=81=8C?= =?UTF-8?q?=E5=85=A5=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs index 3afefe04d..d6bef9e86 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs @@ -193,6 +193,10 @@ namespace VRM return; } + // Render contents using Generic Inspector GUI + m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); + GUIUtility.GetControlID(645789, FocusType.Passive); + // // その他の Validation // @@ -201,9 +205,6 @@ namespace VRM v.DrawGUI(); } - // Render contents using Generic Inspector GUI - m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); - GUIUtility.GetControlID(645789, FocusType.Passive); bool modified = DrawWizardGUI(); EditorGUILayout.EndScrollView(); From 8efcc3da0988faf792c50bdd9a80d1d82fb08e7d Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2020 17:33:26 +0900 Subject: [PATCH 3/5] fix null check --- Assets/VRM/UniVRM/Editor/FirstPerson/VRMFirstPersonValidator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/VRM/UniVRM/Editor/FirstPerson/VRMFirstPersonValidator.cs b/Assets/VRM/UniVRM/Editor/FirstPerson/VRMFirstPersonValidator.cs index c74b74195..acb8540ef 100644 --- a/Assets/VRM/UniVRM/Editor/FirstPerson/VRMFirstPersonValidator.cs +++ b/Assets/VRM/UniVRM/Editor/FirstPerson/VRMFirstPersonValidator.cs @@ -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)) { From 75484b1785e3e833f94bee76f3c294541871eb09 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2020 18:10:54 +0900 Subject: [PATCH 4/5] =?UTF-8?q?tab=20=E3=82=92=E3=82=B9=E3=82=AF=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=83=AB=E3=82=A8=E3=83=AA=E3=82=A2=E3=81=AE=E5=A4=96?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs index d6bef9e86..127d8e2fa 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs @@ -193,6 +193,10 @@ namespace VRM return; } + EditorGUILayout.HelpBox($"Mesh size: {m_validator.ExpectedByteSize / 1000000.0f:0.0} MByte", MessageType.Info); + + _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); @@ -279,7 +283,6 @@ namespace VRM } // tabbar - _tab = TabBar.OnGUI(_tab, TabButtonStyle, TabButtonSize); switch (_tab) { case Tabs.Meta: From a153f30898dde9c53a833b65d2e0a009e0890fff Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2020 18:11:51 +0900 Subject: [PATCH 5/5] =?UTF-8?q?Mesh=E3=82=B5=E3=82=A4=E3=82=BA=E3=81=AE?= =?UTF-8?q?=E4=BA=8B=E5=89=8D=E8=A8=88=E7=AE=97=E3=80=82ReduceBlendShape?= =?UTF-8?q?=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Editor/Format/VRMExporterVaildator.cs | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs index 9182dbf50..3a1fd6ea2 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterVaildator.cs @@ -22,6 +22,7 @@ namespace VRM List m_validations = new List(); public IEnumerable Validations => m_validations; + public int ExpectedByteSize = 0; /// /// ボーン名の重複を確認 @@ -187,6 +188,11 @@ namespace VRM 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) { @@ -198,6 +204,103 @@ namespace VRM } } MetaHasError = meta.Validate().Any(); + + // サイズ の 計算 + var proxy = ExportRoot.GetComponent(); + var clips = new List(); + if (proxy != null && proxy.BlendShapeAvatar != null) + { + clips.AddRange(proxy.BlendShapeAvatar.Clips); + } + + ExpectedByteSize = 0; + foreach (var renderer in ExportRoot.GetComponentsInChildren()) + { + var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, ExportRoot.transform); + var mesh = GetMesh(renderer); + ExpectedByteSize += CalcMeshSize(relativePath, mesh, m_settings, clips); + } + } + + static bool ClipsContainsName(List 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 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(); + if (f != null) + { + return f.sharedMesh; + } + } + return null; } IEnumerable _Validate(GameObject ExportRoot, VRMExportSettings m_settings)