diff --git a/Editor/Scripts/Editor/EditorGUILayoutUtils.cs b/Editor/Scripts/Editor/EditorGUILayoutUtils.cs new file mode 100644 index 0000000..faa68c4 --- /dev/null +++ b/Editor/Scripts/Editor/EditorGUILayoutUtils.cs @@ -0,0 +1,20 @@ +using UnityEditor; +using UnityEngine; + +namespace TAO.VertexAnimation.Editor +{ + public static class EditorGUILayoutUtils + { + public static readonly Color horizontalLineColor = Color.white; + + public static void HorizontalLine(Color color) + { + Color prev = GUI.color; + GUI.color = color; + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + GUI.color = prev; + } + + public static void HorizontalLine() => HorizontalLine(horizontalLineColor); + } +} diff --git a/Editor/Scripts/Editor/EditorGUILayoutUtils.cs.meta b/Editor/Scripts/Editor/EditorGUILayoutUtils.cs.meta new file mode 100644 index 0000000..9a46e64 --- /dev/null +++ b/Editor/Scripts/Editor/EditorGUILayoutUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a78d6eea6c7f534b8361125e43eacc9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Editor/ModelBaker/Editor/VA_ModelBakerEditor.cs b/Editor/Scripts/Editor/ModelBaker/Editor/VA_ModelBakerEditor.cs deleted file mode 100644 index c3ddfa3..0000000 --- a/Editor/Scripts/Editor/ModelBaker/Editor/VA_ModelBakerEditor.cs +++ /dev/null @@ -1,109 +0,0 @@ -using UnityEngine; -using UnityEditor; - -namespace TAO.VertexAnimation.Editor -{ - [CustomEditor(typeof(VA_ModelBaker))] - public class VA_ModelBakerEditor : UnityEditor.Editor - { - private VA_ModelBaker modelBaker = null; - - void OnEnable() - { - modelBaker = target as VA_ModelBaker; - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - - InputGUI(); - BakeGUI(); - OutputGUI(); - - serializedObject.ApplyModifiedProperties(); - } - - private void InputGUI() - { - //public GameObject model; - //public AnimationClip[] animationClips; - //public int fps = 24; - //public int textureWidth = 512; - //public bool saveBakedDataToAsset = true; - //public bool generateAnimationBook = false; - - EditorGUILayout.PropertyField(serializedObject.FindProperty("model")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("animationClips")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("fps")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("textureWidth")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("saveBakedDataToAsset")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("generateAnimationBook")); - } - - private void BakeGUI() - { - if (GUILayout.Button("Bake")) - { - ClearBakedData(); - - modelBaker.Bake(); - - if (modelBaker.saveBakedDataToAsset) - { - SaveBakedData(); - } - } - - using (new EditorGUILayout.HorizontalScope()) - { - if (GUILayout.Button("SaveBakedData", EditorStyles.miniButtonLeft)) - { - SaveBakedData(); - } - - if (GUILayout.Button("ClearBakedData", EditorStyles.miniButtonRight)) - { - ClearBakedData(); - } - } - } - - private void OutputGUI() - { - using (new EditorGUI.DisabledGroupScope(true)) - { - EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData")); - } - } - - private void SaveBakedData() - { - AssetDatabase.AddObjectToAsset(modelBaker.BakedData.mesh, modelBaker); - - foreach (var pm in modelBaker.BakedData.positionMaps) - { - AssetDatabase.AddObjectToAsset(pm, modelBaker); - } - - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - - private void ClearBakedData() - { - var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(modelBaker)); - - foreach (var a in assets) - { - if (a != modelBaker) - { - AssetDatabase.RemoveObjectFromAsset(a); - } - } - - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - } -} diff --git a/Editor/Scripts/Editor/VA_AnimationBookEditor.cs b/Editor/Scripts/Editor/VA_AnimationBookEditor.cs index c09825e..1000889 100644 --- a/Editor/Scripts/Editor/VA_AnimationBookEditor.cs +++ b/Editor/Scripts/Editor/VA_AnimationBookEditor.cs @@ -10,10 +10,6 @@ namespace TAO.VertexAnimation.Editor private Vector2 textureGroupScollPos; private Vector2 animationPagesScollPos; - //private UnityEditor.Editor previewEditor = null; - //private int previewIndex = 0; - //private int curviewIndex = 0; - void OnEnable() { animationBook = target as VA_AnimationBook; @@ -25,11 +21,16 @@ namespace TAO.VertexAnimation.Editor // Texture Groups. GeneralGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); TextureGroupsGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); SyncListSize(); AnimationPagesGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); MaterialGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); AssetBuilderGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); Texture2DGUI(); serializedObject.ApplyModifiedProperties(); diff --git a/Editor/Scripts/Editor/ModelBaker.meta b/Editor/Scripts/ModelBaker.meta similarity index 100% rename from Editor/Scripts/Editor/ModelBaker.meta rename to Editor/Scripts/ModelBaker.meta diff --git a/Editor/Scripts/Editor/ModelBaker/Editor.meta b/Editor/Scripts/ModelBaker/Editor.meta similarity index 100% rename from Editor/Scripts/Editor/ModelBaker/Editor.meta rename to Editor/Scripts/ModelBaker/Editor.meta diff --git a/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs new file mode 100644 index 0000000..e1d5266 --- /dev/null +++ b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs @@ -0,0 +1,216 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; + +namespace TAO.VertexAnimation.Editor +{ + [CustomEditor(typeof(VA_ModelBaker))] + public class VA_ModelBakerEditor : UnityEditor.Editor + { + private VA_ModelBaker modelBaker = null; + + void OnEnable() + { + modelBaker = target as VA_ModelBaker; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + InputGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); + BakeGUI(); + + serializedObject.ApplyModifiedProperties(); + + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); + OutputGUI(); + } + + private void InputGUI() + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("model")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("animationClips")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("fps")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("textureWidth")); + } + + private void BakeGUI() + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("saveBakedDataToAsset")); + + int il = EditorGUI.indentLevel; + if (modelBaker.saveBakedDataToAsset) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(serializedObject.FindProperty("generateAnimationBook")); + + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("generatePrefab")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("materialShader"), new GUIContent("")); + } + } + EditorGUI.indentLevel = il; + + if (GUILayout.Button("Bake", GUILayout.Height(32))) + { + ClearBakedData(); + + modelBaker.Bake(); + + if (modelBaker.saveBakedDataToAsset) + { + SaveBakedData(); + } + } + + if (modelBaker.BakedData.mesh != null) + { + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("Save", EditorStyles.miniButtonLeft)) + { + SaveBakedData(); + } + + if (GUILayout.Button("Clear", EditorStyles.miniButtonRight)) + { + ClearBakedData(); + } + } + + if (modelBaker.prefab && GUILayout.Button("Remove Prefab")) + { + DeletePrefab(); + } + } + } + + private void OutputGUI() + { + using (new EditorGUI.DisabledGroupScope(true)) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData")); + } + } + + private void SaveBakedData() + { + ClearBakedData(); + + AssetDatabase.AddObjectToAsset(modelBaker.BakedData.mesh, modelBaker); + + foreach (var pm in modelBaker.BakedData.positionMaps) + { + AssetDatabase.AddObjectToAsset(pm, modelBaker); + } + + AssetDatabase.SaveAssets(); + + if (modelBaker.generatePrefab) + { + GeneratePrefab(); + } + + if(modelBaker.generateAnimationBook) + { + GenerateBook(); + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + + private void ClearBakedData() + { + var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(modelBaker)); + + foreach (var a in assets) + { + if (a != modelBaker) + { + AssetDatabase.RemoveObjectFromAsset(a); + } + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + + private void DeletePrefab() + { + string path = AssetDatabase.GetAssetPath(modelBaker.prefab); + AssetDatabase.DeleteAsset(path); + AssetDatabase.Refresh(); + } + + private void GeneratePrefab() + { + string path = AssetDatabase.GetAssetPath(modelBaker); + int start = path.LastIndexOf('/'); + path = path.Remove(start, path.Length - start); + path += "/" + modelBaker.name + ".prefab"; + + // Generate Material + modelBaker.material = new Material(modelBaker.materialShader); + modelBaker.material.name = modelBaker.name; + AssetDatabase.AddObjectToAsset(modelBaker.material, modelBaker); + + // Generate Object. + if (!modelBaker.prefab) + { + GameObject go = new GameObject(modelBaker.model.name, typeof(MeshFilter), typeof(MeshRenderer)); + modelBaker.prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(go, path, InteractionMode.AutomatedAction); + DestroyImmediate(go); + } + + GameObject inst = PrefabUtility.InstantiatePrefab(modelBaker.prefab) as GameObject; + + inst.GetComponent().sharedMesh = modelBaker.BakedData.mesh; + inst.GetComponent().sharedMaterial = modelBaker.material; + + // Save. + PrefabUtility.ApplyPrefabInstance(inst, InteractionMode.UserAction); + AssetDatabase.SaveAssets(); + + DestroyImmediate(inst); + } + + private void GenerateBook() + { + if (!modelBaker.book) + { + modelBaker.book = CreateInstance(); + } + + modelBaker.book.name = modelBaker.model.name; + modelBaker.book.editorData = new VA_AnimationBook.EditorData(); + + modelBaker.book.editorData.materials = new Material[1] { modelBaker.material }; + + foreach (Texture2D tex in modelBaker.BakedData.positionMaps) + { + modelBaker.book.editorData.animationPages.Add(new VA_AnimationBook.EditorAnimationPage + { + name = "", + frames = 0, + textures = new List() + { + new VA_AnimationBook.EditorTextureEntry + { + texture2D = tex + } + } + }); + } + + VA_AssetBuilder.AutoFill(ref modelBaker.book); + + AssetDatabase.AddObjectToAsset(modelBaker.book, modelBaker); + AssetDatabase.SaveAssets(); + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Editor/ModelBaker/Editor/VA_ModelBakerEditor.cs.meta b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs.meta similarity index 100% rename from Editor/Scripts/Editor/ModelBaker/Editor/VA_ModelBakerEditor.cs.meta rename to Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs.meta diff --git a/Editor/Scripts/VA_AssetBuilder.cs b/Editor/Scripts/VA_AssetBuilder.cs index d2378f6..f9c1f4b 100644 --- a/Editor/Scripts/VA_AssetBuilder.cs +++ b/Editor/Scripts/VA_AssetBuilder.cs @@ -293,6 +293,13 @@ namespace TAO.VertexAnimation.Editor ap.frames = frames; } } + else if (p.StartsWith("MF-")) + { + if (int.TryParse(p.Remove(0, 3), out int maxFrames)) + { + book.editorData.maxFrames = maxFrames; + } + } } } book.editorData.animationPages[i] = ap; diff --git a/Runtime/Scripts/ModelBaker/MeshCombiner.cs b/Runtime/Scripts/ModelBaker/MeshCombiner.cs index 1f0192e..9369336 100644 --- a/Runtime/Scripts/ModelBaker/MeshCombiner.cs +++ b/Runtime/Scripts/ModelBaker/MeshCombiner.cs @@ -1,16 +1,4 @@ -// References: -// https://forum.unity.com/threads/help-combining-and-manipulating-skinned-mesh-renderers-imported-from-blender.505078/ -// http://wiki.unity3d.com/index.php/CombineSkinnedMeshes -// http://wiki.unity3d.com/index.php/SkinnedMeshCombiner - -// TODO: -// ---Bake ALL the MeshRenderers/SkinnedMeshRenderers and merge them together.--- -// ---Bake multiple animations.--- -// ---Get the longest animation to calculate the texture height, so all the textures have the same height for the 3D texture.--- -// Add options and previews for texture size, animation phasing/fps. -// Either merge with the animation books or generate them from this and maybe store them as child (and then don't destroy them on re-bake to keep the reference but replace it). - -using UnityEngine; +using UnityEngine; using System.Collections.Generic; using System.Linq; diff --git a/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs b/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs index bfddaf4..ee47b33 100644 --- a/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs +++ b/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs @@ -1,5 +1,3 @@ -using System.Collections; -using System.Collections.Generic; using UnityEngine; namespace TAO.VertexAnimation @@ -9,10 +7,20 @@ namespace TAO.VertexAnimation { public GameObject model; public AnimationClip[] animationClips; + [Range(1, 60)] public int fps = 24; public int textureWidth = 512; + +#if UNITY_EDITOR public bool saveBakedDataToAsset = true; - public bool generateAnimationBook = false; + public bool generateAnimationBook = true; + public bool generatePrefab = true; + public Shader materialShader = null; + + public GameObject prefab = null; + public Material material = null; + public VA_AnimationBook book = null; +#endif [SerializeField] private AnimationBaker.BakedData bakedData;