From c465ec6585eaf51ae6fe25dd6800eecadee37f40 Mon Sep 17 00:00:00 2001 From: max Date: Tue, 19 Jan 2021 13:59:31 +0100 Subject: [PATCH] Simplify editor Animations can now be used by scriptable object reference. Bake saves book and animations. Checks to update instead of create+overwrite assets to keep references/configuration. --- Editor/Scripts/AssetDatabaseUtils.cs | 11 ++ .../ModelBaker/Editor/VA_ModelBakerEditor.cs | 29 ++-- Editor/Scripts/ModelBaker/VA_ModelBaker.cs | 126 +++++++++++------- .../ModelBaker/NamingConventionUtils.cs | 6 +- Runtime/Scripts/VA_Animation.cs | 6 + Runtime/Scripts/VA_AnimationBook.cs | 35 ++--- Runtime/Scripts/VA_AnimationLibrary.cs | 43 +++++- 7 files changed, 169 insertions(+), 87 deletions(-) diff --git a/Editor/Scripts/AssetDatabaseUtils.cs b/Editor/Scripts/AssetDatabaseUtils.cs index 39a9336..b49629e 100644 --- a/Editor/Scripts/AssetDatabaseUtils.cs +++ b/Editor/Scripts/AssetDatabaseUtils.cs @@ -20,6 +20,17 @@ namespace TAO.VertexAnimation.Editor return false; } + public static bool TryAddChildAsset(Object parent, Object child) + { + if (!HasChildAsset(parent, child)) + { + AssetDatabase.AddObjectToAsset(child, parent); + return true; + } + + return false; + } + public static void RemoveChildAssets(Object parent, Object[] filter = null) { var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(parent)); diff --git a/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs index e92faf7..7175127 100644 --- a/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs +++ b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs @@ -1,7 +1,5 @@ using UnityEngine; using UnityEditor; -using System.Collections.Generic; -using System.Linq; namespace TAO.VertexAnimation.Editor { @@ -24,9 +22,6 @@ namespace TAO.VertexAnimation.Editor BakeGUI(); serializedObject.ApplyModifiedProperties(); - - EditorGUILayoutUtils.HorizontalLine(color: Color.gray); - OutputGUI(); } private void InputGUI() @@ -51,23 +46,25 @@ namespace TAO.VertexAnimation.Editor if (GUILayout.Button("Bake", GUILayout.Height(32))) { modelBaker.Bake(); - modelBaker.SaveAssets(); } - if (GUILayout.Button("Delete", EditorStyles.miniButtonRight)) + using (new EditorGUILayout.HorizontalScope()) { - if (EditorUtility.DisplayDialog("Delete Assets", "Deleting assets will loose references within the project.", "Ok", "Cancel")) + if (GUILayout.Button("Delete Unused Animations", EditorStyles.miniButtonLeft)) { - modelBaker.DeleteSavedAssets(); + if (EditorUtility.DisplayDialog("Delete Unused Animations", "Deleting assets will loose references within the project.", "Ok", "Cancel")) + { + modelBaker.DeleteUnusedAnimations(); + } } - } - } - private void OutputGUI() - { - using (new EditorGUI.DisabledGroupScope(true)) - { - EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData")); + if (GUILayout.Button("Delete", EditorStyles.miniButtonRight)) + { + if (EditorUtility.DisplayDialog("Delete Assets", "Deleting assets will loose references within the project.", "Ok", "Cancel")) + { + modelBaker.DeleteSavedAssets(); + } + } } } } diff --git a/Editor/Scripts/ModelBaker/VA_ModelBaker.cs b/Editor/Scripts/ModelBaker/VA_ModelBaker.cs index c86a442..2cf5360 100644 --- a/Editor/Scripts/ModelBaker/VA_ModelBaker.cs +++ b/Editor/Scripts/ModelBaker/VA_ModelBaker.cs @@ -29,10 +29,6 @@ namespace TAO.VertexAnimation.Editor public VA_AnimationBook book = null; public List animations = new List(); - // TODO: release baked data from memory when done. - [SerializeField] - private AnimationBaker.BakedData bakedData; - [System.Serializable] public class LODSettings { @@ -89,15 +85,17 @@ namespace TAO.VertexAnimation.Editor target.name = model.name; target.ConbineAndConvertGameObject(); - bakedData = target.Bake(animationClips, fps, textureWidth); + AnimationBaker.BakedData bakedData = target.Bake(animationClips, fps, textureWidth); positionMap = VA_Texture2DArrayUtils.CreateTextureArray(bakedData.positionMaps.ToArray(), false, true, TextureWrapMode.Repeat, FilterMode.Point, 1, string.Format("{0}_PositionMap", name), true); meshes = bakedData.mesh.GenerateLOD(lodSettings.LODCount(), lodSettings.GetQualitySettings()); DestroyImmediate(target); + + SaveAssets(bakedData); } - public void SaveAssets() + private void SaveAssets(AnimationBaker.BakedData bakedData) { AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material }); @@ -112,45 +110,19 @@ namespace TAO.VertexAnimation.Editor if (generatePrefab) { - GeneratePrefab(); + GeneratePrefab(bakedData); } if (generateAnimationBook) { - GenerateBook(); + GenerateBook(bakedData); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } - public void DeleteSavedAssets() - { - // Remove assets. - var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(this)); - foreach (var a in assets) - { - if (a != this) - { - AssetDatabase.RemoveObjectFromAsset(a); - } - } - - // Delete prefab. - string path = AssetDatabase.GetAssetPath(prefab); - AssetDatabase.DeleteAsset(path); - - // Clear variables. - prefab = null; - material = null; - meshes = null; - book = null; - - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - - private void GeneratePrefab() + private void GeneratePrefab(AnimationBaker.BakedData bakedData) { string path = AssetDatabase.GetAssetPath(this); int start = path.LastIndexOf('/'); @@ -175,8 +147,9 @@ namespace TAO.VertexAnimation.Editor prefab = AnimationPrefab.Create(path, name, meshes, material, lodSettings.GetTransitionSettings()); } - private void GenerateBook() + private void GenerateBook(AnimationBaker.BakedData bakedData) { + // Create book. if (!book) { book = CreateInstance(); @@ -184,26 +157,29 @@ namespace TAO.VertexAnimation.Editor book.name = string.Format("{0}_Book", name); book.positionMap = positionMap; + book.animations = new List(); book.TryAddMaterial(material); + // Save book. if (!AssetDatabaseUtils.HasChildAsset(this, book)) { AssetDatabase.AddObjectToAsset(book, this); } - // Add animations. - List info = new List(); - + // Get animation info. + List info = new List(); foreach (var t in bakedData.positionMaps) { info.Add(t.name.GetTextureInfo()); } + // Create animations. for (int i = 0; i < info.Count; i++) { string animationName = string.Format("{0}_{1}", name, info[i].name); VA_AnimationData newData = new VA_AnimationData(animationName, info[i].frames, info[i].maxFrames, info[i].fps, i, -1); - + + // Either update existing animation or create a new one. if (TryGetAnimationWithName(animationName, out VA_Animation animation)) { animation.SetData(newData); @@ -217,30 +193,82 @@ namespace TAO.VertexAnimation.Editor } book.TryAddAnimation(animation); - - if (!AssetDatabaseUtils.HasChildAsset(book, animation)) - { - AssetDatabase.AddObjectToAsset(animation, book); - } } - // TODO: Remove unused animations. + // Save animation objects. + foreach (var a in animations) + { + AssetDatabaseUtils.TryAddChildAsset(book, a); + } } private bool TryGetAnimationWithName(string name, out VA_Animation animation) { foreach (var a in animations) { - if (a.name == name) + if (a != null) { - animation = a; - return true; + if (a.name == name) + { + animation = a; + return true; + } } } animation = null; return false; } + + public void DeleteSavedAssets() + { + // Remove assets. + var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(this)); + foreach (var a in assets) + { + if (a != this) + { + AssetDatabase.RemoveObjectFromAsset(a); + } + } + + // Delete prefab. + string path = AssetDatabase.GetAssetPath(prefab); + AssetDatabase.DeleteAsset(path); + + // Clear variables. + prefab = null; + positionMap = null; + material = null; + meshes = null; + book = null; + animations = new List(); + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + + public void DeleteUnusedAnimations() + { + if (book != null) + { + // Remove unused animations. + for (int i = 0; i < animations.Count; i++) + { + if (!book.animations.Contains(animations[i])) + { + AssetDatabase.RemoveObjectFromAsset(animations[i]); + animations[i] = null; + } + } + + // Remove zero entries. + animations.RemoveAll(a => a == null); + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + } #endif } } diff --git a/Runtime/Scripts/ModelBaker/NamingConventionUtils.cs b/Runtime/Scripts/ModelBaker/NamingConventionUtils.cs index 2a62296..8e6cc12 100644 --- a/Runtime/Scripts/ModelBaker/NamingConventionUtils.cs +++ b/Runtime/Scripts/ModelBaker/NamingConventionUtils.cs @@ -6,7 +6,7 @@ namespace TAO.VertexAnimation { public static class NamingConventionUtils { - public struct TextureInfo + public struct PositionMapInfo { public string name; public int frames; @@ -14,9 +14,9 @@ namespace TAO.VertexAnimation public int fps; } - public static TextureInfo GetTextureInfo(this string name) + public static PositionMapInfo GetTextureInfo(this string name) { - TextureInfo textureInfo = new TextureInfo(); + PositionMapInfo textureInfo = new PositionMapInfo(); string[] parts = name.Split('_'); foreach (var p in parts) diff --git a/Runtime/Scripts/VA_Animation.cs b/Runtime/Scripts/VA_Animation.cs index 8c0b7de..c5e3a99 100644 --- a/Runtime/Scripts/VA_Animation.cs +++ b/Runtime/Scripts/VA_Animation.cs @@ -1,3 +1,4 @@ +using Unity.Collections; using UnityEngine; namespace TAO.VertexAnimation @@ -26,5 +27,10 @@ namespace TAO.VertexAnimation a_data.name = this.name; Data = a_data; } + + public FixedString32 GetName() + { + return Data.name; + } } } \ No newline at end of file diff --git a/Runtime/Scripts/VA_AnimationBook.cs b/Runtime/Scripts/VA_AnimationBook.cs index 0cafdb4..e5acaaa 100644 --- a/Runtime/Scripts/VA_AnimationBook.cs +++ b/Runtime/Scripts/VA_AnimationBook.cs @@ -21,10 +21,7 @@ namespace TAO.VertexAnimation } } - public int MaxFrames - { - get; private set; - } + public int MaxFrames { get; private set; } = 0; public Texture2DArray positionMap = null; public List animations = new List(); @@ -34,9 +31,10 @@ namespace TAO.VertexAnimation { if (animations != null && animations.Count != 0) { - if (!animations.Contains(animation) && animation.Data.maxFrames == MaxFrames) + if (!animations.Contains(animation)) { animations.Add(animation); + OnValidate(); return true; } } @@ -45,7 +43,7 @@ namespace TAO.VertexAnimation // Add first animation. animations.Add(animation); // Set maxFrames for this animation book. - MaxFrames = animations[0].Data.maxFrames; + OnValidate(); return true; } @@ -67,16 +65,10 @@ namespace TAO.VertexAnimation return false; } - public void RemoveAnimation(VA_Animation animation) + public void UpdateMaterials() { - if (animations != null) - { - animations.Remove(animation); - } - } + OnValidate(); - public void SetMaterials() - { if (materials != null) { foreach (var mat in materials) @@ -97,8 +89,21 @@ namespace TAO.VertexAnimation } } + private void UpdateMaxFrames() + { + if (animations != null && animations.Count != 0) + { + if (animations[0] != null) + { + MaxFrames = animations[0].Data.maxFrames; + } + } + } + private void OnValidate() { + UpdateMaxFrames(); + if (animations != null) { foreach (var a in animations) @@ -115,7 +120,7 @@ namespace TAO.VertexAnimation if (positionMap != null) { - if (positionMap.depth > animations.Count) + if (positionMap.depth < animations.Count) { Debug.LogWarning(string.Format("More animations ({0}) than positionMaps in {1}!", animations.Count, this.name)); } diff --git a/Runtime/Scripts/VA_AnimationLibrary.cs b/Runtime/Scripts/VA_AnimationLibrary.cs index 495e776..2729230 100644 --- a/Runtime/Scripts/VA_AnimationLibrary.cs +++ b/Runtime/Scripts/VA_AnimationLibrary.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Unity.Collections; using UnityEngine; namespace TAO.VertexAnimation @@ -12,24 +13,58 @@ namespace TAO.VertexAnimation [HideInInspector] public List animationData = null; +#if UNITY_EDITOR + [SerializeField] + private List loadedAnimationsPreview = null; +#endif + public void Init() { animationData = new List(); foreach (VA_AnimationBook book in animationBooks) { - book.SetMaterials(); + book.UpdateMaterials(); - foreach (VA_Animation animation in book.animations) + if (book != null) { - animationData.Add(animation.Data); + foreach (VA_Animation animation in book.animations) + { + animationData.Add(animation.Data); + } } } } private void OnValidate() { - // TODO: Check for naming conflicts in AnimationBooks. + Dictionary usedNames = new Dictionary(); + + foreach (VA_AnimationBook book in animationBooks) + { + if (book != null) + { + foreach (VA_Animation animation in book.animations) + { + if (!usedNames.ContainsKey(animation.name)) + { + usedNames.Add(animation.name, animation); + } + else + { + Debug.LogWarning(string.Format("Naming conflict found in {0} - Animation {1} and {2} have the same name!", name, usedNames[animation.name].name, animation.name)); + } + } + } + } + +#if UNITY_EDITOR + loadedAnimationsPreview = new List(); + foreach (var un in usedNames) + { + loadedAnimationsPreview.Add(un.Value); + } +#endif } } } \ No newline at end of file