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.
This commit is contained in:
max 2021-01-19 13:59:31 +01:00
parent 2d6e920017
commit c465ec6585
7 changed files with 169 additions and 87 deletions

View File

@ -20,6 +20,17 @@ namespace TAO.VertexAnimation.Editor
return false; 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) public static void RemoveChildAssets(Object parent, Object[] filter = null)
{ {
var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(parent)); var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(parent));

View File

@ -1,7 +1,5 @@
using UnityEngine; using UnityEngine;
using UnityEditor; using UnityEditor;
using System.Collections.Generic;
using System.Linq;
namespace TAO.VertexAnimation.Editor namespace TAO.VertexAnimation.Editor
{ {
@ -24,9 +22,6 @@ namespace TAO.VertexAnimation.Editor
BakeGUI(); BakeGUI();
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
OutputGUI();
} }
private void InputGUI() private void InputGUI()
@ -51,23 +46,25 @@ namespace TAO.VertexAnimation.Editor
if (GUILayout.Button("Bake", GUILayout.Height(32))) if (GUILayout.Button("Bake", GUILayout.Height(32)))
{ {
modelBaker.Bake(); 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() if (GUILayout.Button("Delete", EditorStyles.miniButtonRight))
{ {
using (new EditorGUI.DisabledGroupScope(true)) if (EditorUtility.DisplayDialog("Delete Assets", "Deleting assets will loose references within the project.", "Ok", "Cancel"))
{ {
EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData")); modelBaker.DeleteSavedAssets();
}
}
} }
} }
} }

View File

