diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs b/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs index a8c30903b..c9f88f170 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs @@ -16,12 +16,12 @@ namespace VRM /// /// 出力先 /// エクスポート設定 - public static void Export(string path, VRMExportSettings settings) + public static void Export(string path, GameObject exportRoot, VRMExportSettings settings) { List destroy = new List(); try { - Export(path, settings, destroy); + Export(path, exportRoot, settings, destroy); } finally { @@ -136,9 +136,9 @@ namespace VRM /// /// /// 作業が終わったらDestoryするべき一時オブジェクト - static void Export(string path, VRMExportSettings settings, List destroy) + static void Export(string path, GameObject exportRoot, VRMExportSettings settings, List destroy) { - var target = settings.Source; + var target = exportRoot; // 常にコピーする。シーンを変化させない target = GameObject.Instantiate(target); @@ -146,8 +146,8 @@ namespace VRM { // copy元 - var animator = settings.Source.GetComponent(); - var beforeTransforms = settings.Source.GetComponentsInChildren(); + var animator = exportRoot.GetComponent(); + var beforeTransforms = exportRoot.GetComponentsInChildren(); // copy先 var afterTransforms = target.GetComponentsInChildren(); // copy先のhumanoidBoneのリストを得る diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExportSettings.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExportSettings.cs index 368a602cf..62dc72c40 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExportSettings.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExportSettings.cs @@ -8,40 +8,8 @@ using UnityEngine; namespace VRM { [Serializable] - public class VRMExportSettings + public class VRMExportSettings : ScriptableObject { - /// - /// エクスポート対象 - /// - public GameObject Source; - - // #region Meta - // /// - // /// エクスポート名 - // /// - // public string Title; - - // /// - // /// エクスポートバージョン(エクスポートするModelのバージョン) - // /// - // public string Version; - - // /// - // /// 作者 - // /// - // public string Author; - - // /// - // /// 作者連絡先 - // /// - // public string ContactInformation; - - // /// - // /// 作品引用 - // /// - // public string Reference; - // #endregion - #region Settings /// /// エクスポート時に強制的にT-Pose化する @@ -97,216 +65,212 @@ namespace VRM return fileName.Length > 64; } + // /// + // /// ボーン名の重複を確認 + // /// + // /// + // bool DuplicateBoneNameExists() + // { + // var bones = ExportRoot.transform.Traverse().ToArray(); + // var duplicates = bones + // .GroupBy(p => p.name) + // .Where(g => g.Count() > 1) + // .Select(g => g.Key); - /// - /// ボーン名の重複を確認 - /// - /// - bool DuplicateBoneNameExists() - { - var bones = Source.transform.Traverse().ToArray(); - var duplicates = bones - .GroupBy(p => p.name) - .Where(g => g.Count() > 1) - .Select(g => g.Key); + // return (duplicates.Any()); + // } - return (duplicates.Any()); - } + // /// + // /// エクスポート可能か検証する + // /// + // /// + // public IEnumerable Validate() + // { + // if (ExportRoot == null) + // { + // yield return Validation.Error("Require source"); + // yield break; + // } - /// - /// エクスポート可能か検証する - /// - /// - public IEnumerable Validate() - { - if (Source == null) - { - yield return Validation.Error("Require source"); - yield break; - } + // if (ExportRoot.transform.position != Vector3.zero || + // ExportRoot.transform.rotation != Quaternion.identity || + // ExportRoot.transform.localScale != Vector3.one) + // { + // // EditorUtility.DisplayDialog("Error", "The Root transform should have Default translation, rotation and scale.", "ok"); + // yield return Validation.Warning("The Root translation, rotation and scale will be dropped."); + // } - if (Source.transform.position != Vector3.zero || - Source.transform.rotation != Quaternion.identity || - Source.transform.localScale != Vector3.one) - { - // EditorUtility.DisplayDialog("Error", "The Root transform should have Default translation, rotation and scale.", "ok"); - yield return Validation.Warning("The Root translation, rotation and scale will be dropped."); - } + // var animator = ExportRoot.GetComponent(); + // if (animator == null) + // { + // yield return Validation.Error("Require animator. "); + // } + // else + // { + // if (animator.avatar == null) + // { + // yield return Validation.Error("Require animator.avatar. "); + // } + // else if (!animator.avatar.isValid) + // { + // yield return Validation.Error("Animator.avatar is not valid. "); + // } + // else if (!animator.avatar.isHuman) + // { + // yield return Validation.Error("Animator.avatar is not humanoid. Please change model's AnimationType to humanoid. "); + // } - var animator = Source.GetComponent(); - if (animator == null) - { - yield return Validation.Error("Require animator. "); - } - else - { - if (animator.avatar == null) - { - yield return Validation.Error("Require animator.avatar. "); - } - else if (!animator.avatar.isValid) - { - yield return Validation.Error("Animator.avatar is not valid. "); - } - else if (!animator.avatar.isHuman) - { - yield return Validation.Error("Animator.avatar is not humanoid. Please change model's AnimationType to humanoid. "); - } + // var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw); + // if (jaw != null) + // { + // yield return Validation.Warning("Jaw bone is included. It may not be what you intended. Please check the humanoid avatar setting screen"); + // } + // } - var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw); - if (jaw != null) - { - yield return Validation.Warning("Jaw bone is included. It may not be what you intended. Please check the humanoid avatar setting screen"); - } - } + // if (DuplicateBoneNameExists()) + // { + // yield return Validation.Warning("There is a bone with the same name in the hierarchy. If exported, these bones will be automatically renamed."); + // } - if (DuplicateBoneNameExists()) - { - yield return Validation.Warning("There is a bone with the same name in the hierarchy. If exported, these bones will be automatically renamed."); - } + // if (ReduceBlendshape && ExportRoot.GetComponent() == null) + // { + // yield return Validation.Error("ReduceBlendshapeSize needs VRMBlendShapeProxy. You need to convert to VRM once."); + // } - if (ReduceBlendshape && Source.GetComponent() == null) - { - yield return Validation.Error("ReduceBlendshapeSize needs VRMBlendShapeProxy. You need to convert to VRM once."); - } + // var vertexColor = ExportRoot.GetComponentsInChildren().Any(x => x.sharedMesh.colors.Length > 0); + // if (vertexColor) + // { + // yield return Validation.Warning("This model contains vertex color"); + // } - var vertexColor = Source.GetComponentsInChildren().Any(x => x.sharedMesh.colors.Length > 0); - if (vertexColor) - { - yield return Validation.Warning("This model contains vertex color"); - } + // var renderers = ExportRoot.GetComponentsInChildren(); + // if (renderers.All(x => !x.gameObject.activeInHierarchy)) + // { + // yield return Validation.Error("No active mesh"); + // } - var renderers = Source.GetComponentsInChildren(); - if (renderers.All(x => !x.gameObject.activeInHierarchy)) - { - yield return Validation.Error("No active mesh"); - } + // var materials = renderers.SelectMany(x => x.sharedMaterials).Distinct(); + // foreach (var material in materials) + // { + // if (material.shader.name == "Standard") + // { + // // standard + // continue; + // } - 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.UseUnlit(material.shader.name)) - { - // unlit - continue; - } + // if (VRMMaterialExporter.VRMExtensionShaders.Contains(material.shader.name)) + // { + // // VRM supported + // continue; + // } - if (VRMMaterialExporter.VRMExtensionShaders.Contains(material.shader.name)) - { - // VRM supported - continue; - } + // yield return Validation.Warning(string.Format("{0}: unknown shader '{1}' is used. this will export as `Standard` fallback", + // material.name, + // material.shader.name)); + // } - yield return Validation.Warning(string.Format("{0}: unknown shader '{1}' is used. this will export as `Standard` fallback", - material.name, - material.shader.name)); - } + // foreach (var material in materials) + // { + // if (IsFileNameLengthTooLong(material.name)) + // yield return Validation.Error(string.Format("FileName '{0}' is too long. ", material.name)); + // } - foreach (var material in materials) - { - if (IsFileNameLengthTooLong(material.name)) - yield return Validation.Error(string.Format("FileName '{0}' is 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); + // } + // } + // } + // } - 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(string.Format("FileName '{0}' is too long. ", textureName)); + // } - foreach (var textureName in textureNameList) - { - if (IsFileNameLengthTooLong(textureName)) - yield return Validation.Error(string.Format("FileName '{0}' is 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(string.Format("FileName '{0}' is too long. ", thumbnailName)); + // } - var vrmMeta = Source.GetComponent(); - if (vrmMeta != null && vrmMeta.Meta != null && vrmMeta.Meta.Thumbnail != null) - { - var thumbnailName = vrmMeta.Meta.Thumbnail.name; - if (IsFileNameLengthTooLong(thumbnailName)) - yield return Validation.Error(string.Format("FileName '{0}' is 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(string.Format("FileName '{0}' is too long. ", meshName)); + // } - var meshFilters = Source.GetComponentsInChildren(); - var meshesName = meshFilters.Select(x => x.sharedMesh.name).Distinct(); - foreach (var meshName in meshesName) - { - if (IsFileNameLengthTooLong(meshName)) - yield return Validation.Error(string.Format("FileName '{0}' is 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(string.Format("FileName '{0}' is too long. ", skinnedmeshName)); + // } + // } - var skinnedmeshRenderers = Source.GetComponentsInChildren(); - var skinnedmeshesName = skinnedmeshRenderers.Select(x => x.sharedMesh.name).Distinct(); - foreach (var skinnedmeshName in skinnedmeshesName) - { - if (IsFileNameLengthTooLong(skinnedmeshName)) - yield return Validation.Error(string.Format("FileName '{0}' is too long. ", skinnedmeshName)); - } - } + // /// + // /// 対象のモデルからMeta情報を取得し、エクスポート設定を初期する + // /// + // /// + // public void InitializeFrom(GameObject go) + // { + // // + // // initialize + // // + // // var desc = ExportRoot == null ? null : go.GetComponent(); + // // if (desc == null) + // // { + // // // 初回のVRMエクスポートとみなす + // // ForceTPose = false; // option + // // PoseFreeze = true; + // // } + // // else + // // { + // // // すでに正規化済みとみなす + // // ForceTPose = false; + // // PoseFreeze = false; + // // } - /// - /// 対象のモデルからMeta情報を取得し、エクスポート設定を初期する - /// - /// - public void InitializeFrom(GameObject go) - { - if (Source == go) return; - Source = go; - - // - // initialize - // - var desc = Source == null ? null : go.GetComponent(); - if (desc == null) - { - // 初回のVRMエクスポートとみなす - ForceTPose = false; // option - PoseFreeze = true; - } - else - { - // すでに正規化済みとみなす - ForceTPose = false; - PoseFreeze = false; - } - - // - // Meta - // - var meta = Source == null ? null : go.GetComponent(); - // if (meta != null && meta.Meta != null) - // { - // Title = meta.Meta.Title; - // Version = string.IsNullOrEmpty(meta.Meta.Version) ? "0.0" : meta.Meta.Version; - // Author = meta.Meta.Author; - // ContactInformation = meta.Meta.ContactInformation; - // Reference = meta.Meta.Reference; - // } - // else - // { - // Title = go.name; - // Version = "0.0"; - // } - } + // // + // // Meta + // // + // // var meta = ExportRoot == null ? null : go.GetComponent(); + // // if (meta != null && meta.Meta != null) + // // { + // // Title = meta.Meta.Title; + // // Version = string.IsNullOrEmpty(meta.Meta.Version) ? "0.0" : meta.Meta.Version; + // // Author = meta.Meta.Author; + // // ContactInformation = meta.Meta.ContactInformation; + // // Reference = meta.Meta.Reference; + // // } + // // else + // // { + // // Title = go.name; + // // Version = "0.0"; + // // } + // } } } \ No newline at end of file diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterMenu.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterMenu.cs index 38bd6da80..53564a092 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterMenu.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterMenu.cs @@ -8,23 +8,23 @@ namespace VRM { const string CONVERT_HUMANOID_KEY = VRMVersion.MENU + "/Export humanoid"; - [MenuItem(CONVERT_HUMANOID_KEY, true, 1)] - private static bool ExportValidate() - { - var root = Selection.activeObject as GameObject; - if (root == null) - { - return false; - } + // [MenuItem(CONVERT_HUMANOID_KEY, true, 1)] + // private static bool ExportValidate() + // { + // var root = Selection.activeObject as GameObject; + // if (root == null) + // { + // return false; + // } - var animator = root.GetComponent(); - if (animator == null) - { - return false; - } + // var animator = root.GetComponent(); + // if (animator == null) + // { + // return false; + // } - return true; - } + // return true; + // } [MenuItem(CONVERT_HUMANOID_KEY, false, 1)] private static void ExportFromMenu() diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs index 0cc1013bf..684d91f89 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs @@ -15,7 +15,12 @@ namespace VRM public class VRMExporterWizard : EditorWindow { [SerializeField] - public VRMExportSettings m_settings = new VRMExportSettings(); + public GameObject ExportRoot; + + SerializedProperty m_exportRoot; + + [SerializeField] + public VRMExportSettings m_settings; VRMMetaObject m_meta; VRMMetaObject Meta @@ -24,16 +29,37 @@ namespace VRM set { if (m_meta == value) return; - if (m_meta != null) + if (m_metaEditor != null) { UnityEditor.Editor.DestroyImmediate(m_metaEditor); + m_metaEditor = null; } m_meta = value; - if (m_meta == null) + } + } + + void UpdateRoot(GameObject root) + { + if (root == ExportRoot) + { + return; + } + ExportRoot = root; + if (ExportRoot == null) + { + Meta = null; + } + else + { + var meta = ExportRoot.GetComponent(); + if (meta != null) { - m_meta = TmpMeta; + Meta = meta.Meta; + } + else + { + Meta = null; } - // m_metaEditor = Editor.CreateEditor(m_meta); } } @@ -66,6 +92,7 @@ namespace VRM UnityEditor.Editor.DestroyImmediate(m_Inspector); Meta = null; ScriptableObject.DestroyImmediate(m_tmpMeta); + ScriptableObject.DestroyImmediate(m_settings); } private void InvokeWizardUpdate() @@ -104,6 +131,10 @@ namespace VRM { EditorGUIUtility.labelWidth = 150; + EditorGUILayout.LabelField("ExportRoot"); + var root = (GameObject)EditorGUILayout.ObjectField(ExportRoot, typeof(GameObject), true); + UpdateRoot(root); + // Render contents using Generic Inspector GUI m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); GUIUtility.GetControlID(645789, FocusType.Passive); @@ -162,19 +193,32 @@ namespace VRM protected virtual bool DrawWizardGUI() { - if (Meta != null) { if (m_metaEditor == null) { - m_metaEditor = Editor.CreateEditor(Meta); + if (Meta != null) + { + m_metaEditor = Editor.CreateEditor(Meta); + } + else + { + m_metaEditor = Editor.CreateEditor(TmpMeta); + } } + EditorGUILayout.LabelField("Meta ", EditorStyles.boldLabel); m_metaEditor.OnInspectorGUI(); } { if (m_Inspector == null) { - m_Inspector = Editor.CreateEditor(this); + if (m_settings == null) + { + m_settings = ScriptableObject.CreateInstance(); + } + m_Inspector = Editor.CreateEditor(m_settings); } + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Export Settings ", EditorStyles.boldLabel); m_Inspector.OnInspectorGUI(); } return true; @@ -284,7 +328,7 @@ namespace VRM var go = Selection.activeObject as GameObject; // update checkbox - wiz.m_settings.InitializeFrom(go); + wiz.UpdateRoot(go); wiz.OnWizardUpdate(); } @@ -315,7 +359,7 @@ namespace VRM var path = EditorUtility.SaveFilePanel( "Save vrm", directory, - m_settings.Source.name + EXTENSION, + ExportRoot.name + EXTENSION, EXTENSION.Substring(1)); if (string.IsNullOrEmpty(path)) { @@ -324,41 +368,26 @@ namespace VRM m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); // export - VRMEditorExporter.Export(path, m_settings); + VRMEditorExporter.Export(path, ExportRoot, m_settings); } void OnWizardUpdate() { - m_validations.Clear(); - m_validations.AddRange(m_settings.Validate()); - if (Meta != null) - { - m_validations.AddRange(Meta.Validate()); - } - else - { - m_validations.Add(Validation.Error("meta がありません")); - } + // m_validations.Clear(); + // m_validations.AddRange(m_settings.Validate()); + // if (Meta != null) + // { + // m_validations.AddRange(Meta.Validate()); + // } + // else + // { + // m_validations.Add(Validation.Error("meta がありません")); + // } - var hasError = m_validations.Any(x => !x.CanExport); - m_IsValid = !hasError; + // var hasError = m_validations.Any(x => !x.CanExport); + // m_IsValid = !hasError; - if (m_settings.Source == null) - { - Meta = null; - } - else - { - var meta = m_settings.Source.GetComponent(); - if (meta != null) - { - Meta = meta.Meta; - } - else - { - Meta = null; - } - } + UpdateRoot(ExportRoot); Repaint(); // GUIUtility.ExitGUI(); diff --git a/Assets/VRM/UniVRM/Editor/Meta/VRMMetaObjectEditor.cs b/Assets/VRM/UniVRM/Editor/Meta/VRMMetaObjectEditor.cs index 3768e9459..5a6e21e80 100644 --- a/Assets/VRM/UniVRM/Editor/Meta/VRMMetaObjectEditor.cs +++ b/Assets/VRM/UniVRM/Editor/Meta/VRMMetaObjectEditor.cs @@ -87,10 +87,7 @@ namespace VRM private void OnEnable() { // m_ScriptProp = serializedObject.FindProperty("m_Script"); - if (serializedObject != null) - { - InitMap(serializedObject); - } + InitMap(serializedObject); } public override void OnInspectorGUI() @@ -115,6 +112,7 @@ namespace VRM so.Update(); GUI.enabled = false; + EditorGUILayout.PropertyField(m_propMap["ExporterVersion"]); if (VRMVersion.IsNewer(m_propMap["ExporterVersion"].stringValue)) { @@ -125,14 +123,15 @@ namespace VRM m_foldoutInfo = EditorGUILayout.Foldout(m_foldoutInfo, "Information"); if (m_foldoutInfo) { + // texture + var thumbnail = m_propMap["Thumbnail"]; + EditorGUILayout.PropertyField(thumbnail); + thumbnail.objectReferenceValue = TextureField("", (Texture2D)thumbnail.objectReferenceValue, 100); + foreach (var kv in m_customPropMap) { kv.Value.OnGUI(); } - - var thumbnail = m_propMap["Thumbnail"]; - EditorGUILayout.PropertyField(thumbnail); - thumbnail.objectReferenceValue = TextureField("", (Texture2D)thumbnail.objectReferenceValue, 100); } EditorGUILayout.LabelField("License ", EditorStyles.boldLabel); diff --git a/Assets/VRM/UniVRM/Scripts/Validation.cs.meta b/Assets/VRM/UniVRM/Scripts/Validation.cs.meta new file mode 100644 index 000000000..b7ff47730 --- /dev/null +++ b/Assets/VRM/UniVRM/Scripts/Validation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 703726d4973c85447a3bd2ae30c760f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: