Skip to content

Commit

Permalink
Merge pull request #505 from ousttrue/new_dialog
Browse files Browse the repository at this point in the history
エクスポートダイアログをScriptableWizardからEditorWindowで作り直し
  • Loading branch information
ousttrue authored Aug 12, 2020
2 parents f3f938b + 877c40f commit 440bd58
Show file tree
Hide file tree
Showing 15 changed files with 1,116 additions and 498 deletions.
22 changes: 11 additions & 11 deletions Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ public static class VRMEditorExporter
/// </summary>
/// <param name="path">出力先</param>
/// <param name="settings">エクスポート設定</param>
public static void Export(string path, VRMExportSettings settings)
public static void Export(string path, GameObject exportRoot, VRMExportSettings settings)
{
List<GameObject> destroy = new List<GameObject>();
try
{
Export(path, settings, destroy);
Export(path, exportRoot, settings, destroy);
}
finally
{
Expand Down Expand Up @@ -136,18 +136,18 @@ static void ForceUniqueName(Transform transform, Dictionary<string, int> nameCou
/// <param name="path"></param>
/// <param name="settings"></param>
/// <param name="destroy">作業が終わったらDestoryするべき一時オブジェクト</param>
static void Export(string path, VRMExportSettings settings, List<GameObject> destroy)
static void Export(string path, GameObject exportRoot, VRMExportSettings settings, List<GameObject> destroy)
{
var target = settings.Source;
var target = exportRoot;

// 常にコピーする。シーンを変化させない
target = GameObject.Instantiate(target);
destroy.Add(target);

{
// copy元
var animator = settings.Source.GetComponent<Animator>();
var beforeTransforms = settings.Source.GetComponentsInChildren<Transform>();
var animator = exportRoot.GetComponent<Animator>();
var beforeTransforms = exportRoot.GetComponentsInChildren<Transform>();
// copy先
var afterTransforms = target.GetComponentsInChildren<Transform>();
// copy先のhumanoidBoneのリストを得る
Expand Down Expand Up @@ -213,11 +213,11 @@ static void Export(string path, VRMExportSettings settings, List<GameObject> des
ExportOnlyBlendShapePosition = settings.OnlyBlendshapePosition,
RemoveVertexColor = settings.RemoveVertexColor
});
vrm.extensions.VRM.meta.title = settings.Title;
vrm.extensions.VRM.meta.version = settings.Version;
vrm.extensions.VRM.meta.author = settings.Author;
vrm.extensions.VRM.meta.contactInformation = settings.ContactInformation;
vrm.extensions.VRM.meta.reference = settings.Reference;
// vrm.extensions.VRM.meta.title = settings.Title;
// vrm.extensions.VRM.meta.version = settings.Version;
// vrm.extensions.VRM.meta.author = settings.Author;
// vrm.extensions.VRM.meta.contactInformation = settings.ContactInformation;
// vrm.extensions.VRM.meta.reference = settings.Reference;

var bytes = vrm.ToGlbBytes(settings.UseExperimentalExporter ? SerializerTypes.Generated : SerializerTypes.UniJSON);
File.WriteAllBytes(path, bytes);
Expand Down
298 changes: 3 additions & 295 deletions Assets/VRM/UniVRM/Editor/Format/VRMExportSettings.cs
Original file line number Diff line number Diff line change
@@ -1,49 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF;
using UnityEditor;
using UnityEngine;


namespace VRM
{
[Serializable]
public class VRMExportSettings
public class VRMExportSettings : ScriptableObject
{
/// <summary>
/// エクスポート対象
/// </summary>
public GameObject Source;

#region Meta
/// <summary>
/// エクスポート名
/// </summary>
public string Title;

/// <summary>
/// エクスポートバージョン(エクスポートするModelのバージョン)
/// </summary>
public string Version;

/// <summary>
/// 作者
/// </summary>
public string Author;

/// <summary>
/// 作者連絡先
/// </summary>
public string ContactInformation;

/// <summary>
/// 作品引用
/// </summary>
public string Reference;
#endregion

#region Settings
/// <summary>
/// エクスポート時に強制的にT-Pose化する
/// </summary>
Expand Down Expand Up @@ -91,259 +53,5 @@ public class VRMExportSettings
/// </summary>
[Tooltip("Remove vertex color")]
public bool RemoveVertexColor = false;
#endregion

public static bool IsFileNameLengthTooLong(string fileName)
{
return fileName.Length > 64;
}

public struct Validation
{
/// <summary>
/// エクスポート可能か否か。
/// true のメッセージは警告
/// false のメッセージはエラー
/// </summary>
public readonly bool CanExport;
public readonly String Message;

Validation(bool canExport, string message)
{
CanExport = canExport;
Message = message;
}

public static Validation Error(string msg)
{
return new Validation(false, msg);
}

public static Validation Warning(string msg)
{
return new Validation(true, msg);
}
}

/// <summary>
/// ボーン名の重複を確認
/// </summary>
/// <returns></returns>
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());
}

/// <summary>
/// エクスポート可能か検証する
/// </summary>
/// <returns></returns>
public IEnumerable<Validation> Validate()
{
if (Source == null)
{
yield return Validation.Error("Require source");
yield break;
}

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 = Source.GetComponent<Animator>();
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");
}

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 (string.IsNullOrEmpty(Title))
{
yield return Validation.Error("Require Title. ");
}
if (string.IsNullOrEmpty(Version))
{
yield return Validation.Error("Require Version. ");
}
if (string.IsNullOrEmpty(Author))
{
yield return Validation.Error("Require Author. ");
}

if (ReduceBlendshape && Source.GetComponent<VRMBlendShapeProxy>() == null)
{
yield return Validation.Error("ReduceBlendshapeSize needs VRMBlendShapeProxy. You need to convert to VRM once.");
}

var vertexColor = Source.GetComponentsInChildren<SkinnedMeshRenderer>().Any(x => x.sharedMesh.colors.Length > 0);
if (vertexColor)
{
yield return Validation.Warning("This model contains vertex color");
}

var renderers = Source.GetComponentsInChildren<Renderer>();
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;
}

if (VRMMaterialExporter.UseUnlit(material.shader.name))
{
// unlit
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));
}

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<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(string.Format("FileName '{0}' is too long. ", textureName));
}

var vrmMeta = Source.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(string.Format("FileName '{0}' is too long. ", thumbnailName));
}

var meshFilters = Source.GetComponentsInChildren<MeshFilter>();
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 = Source.GetComponentsInChildren<SkinnedMeshRenderer>();
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));
}
}

/// <summary>
/// 対象のモデルからMeta情報を取得し、エクスポート設定を初期する
/// </summary>
/// <param name="go"></param>
public void InitializeFrom(GameObject go)
{
if (Source == go) return;
Source = go;

//
// initialize
//
var desc = Source == null ? null : go.GetComponent<VRMHumanoidDescription>();
if (desc == null)
{
// 初回のVRMエクスポートとみなす
ForceTPose = false; // option
PoseFreeze = true;
}
else
{
// すでに正規化済みとみなす
ForceTPose = false;
PoseFreeze = false;
}

//
// Meta
//
var meta = Source == null ? null : go.GetComponent<VRMMeta>();
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";
}
}
}
}
}
}
Loading

0 comments on commit 440bd58

Please sign in to comment.