From 83d759199ccc308b0105df51ab6830976b04b168 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 26 Feb 2021 13:34:41 +0900 Subject: [PATCH 1/4] GltfExportWindow.cs --- Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef | 1 + .../Editor/UniGLTF/GltfExportSettings.cs | 18 ++ .../Editor/UniGLTF/GltfExportSettings.cs.meta | 11 + .../Editor/UniGLTF/GltfExportWindow.cs | 248 ++++++++++++++++++ .../Editor/UniGLTF/GltfExportWindow.cs.meta | 11 + .../Valildators/HierarchyValidator.cs | 15 ++ .../Runtime/UniGLTF/IO/MeshExporter.cs | 1 + .../Runtime/UniGLTF/IO/gltfExporter.cs | 87 ------ 8 files changed, 305 insertions(+), 87 deletions(-) create mode 100644 Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs create mode 100644 Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs.meta create mode 100644 Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs create mode 100644 Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs.meta diff --git a/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef b/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef index 6c391dfbe..45229522d 100644 --- a/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef +++ b/Assets/UniGLTF/Editor/UniGLTF.Editor.asmdef @@ -2,6 +2,7 @@ "name": "UniGLTF.Editor", "references": [ "UniGLTF", + "MeshUtility", "MeshUtility.Editor" ], "optionalUnityReferences": [], diff --git a/Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs b/Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs new file mode 100644 index 000000000..843e47a5e --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs @@ -0,0 +1,18 @@ + + +using UnityEngine; + +namespace UniGLTF +{ + public class GltfExportSettings : ScriptableObject + { + public GameObject Root { get; set; } + + public Axises InverseAxis; + + [Header("MorphTarget(BlendShape)")] + public bool Sparse; + + public bool DropNormal; + } +} diff --git a/Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs.meta new file mode 100644 index 000000000..f8ffaa2a9 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/GltfExportSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e6d0977c916e05438394a6ea65b6a1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs new file mode 100644 index 000000000..9c89a3735 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs @@ -0,0 +1,248 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using MeshUtility.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF +{ + public class GltfExportWindow : EditorWindow + { + const string MENU_KEY = UniGLTFVersion.MENU + "/Export " + UniGLTFVersion.UNIGLTF_VERSION; + + [MenuItem(MENU_KEY, false, 0)] + private static void ExportFromMenu() + { + var window = (GltfExportWindow)GetWindow(typeof(GltfExportWindow)); + window.titleContent = new GUIContent("Gltf Exporter"); + window.Show(); + } + + private static void Export(GameObject go, string path, MeshExportSettings settings) + { + var ext = Path.GetExtension(path).ToLower(); + var isGlb = false; + switch (ext) + { + case ".glb": isGlb = true; break; + case ".gltf": isGlb = false; break; + default: throw new System.Exception(); + } + + var gltf = new glTF(); + using (var exporter = new gltfExporter(gltf)) + { + exporter.Prepare(go); + exporter.Export(settings); + } + + + if (isGlb) + { + var bytes = gltf.ToGlbBytes(); + File.WriteAllBytes(path, bytes); + } + else + { + var (json, buffers) = gltf.ToGltf(path); + // without BOM + var encoding = new System.Text.UTF8Encoding(false); + File.WriteAllText(path, json, encoding); + // write to local folder + var dir = Path.GetDirectoryName(path); + foreach (var b in buffers) + { + var bufferPath = Path.Combine(dir, b.uri); + File.WriteAllBytes(bufferPath, b.GetBytes().ToArray()); + } + } + + if (path.StartsWithUnityAssetPath()) + { + AssetDatabase.ImportAsset(path.ToUnityRelativePath()); + AssetDatabase.Refresh(); + } + } + + MeshUtility.ExporterDialogState m_state; + GltfExportSettings m_settings; + Editor m_settingsInspector; + + void OnEnable() + { + // Debug.Log("OnEnable"); + Undo.willFlushUndoRecord += Repaint; + Selection.selectionChanged += Repaint; + + m_settings = ScriptableObject.CreateInstance(); + m_settingsInspector = Editor.CreateEditor(m_settings); + + m_state = new MeshUtility.ExporterDialogState(); + m_state.ExportRootChanged += (root) => + { + Repaint(); + }; + m_state.ExportRoot = Selection.activeObject as GameObject; + } + + void OnDisable() + { + m_state.Dispose(); + + // Debug.Log("OnDisable"); + Selection.selectionChanged -= Repaint; + Undo.willFlushUndoRecord -= Repaint; + + // m_settingsInspector + UnityEditor.Editor.DestroyImmediate(m_settingsInspector); + m_settingsInspector = null; + // m_settings + ScriptableObject.DestroyImmediate(m_settings); + m_settings = null; + } + + public delegate Vector2 BeginVerticalScrollViewFunc(Vector2 scrollPosition, bool alwaysShowVertical, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options); + static BeginVerticalScrollViewFunc s_func; + static BeginVerticalScrollViewFunc BeginVerticalScrollView + { + get + { + if (s_func == null) + { + var methods = typeof(EditorGUILayout).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Where(x => x.Name == "BeginVerticalScrollView").ToArray(); + var method = methods.First(x => x.GetParameters()[1].ParameterType == typeof(bool)); + s_func = (BeginVerticalScrollViewFunc)method.CreateDelegate(typeof(BeginVerticalScrollViewFunc)); + } + return s_func; + } + } + private Vector2 m_ScrollPosition; + + IEnumerable ValidatorFactory() + { + yield return MeshUtility.Validators.HierarchyValidator.ValidateRoot; + if (!m_state.ExportRoot) + { + yield break; + } + } + + private void OnGUI() + { + // ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint Aborting + // Validation により GUI の表示項目が変わる場合があるので、 + // EventType.Layout と EventType.Repaint 間で内容が変わらないようしている。 + if (Event.current.type == EventType.Layout) + { + m_state.Validate(ValidatorFactory()); + } + + EditorGUIUtility.labelWidth = 150; + + // lang + MeshUtility.M17N.Getter.OnGuiSelectLang(); + + EditorGUILayout.LabelField("ExportRoot"); + { + m_state.ExportRoot = (GameObject)EditorGUILayout.ObjectField(m_state.ExportRoot, typeof(GameObject), true); + } + + // Render contents using Generic Inspector GUI + m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); + GUIUtility.GetControlID(645789, FocusType.Passive); + + bool modified = ScrollArea(); + + EditorGUILayout.EndScrollView(); + + // Create and Other Buttons + { + // errors + GUILayout.BeginVertical(); + // GUILayout.FlexibleSpace(); + + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUI.enabled = m_state.Validations.All(x => x.CanExport); + + if (GUILayout.Button("Export", GUILayout.MinWidth(100))) + { + OnExportClicked(m_state.ExportRoot, m_settings); + Close(); + GUIUtility.ExitGUI(); + } + GUI.enabled = true; + + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + } + + GUILayout.Space(8); + + if (modified) + { + m_state.Invalidate(); + } + } + + bool ScrollArea() + { + // + // Validation + // + foreach (var v in m_state.Validations) + { + v.DrawGUI(); + if (v.ErrorLevel == MeshUtility.ErrorLevels.Critical) + { + // Export UI を表示しない + return false; + } + } + + // + // GUI + // + m_settings.Root = m_state.ExportRoot; + m_settingsInspector.OnInspectorGUI(); + return true; + } + + private static string m_lastExportDir; + static void OnExportClicked(GameObject root, GltfExportSettings settings) + { + string directory; + if (string.IsNullOrEmpty(m_lastExportDir)) + { + directory = Directory.GetParent(Application.dataPath).ToString(); + } + else + { + directory = m_lastExportDir; + } + + // save dialog + var path = EditorUtility.SaveFilePanel( + "Save vrm", + directory, + root.name + ".glb", + "glb,gltf"); + if (string.IsNullOrEmpty(path)) + { + return; + } + m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); + + // export + Export(root, path, new MeshExportSettings + { + ExportOnlyBlendShapePosition = settings.DropNormal, + UseSparseAccessorForMorphTarget = settings.Sparse, + }); + } + } +} diff --git a/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs.meta new file mode 100644 index 000000000..c1d330c6e --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd4010850f4b6bf4e8c3cc58a5af9fc9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/Valildators/HierarchyValidator.cs b/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/Valildators/HierarchyValidator.cs index d54fc4061..5f7e238a2 100644 --- a/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/Valildators/HierarchyValidator.cs +++ b/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/Valildators/HierarchyValidator.cs @@ -62,6 +62,21 @@ namespace MeshUtility.Validators return false; } + public static IEnumerable ValidateRoot(GameObject ExportRoot) + { + if (ExportRoot == null) + { + yield return Validation.Critical(ExportValidatorMessages.ROOT_EXISTS.Msg()); + yield break; + } + + if (ExportRoot.transform.parent != null) + { + yield return Validation.Critical(ExportValidatorMessages.NO_PARENT.Msg()); + yield break; + } + } + public static IEnumerable Validate(GameObject ExportRoot) { if (ExportRoot == null) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs index c0f7c4318..d2cdd5270 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs @@ -5,6 +5,7 @@ using UnityEngine; namespace UniGLTF { + [Serializable] public struct MeshExportSettings { // MorphTarget に Sparse Accessor を使う diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index 9df3733ed..b34cf8d73 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -1,100 +1,13 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace UniGLTF { public class gltfExporter : IDisposable { - const string MENU_EXPORT_GLB_KEY = UniGLTFVersion.MENU + "/Export(glb)"; - const string MENU_EXPORT_GLTF_KEY = UniGLTFVersion.MENU + "/Export(gltf)"; - -#if UNITY_EDITOR - [MenuItem(MENU_EXPORT_GLTF_KEY, true, 1)] - [MenuItem(MENU_EXPORT_GLB_KEY, true, 1)] - private static bool ExportValidate() - { - return Selection.activeObject != null && Selection.activeObject is GameObject; - } - - [MenuItem(MENU_EXPORT_GLTF_KEY, priority = 0)] - private static void ExportGltfFromMenu() - { - ExportFromMenu(false, new MeshExportSettings - { - ExportOnlyBlendShapePosition = false, - UseSparseAccessorForMorphTarget = true, - }); - } - - [MenuItem(MENU_EXPORT_GLB_KEY, priority = 10)] - private static void ExportGlbFromMenu() - { - ExportFromMenu(true, MeshExportSettings.Default); - } - - private static void ExportFromMenu(bool isGlb, MeshExportSettings settings) - { - var go = Selection.activeObject as GameObject; - - var ext = isGlb ? "glb" : "gltf"; - - if (go.transform.position == Vector3.zero && - go.transform.rotation == Quaternion.identity && - go.transform.localScale == Vector3.one) - { - var path = EditorUtility.SaveFilePanel( - $"Save {ext}", "", go.name + $".{ext}", $"{ext}"); - if (string.IsNullOrEmpty(path)) - { - return; - } - - var gltf = new glTF(); - using (var exporter = new gltfExporter(gltf)) - { - exporter.Prepare(go); - exporter.Export(settings); - } - - if (isGlb) - { - var bytes = gltf.ToGlbBytes(); - File.WriteAllBytes(path, bytes); - } - else - { - var (json, buffers) = gltf.ToGltf(path); - // without BOM - var encoding = new System.Text.UTF8Encoding(false); - File.WriteAllText(path, json, encoding); - // write to local folder - var dir = Path.GetDirectoryName(path); - foreach (var b in buffers) - { - var bufferPath = Path.Combine(dir, b.uri); - File.WriteAllBytes(bufferPath, b.GetBytes().ToArray()); - } - } - - if (path.StartsWithUnityAssetPath()) - { - AssetDatabase.ImportAsset(path.ToUnityRelativePath()); - AssetDatabase.Refresh(); - } - } - else - { - EditorUtility.DisplayDialog("Error", "The Root transform should have Default translation, rotation and scale.", "ok"); - } - } -#endif protected glTF glTF; From e6a167b906df24edecbe42dc0b47dc9f42177972 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 26 Feb 2021 13:52:34 +0900 Subject: [PATCH 2/4] IAxisInverter --- .../Editor/UniGLTF/GltfExportWindow.cs | 1 + .../UniGLTF/IO/AnimationImporterUtil.cs | 2 +- Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs | 77 +++++++++++++++---- .../Runtime/UniGLTF/IO/ImporterContext.cs | 15 +--- .../Runtime/UniGLTF/IO/MeshExporter.cs | 4 + .../Runtime/UniGLTF/IO/MeshImporter.cs | 6 +- .../Runtime/UniGLTF/IO/NodeImporter.cs | 4 +- .../UniGLTF/IO/RootAnimationImporter.cs | 20 +---- 8 files changed, 74 insertions(+), 55 deletions(-) diff --git a/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs index 9c89a3735..5c3fb0736 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs @@ -240,6 +240,7 @@ namespace UniGLTF // export Export(root, path, new MeshExportSettings { + InvertAxis = settings.InverseAxis, ExportOnlyBlendShapePosition = settings.DropNormal, UseSparseAccessorForMorphTarget = settings.Sparse, }); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs index 0e4c16fe5..a5d9d65a0 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs @@ -185,7 +185,7 @@ namespace UniGLTF return string.Join("/", path); } - public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, AxisInverter inverter, glTFNode root = null) + public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, IAxisInverter inverter, glTFNode root = null) { var clip = new AnimationClip(); clip.ClearCurves(); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs index 9096e708f..abaa02ec5 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs @@ -9,27 +9,70 @@ namespace UniGLTF X, } - public struct AxisInverter + public interface IAxisInverter { - public Func InvertVector3; - public Func InvertVector4; - public Func InvertQuaternion; - public Func InvertMat4; + Vector3 InvertVector3(Vector3 src); + Vector4 InvertVector4(Vector4 src); + Quaternion InvertQuaternion(Quaternion src); + Matrix4x4 InvertMat4(Matrix4x4 src); + } - public static AxisInverter ReverseZ => new AxisInverter + public struct ReverseZ : IAxisInverter + { + public Matrix4x4 InvertMat4(Matrix4x4 src) { - InvertVector3 = x => x.ReverseZ(), - InvertVector4 = x => x.ReverseZ(), - InvertQuaternion = x => x.ReverseZ(), - InvertMat4 = x => x.ReverseZ(), - }; + return src.ReverseZ(); + } - public static AxisInverter ReverseX => new AxisInverter + public Quaternion InvertQuaternion(Quaternion src) { - InvertVector3 = x => x.ReverseX(), - InvertVector4 = x => x.ReverseX(), - InvertQuaternion = x => x.ReverseX(), - InvertMat4 = x => x.ReverseX(), - }; + return src.ReverseZ(); + } + + public Vector3 InvertVector3(Vector3 src) + { + return src.ReverseZ(); + } + + public Vector4 InvertVector4(Vector4 src) + { + return src.ReverseZ(); + } + } + + public class ReverseX : IAxisInverter + { + public Matrix4x4 InvertMat4(Matrix4x4 src) + { + return src.ReverseX(); + } + + public Quaternion InvertQuaternion(Quaternion src) + { + return src.ReverseX(); + } + + public Vector3 InvertVector3(Vector3 src) + { + return src.ReverseX(); + } + + public Vector4 InvertVector4(Vector4 src) + { + return src.ReverseX(); + } + } + + public static class AxisesExtensions + { + public static IAxisInverter Create(this Axises axis) + { + switch (axis) + { + case Axises.Z: return new ReverseZ(); + case Axises.X: return new ReverseX(); + default: throw new NotImplementedException(); + } + } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 5c82ba2fe..a2ea04a55 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -71,20 +71,7 @@ namespace UniGLTF MeasureTime = new ImporterContextSpeedLog().MeasureTime; } - AxisInverter inverter = default; - switch (InvertAxis) - { - case Axises.Z: - inverter = AxisInverter.ReverseZ; - break; - - case Axises.X: - inverter = AxisInverter.ReverseX; - break; - - default: - throw new NotImplementedException(); - } + var inverter = InvertAxis.Create(); if (Root == null) { diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs index d2cdd5270..d10638ed4 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs @@ -8,6 +8,9 @@ namespace UniGLTF [Serializable] public struct MeshExportSettings { + // 反転軸 + public Axises InvertAxis; + // MorphTarget に Sparse Accessor を使う public bool UseSparseAccessorForMorphTarget; @@ -16,6 +19,7 @@ namespace UniGLTF public static MeshExportSettings Default => new MeshExportSettings { + InvertAxis = Axises.Z, UseSparseAccessorForMorphTarget = false, ExportOnlyBlendShapePosition = false, }; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs index aa35e5e27..b651cb98c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs @@ -107,7 +107,7 @@ namespace UniGLTF /// /// /// - public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, AxisInverter inverter) + public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, IAxisInverter inverter) { foreach (var prim in gltfMesh.primitives) { @@ -291,7 +291,7 @@ namespace UniGLTF /// /// /// - public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, AxisInverter inverter) + public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, IAxisInverter inverter) { { // 同じVertexBufferを共有しているので先頭のモノを使う @@ -507,7 +507,7 @@ namespace UniGLTF return sharedAttributes; } - public MeshContext ReadMesh(ImporterContext ctx, int meshIndex, AxisInverter inverter) + public MeshContext ReadMesh(ImporterContext ctx, int meshIndex, IAxisInverter inverter) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs index da02b9272..541b4e034 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs @@ -131,7 +131,7 @@ namespace UniGLTF // // fix node's coordinate. z-back to z-forward // - public static void FixCoordinate(ImporterContext context, List nodes, AxisInverter inverter) + public static void FixCoordinate(ImporterContext context, List nodes, IAxisInverter inverter) { var globalTransformMap = nodes.ToDictionary(x => x.Transform, x => new PosRot { @@ -154,7 +154,7 @@ namespace UniGLTF } } - public static void SetupSkinning(ImporterContext context, List nodes, int i, AxisInverter inverter) + public static void SetupSkinning(ImporterContext context, List nodes, int i, IAxisInverter inverter) { var x = nodes[i]; var skinnedMeshRenderer = x.Transform.GetComponent(); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs index 029efc3c4..d48f7ee81 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs @@ -46,26 +46,10 @@ namespace UniGLTF animation.name = $"animation:{i}"; } - AxisInverter inverter = default; - switch (invertAxis) - { - case Axises.X: - inverter = AxisInverter.ReverseX; - break; - - case Axises.Z: - inverter = AxisInverter.ReverseZ; - break; - - default: - throw new System.Exception(); - - } - - animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation, inverter)); + animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation, invertAxis.Create())); } return animationClips; } } -} \ No newline at end of file +} From d96f47bd2a43189231771c38c851a606917c0776 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 26 Feb 2021 14:35:16 +0900 Subject: [PATCH 3/4] gltfExporter.m_axisInverter --- .../Editor/UniGLTF/GltfExportWindow.cs | 7 ++-- .../Runtime/Extensions/UnityExtensions.cs | 6 ++-- .../Runtime/UniGLTF/IO/MeshExporter.cs | 34 +++++++++---------- .../Runtime/UniGLTF/IO/gltfExporter.cs | 14 +++++--- Assets/VRM/Runtime/IO/VRMExporter.cs | 2 +- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs index 5c3fb0736..6e6d9070a 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/GltfExportWindow.cs @@ -20,7 +20,7 @@ namespace UniGLTF window.Show(); } - private static void Export(GameObject go, string path, MeshExportSettings settings) + private static void Export(GameObject go, string path, MeshExportSettings settings, Axises inverseAxis) { var ext = Path.GetExtension(path).ToLower(); var isGlb = false; @@ -32,7 +32,7 @@ namespace UniGLTF } var gltf = new glTF(); - using (var exporter = new gltfExporter(gltf)) + using (var exporter = new gltfExporter(gltf, inverseAxis)) { exporter.Prepare(go); exporter.Export(settings); @@ -240,10 +240,9 @@ namespace UniGLTF // export Export(root, path, new MeshExportSettings { - InvertAxis = settings.InverseAxis, ExportOnlyBlendShapePosition = settings.DropNormal, UseSparseAccessorForMorphTarget = settings.Sparse, - }); + }, settings.InverseAxis); } } } diff --git a/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs index e56fb7729..4a3890053 100644 --- a/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs @@ -286,14 +286,14 @@ namespace UniGLTF return new float[] { c.r, c.g, c.b, c.a }; } - public static void ReverseZRecursive(this Transform root) + public static void ReverseRecursive(this Transform root, IAxisInverter axisInverter) { var globalMap = root.Traverse().ToDictionary(x => x, x => PosRot.FromGlobalTransform(x)); foreach (var x in root.Traverse()) { - x.position = globalMap[x].Position.ReverseZ(); - x.rotation = globalMap[x].Rotation.ReverseZ(); + x.position = axisInverter.InvertVector3(globalMap[x].Position); + x.rotation = axisInverter.InvertQuaternion(globalMap[x].Rotation); } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs index d10638ed4..70899bc5d 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs @@ -8,9 +8,6 @@ namespace UniGLTF [Serializable] public struct MeshExportSettings { - // 反転軸 - public Axises InvertAxis; - // MorphTarget に Sparse Accessor を使う public bool UseSparseAccessorForMorphTarget; @@ -19,7 +16,6 @@ namespace UniGLTF public static MeshExportSettings Default => new MeshExportSettings { - InvertAxis = Axises.Z, UseSparseAccessorForMorphTarget = false, ExportOnlyBlendShapePosition = false, }; @@ -28,18 +24,19 @@ namespace UniGLTF public static class MeshExporter { static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, - MeshWithRenderer unityMesh, List unityMaterials) + MeshWithRenderer unityMesh, List unityMaterials, + IAxisInverter axisInverter) { var mesh = unityMesh.Mesh; var materials = unityMesh.Renderer.sharedMaterials; - var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray(); + var positions = mesh.vertices.Select(axisInverter.InvertVector3).ToArray(); var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER); gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); - var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.normalized.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); + var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => axisInverter.InvertVector3(y.normalized)).ToArray(), glBufferTarget.ARRAY_BUFFER); #if GLTF_EXPORT_TANGENTS - var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); + var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(axisInverter.InvertVector4()).ToArray(), glBufferTarget.ARRAY_BUFFER); #endif var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); var uvAccessorIndex1 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); @@ -166,7 +163,8 @@ namespace UniGLTF static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, Mesh mesh, int j, bool useSparseAccessorForMorphTarget, - bool exportOnlyBlendShapePosition) + bool exportOnlyBlendShapePosition, + IAxisInverter axisInverter) { var blendShapeVertices = mesh.vertices; var usePosition = blendShapeVertices != null && blendShapeVertices.Length > 0; @@ -222,7 +220,7 @@ namespace UniGLTF { sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(bufferIndex, sparseIndices); - blendShapeVertices = sparseIndices.Select(x => blendShapeVertices[x].ReverseZ()).ToArray(); + blendShapeVertices = sparseIndices.Select(x => axisInverter.InvertVector3(blendShapeVertices[x])).ToArray(); blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeVertices, sparseIndices, sparseIndicesViewIndex, @@ -231,7 +229,7 @@ namespace UniGLTF if (useNormal) { - blendShapeNormals = sparseIndices.Select(x => blendShapeNormals[x].ReverseZ()).ToArray(); + blendShapeNormals = sparseIndices.Select(x => axisInverter.InvertVector3(blendShapeNormals[x])).ToArray(); blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeNormals, sparseIndices, sparseIndicesViewIndex, @@ -240,7 +238,7 @@ namespace UniGLTF if (useTangent) { - blendShapeTangents = sparseIndices.Select(x => blendShapeTangents[x].ReverseZ()).ToArray(); + blendShapeTangents = sparseIndices.Select(x => axisInverter.InvertVector3(blendShapeTangents[x])).ToArray(); blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeTangents, sparseIndices, sparseIndicesViewIndex, glBufferTarget.NONE); @@ -248,7 +246,7 @@ namespace UniGLTF } else { - for (int i = 0; i < blendShapeVertices.Length; ++i) blendShapeVertices[i] = blendShapeVertices[i].ReverseZ(); + for (int i = 0; i < blendShapeVertices.Length; ++i) blendShapeVertices[i] = axisInverter.InvertVector3(blendShapeVertices[i]); if (usePosition) { blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, @@ -258,7 +256,7 @@ namespace UniGLTF if (useNormal) { - for (int i = 0; i < blendShapeNormals.Length; ++i) blendShapeNormals[i] = blendShapeNormals[i].ReverseZ(); + for (int i = 0; i < blendShapeNormals.Length; ++i) blendShapeNormals[i] = axisInverter.InvertVector3(blendShapeNormals[i]); blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeNormals, glBufferTarget.ARRAY_BUFFER); @@ -266,7 +264,7 @@ namespace UniGLTF if (useTangent) { - for (int i = 0; i < blendShapeTangents.Length; ++i) blendShapeTangents[i] = blendShapeTangents[i].ReverseZ(); + for (int i = 0; i < blendShapeTangents.Length; ++i) blendShapeTangents[i] = axisInverter.InvertVector3(blendShapeTangents[i]); blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeTangents, glBufferTarget.ARRAY_BUFFER); @@ -289,12 +287,12 @@ namespace UniGLTF public static IEnumerable<(Mesh, glTFMesh, Dictionary)> ExportMeshes(glTF gltf, int bufferIndex, List unityMeshes, List unityMaterials, - MeshExportSettings settings) + MeshExportSettings settings, IAxisInverter axisInverter) { foreach (var unityMesh in unityMeshes) { var gltfMesh = ExportPrimitives(gltf, bufferIndex, - unityMesh, unityMaterials); + unityMesh, unityMaterials, axisInverter); var targetNames = new List(); @@ -305,7 +303,7 @@ namespace UniGLTF var morphTarget = ExportMorphTarget(gltf, bufferIndex, unityMesh.Mesh, j, settings.UseSparseAccessorForMorphTarget, - settings.ExportOnlyBlendShapePosition); + settings.ExportOnlyBlendShapePosition, axisInverter); if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0) { continue; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index b34cf8d73..a70078a8e 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -88,7 +88,9 @@ namespace UniGLTF } } - public gltfExporter(glTF gltf) + IAxisInverter m_axisInverter; + + public gltfExporter(glTF gltf, Axises invertAxis = Axises.Z) { glTF = gltf; @@ -99,15 +101,17 @@ namespace UniGLTF generator = "UniGLTF-" + UniGLTFVersion.VERSION, version = "2.0", }; + + m_axisInverter = invertAxis.Create(); } GameObject m_tmpParent = null; public virtual void Prepare(GameObject go) { - // コピーを作って、Z軸を反転することで左手系を右手系に変換する + // コピーを作って左手系を右手系に変換する Copy = GameObject.Instantiate(go); - Copy.transform.ReverseZRecursive(); + Copy.transform.ReverseRecursive(m_axisInverter); // Export の root は gltf の scene になるので、 // エクスポート対象が単一の GameObject の場合に、 @@ -216,7 +220,7 @@ namespace UniGLTF MeshBlendShapeIndexMap = new Dictionary>(); foreach (var (mesh, gltfMesh, blendShapeIndexMap) in MeshExporter.ExportMeshes( - glTF, bufferIndex, unityMeshes, Materials, meshExportSettings)) + glTF, bufferIndex, unityMeshes, Materials, meshExportSettings, m_axisInverter)) { glTF.meshes.Add(gltfMesh); if (!MeshBlendShapeIndexMap.ContainsKey(mesh)) @@ -243,7 +247,7 @@ namespace UniGLTF foreach (var x in unitySkins) { - var matrices = x.GetBindPoses().Select(y => y.ReverseZ()).ToArray(); + var matrices = x.GetBindPoses().Select(m_axisInverter.InvertMat4).ToArray(); var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var renderer = x.Renderer as SkinnedMeshRenderer; diff --git a/Assets/VRM/Runtime/IO/VRMExporter.cs b/Assets/VRM/Runtime/IO/VRMExporter.cs index 3181c3ca7..2c45816bf 100644 --- a/Assets/VRM/Runtime/IO/VRMExporter.cs +++ b/Assets/VRM/Runtime/IO/VRMExporter.cs @@ -28,7 +28,7 @@ namespace VRM public readonly VRM.glTF_VRM_extensions VRM = new glTF_VRM_extensions(); - public VRMExporter(glTF gltf) : base(gltf) + public VRMExporter(glTF gltf) : base(gltf, Axises.Z) { gltf.extensionsUsed.Add(glTF_VRM_extensions.ExtensionName); } From 895cf2af140bdd0d71b1141d215e854b106063d6 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 1 Mar 2021 14:37:13 +0900 Subject: [PATCH 4/4] struct --- Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs index abaa02ec5..e6a2cf07f 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs @@ -40,7 +40,7 @@ namespace UniGLTF } } - public class ReverseX : IAxisInverter + public struct ReverseX : IAxisInverter { public Matrix4x4 InvertMat4(Matrix4x4 src) {