您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
307 行
9.7 KiB
307 行
9.7 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UniGLTF;
|
|
using UniGLTF.M17N;
|
|
using UniGLTF.MeshUtility;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using VrmLib;
|
|
using VRMShaders;
|
|
|
|
namespace UniVRM10
|
|
{
|
|
public class VRM10ExportDialog : ExportDialogBase
|
|
{
|
|
public static void Open()
|
|
{
|
|
var window = (VRM10ExportDialog)GetWindow(typeof(VRM10ExportDialog));
|
|
window.titleContent = new GUIContent("VRM-1.0 Exporter");
|
|
window.Show();
|
|
}
|
|
|
|
|
|
enum Tabs
|
|
{
|
|
Meta,
|
|
Mesh,
|
|
ExportSettings,
|
|
}
|
|
Tabs _tab;
|
|
|
|
|
|
VRM10ExportSettings m_settings;
|
|
Editor m_settingsInspector;
|
|
|
|
|
|
MeshExportValidator m_meshes;
|
|
Editor m_meshesInspector;
|
|
|
|
VRM10Object m_meta;
|
|
VRM10Object Vrm
|
|
{
|
|
get { return m_meta; }
|
|
set
|
|
{
|
|
if (value != null && AssetDatabase.IsSubAsset(value))
|
|
{
|
|
// SubAsset is readonly. copy
|
|
Debug.Log("copy VRM10ObjectMeta");
|
|
value.Meta.CopyTo(m_tmpObject.Meta);
|
|
return;
|
|
}
|
|
|
|
if (m_meta == value)
|
|
{
|
|
return;
|
|
}
|
|
m_metaEditor = default;
|
|
m_meta = value;
|
|
}
|
|
}
|
|
VRM10Object m_tmpObject;
|
|
VRM10MetaEditor m_metaEditor;
|
|
|
|
protected override void Initialize()
|
|
{
|
|
m_tmpObject = ScriptableObject.CreateInstance<VRM10Object>();
|
|
m_tmpObject.name = "_vrm1_";
|
|
m_tmpObject.Meta.Authors = new List<string> { "" };
|
|
|
|
m_settings = ScriptableObject.CreateInstance<VRM10ExportSettings>();
|
|
m_settingsInspector = Editor.CreateEditor(m_settings);
|
|
|
|
m_meshes = ScriptableObject.CreateInstance<MeshExportValidator>();
|
|
m_meshesInspector = Editor.CreateEditor(m_meshes);
|
|
|
|
State.ExportRootChanged += (root) =>
|
|
{
|
|
// update meta
|
|
if (root == null)
|
|
{
|
|
Vrm = null;
|
|
}
|
|
else
|
|
{
|
|
var controller = root.GetComponent<Vrm10Instance>();
|
|
if (controller != null)
|
|
{
|
|
Vrm = controller.Vrm;
|
|
}
|
|
else
|
|
{
|
|
Vrm = null;
|
|
}
|
|
|
|
// default setting
|
|
// m_settings.PoseFreeze =
|
|
// MeshUtility.Validators.HumanoidValidator.HasRotationOrScale(root)
|
|
// || m_meshes.Meshes.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning)
|
|
// ;
|
|
}
|
|
};
|
|
}
|
|
|
|
protected override void Clear()
|
|
{
|
|
// m_settingsInspector
|
|
UnityEditor.Editor.DestroyImmediate(m_settingsInspector);
|
|
m_settingsInspector = null;
|
|
// m_meshesInspector
|
|
UnityEditor.Editor.DestroyImmediate(m_meshesInspector);
|
|
m_meshesInspector = null;
|
|
// Meta
|
|
Vrm = null;
|
|
ScriptableObject.DestroyImmediate(m_tmpObject);
|
|
m_tmpObject = null;
|
|
// m_settings
|
|
ScriptableObject.DestroyImmediate(m_settings);
|
|
m_settings = null;
|
|
// m_meshes
|
|
ScriptableObject.DestroyImmediate(m_meshes);
|
|
m_meshes = null;
|
|
}
|
|
|
|
protected override IEnumerable<Validator> ValidatorFactory()
|
|
{
|
|
HumanoidValidator.MeshInformations = m_meshes.Meshes;
|
|
// HumanoidValidator.EnableFreeze = m_settings.PoseFreeze;
|
|
|
|
yield return HierarchyValidator.Validate;
|
|
if (!State.ExportRoot)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
// Mesh/Renderer のチェック
|
|
m_meshes.MaterialValidator = new VRM10MaterialValidator();
|
|
yield return m_meshes.Validate;
|
|
|
|
yield return HumanoidValidator.Validate_TPose;
|
|
|
|
// MeshUtility.Validators.HumanoidValidator.EnableFreeze = false;
|
|
// yield return MeshUtility.Validators.HumanoidValidator.Validate;
|
|
|
|
// yield return VRMExporterValidator.Validate;
|
|
// yield return VRMSpringBoneValidator.Validate;
|
|
|
|
// var firstPerson = State.ExportRoot.GetComponent<VRMFirstPerson>();
|
|
// if (firstPerson != null)
|
|
// {
|
|
// yield return firstPerson.Validate;
|
|
// }
|
|
|
|
// var proxy = State.ExportRoot.GetComponent<VRMBlendShapeProxy>();
|
|
// if (proxy != null)
|
|
// {
|
|
// yield return proxy.Validate;
|
|
// }
|
|
|
|
var vrm = Vrm ? Vrm : m_tmpObject;
|
|
yield return vrm.Meta.Validate;
|
|
}
|
|
|
|
protected override void OnLayout()
|
|
{
|
|
// m_settings, m_meshes.Meshes
|
|
m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings, new DefualtBlendShapeExportFilter());
|
|
}
|
|
|
|
protected override bool DoGUI(bool isValid)
|
|
{
|
|
if (State.ExportRoot == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (State.ExportRoot.GetComponent<Animator>() != null)
|
|
{
|
|
var backup = GUI.enabled;
|
|
GUI.enabled = State.ExportRoot.scene.IsValid();
|
|
if (GUI.enabled)
|
|
{
|
|
EditorGUILayout.HelpBox(EnableTPose.ENALBE_TPOSE_BUTTON.Msg(), MessageType.Info);
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.HelpBox(EnableTPose.DISABLE_TPOSE_BUTTON.Msg(), MessageType.Warning);
|
|
}
|
|
|
|
if (GUILayout.Button("T-Pose" + "(unity internal)"))
|
|
{
|
|
if (State.ExportRoot != null)
|
|
{
|
|
Undo.RecordObjects(State.ExportRoot.GetComponentsInChildren<Transform>(), "tpose.internal");
|
|
if (InternalTPose.TryMakePoseValid(State.ExportRoot))
|
|
{
|
|
// done
|
|
Repaint();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("not found");
|
|
}
|
|
}
|
|
}
|
|
|
|
GUI.enabled = backup;
|
|
}
|
|
|
|
if (!isValid)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_tmpObject == null)
|
|
{
|
|
// disabled
|
|
return false;
|
|
}
|
|
|
|
// tabbar
|
|
_tab = TabBar.OnGUI(_tab);
|
|
switch (_tab)
|
|
{
|
|
case Tabs.Meta:
|
|
if (m_metaEditor == null)
|
|
{
|
|
SerializedObject so;
|
|
if (m_meta != null)
|
|
{
|
|
so = new SerializedObject(Vrm);
|
|
}
|
|
else
|
|
{
|
|
so = new SerializedObject(m_tmpObject);
|
|
}
|
|
m_metaEditor = VRM10MetaEditor.Create(so);
|
|
}
|
|
m_metaEditor.OnInspectorGUI();
|
|
break;
|
|
|
|
case Tabs.Mesh:
|
|
m_meshesInspector.OnInspectorGUI();
|
|
break;
|
|
|
|
case Tabs.ExportSettings:
|
|
m_settingsInspector.OnInspectorGUI();
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected override string SaveTitle => "Vrm1";
|
|
protected override string SaveName => $"{State.ExportRoot.name}.vrm";
|
|
protected override string[] SaveExtensions => new string[] { "vrm" };
|
|
|
|
string m_logLabel;
|
|
|
|
protected override void ExportPath(string path)
|
|
{
|
|
m_logLabel = "";
|
|
|
|
m_logLabel += $"export...\n";
|
|
|
|
var root = State.ExportRoot;
|
|
|
|
try
|
|
{
|
|
using (var arrayManager = new NativeArrayManager())
|
|
{
|
|
var converter = new UniVRM10.ModelExporter();
|
|
var model = converter.Export(arrayManager, root);
|
|
// 右手系に変換
|
|
m_logLabel += $"convert to right handed coordinate...\n";
|
|
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
|
|
// export vrm-1.0
|
|
var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer(), m_settings.MeshExportSettings);
|
|
var option = new VrmLib.ExportArgs
|
|
{
|
|
sparse = m_settings.MorphTargetUseSparse,
|
|
};
|
|
exporter.Export(root, model, converter, option, Vrm ? Vrm.Meta : m_tmpObject.Meta);
|
|
|
|
var exportedBytes = exporter.Storage.ToGlbBytes();
|
|
|
|
m_logLabel += $"write to {path}...\n";
|
|
File.WriteAllBytes(path, exportedBytes);
|
|
Debug.Log("exportedBytes: " + exportedBytes.Length);
|
|
|
|
var assetPath = UniGLTF.UnityPath.FromFullpath(path);
|
|
if (assetPath.IsUnderWritableFolder)
|
|
{
|
|
// asset folder 内。import を発動
|
|
assetPath.ImportAsset();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
m_logLabel += ex.ToString();
|
|
// rethrow
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|