@ -29,10 +29,6 @@ namespace TAO.VertexAnimation.Editor
public VA_AnimationBook book = null; public VA_AnimationBook book = null;
public List<VA_Animation> animations = new List<VA_Animation>(); public List<VA_Animation> animations = new List<VA_Animation>();
// TODO: release baked data from memory when done.
[SerializeField]
private AnimationBaker.BakedData bakedData;
[System.Serializable] [System.Serializable]
public class LODSettings public class LODSettings
{ {
@ -89,15 +85,17 @@ namespace TAO.VertexAnimation.Editor
target.name = model.name; target.name = model.name;
target.ConbineAndConvertGameObject(); 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); 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()); meshes = bakedData.mesh.GenerateLOD(lodSettings.LODCount(), lodSettings.GetQualitySettings());
DestroyImmediate(target); DestroyImmediate(target);
SaveAssets(bakedData);
} }
public void SaveAssets() private void SaveAssets(AnimationBaker.BakedData bakedData)
{ {
AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material }); AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material });
@ -112,45 +110,19 @@ namespace TAO.VertexAnimation.Editor
if (generatePrefab) if (generatePrefab)
{ {
GeneratePrefab(); GeneratePrefab(bakedData);
} }
if (generateAnimationBook) if (generateAnimationBook)
{ {
GenerateBook(); GenerateBook(bakedData);
} }
AssetDatabase.SaveAssets(); AssetDatabase.SaveAssets();
AssetDatabase.Refresh(); AssetDatabase.Refresh();
} }
public void DeleteSavedAssets() private void GeneratePrefab(AnimationBaker.BakedData bakedData)
{
// 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()
{ {
string path = AssetDatabase.GetAssetPath(this); string path = AssetDatabase.GetAssetPath(this);
int start = path.LastIndexOf('/'); int start = path.LastIndexOf('/');
@ -175,8 +147,9 @@ namespace TAO.VertexAnimation.Editor
prefab = AnimationPrefab.Create(path, name, meshes, material, lodSettings.GetTransitionSettings()); prefab = AnimationPrefab.Create(path, name, meshes, material, lodSettings.GetTransitionSettings());
} }
private void GenerateBook() private void GenerateBook(AnimationBaker.BakedData bakedData)
{ {
// Create book.
if (!book) if (!book)
{ {
book = CreateInstance<VA_AnimationBook>(); book = CreateInstance<VA_AnimationBook>();
@ -184,26 +157,29 @@ namespace TAO.VertexAnimation.Editor
book.name = string.Format("{0}_Book", name); book.name = string.Format("{0}_Book", name);
book.positionMap = positionMap; book.positionMap = positionMap;
book.animations = new List<VA_Animation>();
book.TryAddMaterial(material); book.TryAddMaterial(material);
// Save book.
if (!AssetDatabaseUtils.HasChildAsset(this, book)) if (!AssetDatabaseUtils.HasChildAsset(this, book))
{ {
AssetDatabase.AddObjectToAsset(book, this); AssetDatabase.AddObjectToAsset(book, this);
} }
// Add animations. // Get animation info.
List<NamingConventionUtils.TextureInfo> info = new List<NamingConventionUtils.TextureInfo>(); List<NamingConventionUtils.PositionMapInfo> info = new List<NamingConventionUtils.PositionMapInfo>();
foreach (var t in bakedData.positionMaps) foreach (var t in bakedData.positionMaps)
{ {
info.Add(t.name.GetTextureInfo()); info.Add(t.name.GetTextureInfo());
} }
// Create animations.
for (int i = 0; i < info.Count; i++) for (int i = 0; i < info.Count; i++)
{ {
string animationName = string.Format("{0}_{1}", name, info[i].name); 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); 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)) if (TryGetAnimationWithName(animationName, out VA_Animation animation))
{ {
animation.SetData(newData); animation.SetData(newData);
@ -217,30 +193,82 @@ namespace TAO.VertexAnimation.Editor
} }
book.TryAddAnimation(animation); 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) private bool TryGetAnimationWithName(string name, out VA_Animation animation)
{ {
foreach (var a in animations) foreach (var a in animations)
{ {
if (a.name == name) if (a != null)
{ {
animation = a; if (a.name == name)
return true; {
animation = a;
return true;
}
} }
} }
animation = null; animation = null;
return false; 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<VA_Animation>();
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 #endif
} }
} }

View File

@ -6,7 +6,7 @@ namespace TAO.VertexAnimation
{ {
public static class NamingConventionUtils public static class NamingConventionUtils
{ {
public struct TextureInfo public struct PositionMapInfo
{ {
public string name; public string name;
public int frames; public int frames;
@ -14,9 +14,9 @@ namespace TAO.VertexAnimation
public int fps; 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('_'); string[] parts = name.Split('_');
foreach (var p in parts) foreach (var p in parts)

View File

@ -1,3 +1,4 @@
using Unity.Collections;
using UnityEngine; using UnityEngine;
namespace TAO.VertexAnimation namespace TAO.VertexAnimation
@ -26,5 +27,10 @@ namespace TAO.VertexAnimation
a_data.name = this.name; a_data.name = this.name;
Data = a_data; Data = a_data;
} }
public FixedString32 GetName()
{
return Data.name;
}
} }
} }

View File

@ -21,10 +21,7 @@ namespace TAO.VertexAnimation
} }
} }
public int MaxFrames public int MaxFrames { get; private set; } = 0;
{
get; private set;
}
public Texture2DArray positionMap = null; public Texture2DArray positionMap = null;
public List<VA_Animation> animations = new List<VA_Animation>(); public List<VA_Animation> animations = new List<VA_Animation>();
@ -34,9 +31,10 @@ namespace TAO.VertexAnimation
{ {
if (animations != null && animations.Count != 0) if (animations != null && animations.Count != 0)
{ {
if (!animations.Contains(animation) && animation.Data.maxFrames == MaxFrames) if (!animations.Contains(animation))
{ {
animations.Add(animation); animations.Add(animation);
OnValidate();
return true; return true;
} }
} }
@ -45,7 +43,7 @@ namespace TAO.VertexAnimation
// Add first animation. // Add first animation.
animations.Add(animation); animations.Add(animation);
// Set maxFrames for this animation book. // Set maxFrames for this animation book.
MaxFrames = animations[0].Data.maxFrames; OnValidate();
return true; return true;
} }
@ -67,16 +65,10 @@ namespace TAO.VertexAnimation
return false; return false;
} }
public void RemoveAnimation(VA_Animation animation) public void UpdateMaterials()
{ {
if (animations != null) OnValidate();
{
animations.Remove(animation);
}
}
public void SetMaterials()
{
if (materials != null) if (materials != null)
{ {
foreach (var mat in materials) 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() private void OnValidate()
{ {
UpdateMaxFrames();
if (animations != null) if (animations != null)
{ {
foreach (var a in animations) foreach (var a in animations)
@ -115,7 +120,7 @@ namespace TAO.VertexAnimation
if (positionMap != null) 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)); Debug.LogWarning(string.Format("More animations ({0}) than positionMaps in {1}!", animations.Count, this.name));
} }

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Unity.Collections;
using UnityEngine; using UnityEngine;
namespace TAO.VertexAnimation namespace TAO.VertexAnimation
@ -12,24 +13,58 @@ namespace TAO.VertexAnimation
[HideInInspector] [HideInInspector]
public List<VA_AnimationData> animationData = null; public List<VA_AnimationData> animationData = null;
#if UNITY_EDITOR
[SerializeField]
private List<VA_Animation> loadedAnimationsPreview = null;
#endif
public void Init() public void Init()
{ {
animationData = new List<VA_AnimationData>(); animationData = new List<VA_AnimationData>();
foreach (VA_AnimationBook book in animationBooks) 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() private void OnValidate()
{ {
// TODO: Check for naming conflicts in AnimationBooks. Dictionary<string, VA_Animation> usedNames = new Dictionary<string, VA_Animation>();
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<VA_Animation>();
foreach (var un in usedNames)
{
loadedAnimationsPreview.Add(un.Value);
}
#endif
} }
} }
} }