From d3b4d3440911ec73f62275b565373dac788fe88c Mon Sep 17 00:00:00 2001 From: max Date: Thu, 14 Jan 2021 00:45:25 +0100 Subject: [PATCH] Model Baker Updates ... Added fps to book data. Cleanup. Preparing LOD generation. --- Editor/Scripts/Editor/AssetDatabaseUtils.cs | 47 ++ .../Scripts/Editor/AssetDatabaseUtils.cs.meta | 11 + .../Scripts/Editor/VA_AnimationBookEditor.cs | 1 + Editor/Scripts/ModelBaker/AnimationPrefab.cs | 52 +++ .../ModelBaker/AnimationPrefab.cs.meta | 11 + .../ModelBaker/Editor/VA_ModelBakerEditor.cs | 263 +++-------- Editor/Scripts/ModelBaker/VA_ModelBaker.cs | 169 ++++++++ .../Scripts/ModelBaker/VA_ModelBaker.cs.meta | 0 Editor/Scripts/VA_AssetBuilder.cs | 8 + Editor/TAO.VertexAnimation.Editor.asmdef | 4 +- Runtime/Scripts/ModelBaker/AnimationBaker.cs | 297 ++++++------- .../Scripts/ModelBaker/AnimationMaterial.cs | 18 + .../ModelBaker/AnimationMaterial.cs.meta | 11 + Runtime/Scripts/ModelBaker/MeshCombiner.cs | 407 +++++++++--------- Runtime/Scripts/ModelBaker/VA_ModelBaker.cs | 45 -- Runtime/Scripts/VA_AnimationBook.cs | 295 ++++++------- .../VA_AnimationLibraryComponentAuthoring.cs | 2 +- Runtime/Scripts/VA_AnimationLibraryData.cs | 36 +- .../Scripts/VA_AnimatorComponentAuthoring.cs | 6 +- Runtime/Scripts/VA_Texture2DArrayUtils.cs | 164 +++---- 20 files changed, 1009 insertions(+), 838 deletions(-) create mode 100644 Editor/Scripts/Editor/AssetDatabaseUtils.cs create mode 100644 Editor/Scripts/Editor/AssetDatabaseUtils.cs.meta create mode 100644 Editor/Scripts/ModelBaker/AnimationPrefab.cs create mode 100644 Editor/Scripts/ModelBaker/AnimationPrefab.cs.meta create mode 100644 Editor/Scripts/ModelBaker/VA_ModelBaker.cs rename {Runtime => Editor}/Scripts/ModelBaker/VA_ModelBaker.cs.meta (100%) create mode 100644 Runtime/Scripts/ModelBaker/AnimationMaterial.cs create mode 100644 Runtime/Scripts/ModelBaker/AnimationMaterial.cs.meta delete mode 100644 Runtime/Scripts/ModelBaker/VA_ModelBaker.cs diff --git a/Editor/Scripts/Editor/AssetDatabaseUtils.cs b/Editor/Scripts/Editor/AssetDatabaseUtils.cs new file mode 100644 index 0000000..611258c --- /dev/null +++ b/Editor/Scripts/Editor/AssetDatabaseUtils.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using UnityEditor; + +namespace TAO.VertexAnimation.Editor +{ + public static class AssetDatabaseUtils + { + public static bool HasChildAsset(Object parent, Object child) + { + var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(parent)); + + foreach (var a in assets) + { + if (a == child) + { + return true; + } + } + + return false; + } + + public static void RemoveChildAssets(Object parent, Object[] filter = null) + { + var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(parent)); + + foreach (var a in assets) + { + bool filterSkip = false; + + foreach (var f in filter) + { + if (a == f) + { + filterSkip = true; + break; + } + } + + if (!filterSkip && a != parent) + { + AssetDatabase.RemoveObjectFromAsset(a); + } + } + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Editor/AssetDatabaseUtils.cs.meta b/Editor/Scripts/Editor/AssetDatabaseUtils.cs.meta new file mode 100644 index 0000000..bfdf986 --- /dev/null +++ b/Editor/Scripts/Editor/AssetDatabaseUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d394aa43ff9889d45878e965ac0f1a30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Editor/VA_AnimationBookEditor.cs b/Editor/Scripts/Editor/VA_AnimationBookEditor.cs index 1000889..9dfe4c9 100644 --- a/Editor/Scripts/Editor/VA_AnimationBookEditor.cs +++ b/Editor/Scripts/Editor/VA_AnimationBookEditor.cs @@ -68,6 +68,7 @@ namespace TAO.VertexAnimation.Editor using (new EditorGUILayout.VerticalScope()) { EditorGUILayout.LabelField("General", EditorStyles.centeredGreyMiniLabel); + EditorGUILayout.PropertyField(editorData.FindPropertyRelative("fps")); EditorGUILayout.PropertyField(editorData.FindPropertyRelative("maxFrames")); } } diff --git a/Editor/Scripts/ModelBaker/AnimationPrefab.cs b/Editor/Scripts/ModelBaker/AnimationPrefab.cs new file mode 100644 index 0000000..5fff3ca --- /dev/null +++ b/Editor/Scripts/ModelBaker/AnimationPrefab.cs @@ -0,0 +1,52 @@ +using UnityEngine; +using UnityEditor; + +namespace TAO.VertexAnimation.Editor +{ + public static class AnimationPrefab + { + public static GameObject Create(string path, string name, Mesh[] meshes, Material material, float[] lodTransitions) + { + // Create parent. + GameObject parent = new GameObject(name, typeof(LODGroup), typeof(VA_AnimatorComponentAuthoring), typeof(Unity.Entities.ConvertToEntity)); + + // Create all LODs. + LOD[] lods = new LOD[meshes.Length]; + + for (int i = 0; i < meshes.Length; i++) + { + GameObject lod = new GameObject(string.Format("{0}_LOD{1}", name, i), typeof(MeshFilter), typeof(MeshRenderer)); + + var mf = lod.GetComponent(); + mf.sharedMesh = meshes[i]; + var mr = lod.GetComponent(); + mr.sharedMaterial = material; + + lod.transform.SetParent(parent.transform); + lods[i] = new LOD(lodTransitions[i], new Renderer[1] { mr }); + } + + var lodGroup = parent.GetComponent(); + lodGroup.SetLODs(lods); + lodGroup.RecalculateBounds(); + + // Create prefab. + GameObject prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(parent, path, InteractionMode.AutomatedAction); + GameObject.DestroyImmediate(parent); + + return prefab; + } + + public static GameObject Create(string path, string name, Mesh[] meshes, Material material, AnimationCurve lodTransitions) + { + float[] lt = new float[meshes.Length]; + + for (int i = 0; i < lt.Length; i++) + { + lt[i] = lodTransitions.Evaluate((1.0f / lt.Length) * (i + 1)); + } + + return Create(path, name, meshes, material, lt); + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/ModelBaker/AnimationPrefab.cs.meta b/Editor/Scripts/ModelBaker/AnimationPrefab.cs.meta new file mode 100644 index 0000000..9835ae6 --- /dev/null +++ b/Editor/Scripts/ModelBaker/AnimationPrefab.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b2f9ea47456fd24387722ab88de04c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs index e1d5266..0173b28 100644 --- a/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs +++ b/Editor/Scripts/ModelBaker/Editor/VA_ModelBakerEditor.cs @@ -5,212 +5,87 @@ using System.Linq; namespace TAO.VertexAnimation.Editor { - [CustomEditor(typeof(VA_ModelBaker))] - public class VA_ModelBakerEditor : UnityEditor.Editor - { - private VA_ModelBaker modelBaker = null; + [CustomEditor(typeof(VA_ModelBaker))] + public class VA_ModelBakerEditor : UnityEditor.Editor + { + private VA_ModelBaker modelBaker = null; - void OnEnable() - { - modelBaker = target as VA_ModelBaker; - } + void OnEnable() + { + modelBaker = target as VA_ModelBaker; + } - public override void OnInspectorGUI() - { - serializedObject.Update(); + public override void OnInspectorGUI() + { + serializedObject.Update(); - InputGUI(); - EditorGUILayoutUtils.HorizontalLine(color: Color.gray); - BakeGUI(); + InputGUI(); + EditorGUILayoutUtils.HorizontalLine(color: Color.gray); + BakeGUI(); - serializedObject.ApplyModifiedProperties(); + serializedObject.ApplyModifiedProperties(); - EditorGUILayoutUtils.HorizontalLine(color: Color.gray); - OutputGUI(); - } + 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 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")); + private void BakeGUI() + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("saveBakedDataToAsset")); - int il = EditorGUI.indentLevel; - if (modelBaker.saveBakedDataToAsset) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(serializedObject.FindProperty("generateAnimationBook")); + 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; + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("generateLODS")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("lodCurve"), new GUIContent("")); + } - if (GUILayout.Button("Bake", GUILayout.Height(32))) - { - ClearBakedData(); + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("generatePrefab")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("materialShader"), new GUIContent("")); + } + } + EditorGUI.indentLevel = il; - modelBaker.Bake(); + if (GUILayout.Button("Bake", GUILayout.Height(32))) + { + modelBaker.Bake(); - if (modelBaker.saveBakedDataToAsset) - { - SaveBakedData(); - } - } + if (modelBaker.saveBakedDataToAsset) + { + modelBaker.SaveAssets(); + } + } - if (modelBaker.BakedData.mesh != null) - { - using (new EditorGUILayout.HorizontalScope()) - { - if (GUILayout.Button("Save", EditorStyles.miniButtonLeft)) - { - SaveBakedData(); - } + if (GUILayout.Button("Delete", EditorStyles.miniButtonRight)) + { + if (EditorUtility.DisplayDialog("Delete Assets", "Deleting assets will loose references within the project.", "Ok", "Cancel")) + { + modelBaker.DeleteSavedAssets(); + } + } + } - 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(); - } - } + private void OutputGUI() + { + using (new EditorGUI.DisabledGroupScope(true)) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData")); + } + } + } } \ No newline at end of file diff --git a/Editor/Scripts/ModelBaker/VA_ModelBaker.cs b/Editor/Scripts/ModelBaker/VA_ModelBaker.cs new file mode 100644 index 0000000..f72da5a --- /dev/null +++ b/Editor/Scripts/ModelBaker/VA_ModelBaker.cs @@ -0,0 +1,169 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace TAO.VertexAnimation.Editor +{ + [CreateAssetMenu(fileName = "new ModelBaker", menuName = "VA_ModelBaker/ModelBaker", order = 400)] + public class VA_ModelBaker : ScriptableObject + { +#if UNITY_EDITOR + // Input. + public GameObject model; + public AnimationClip[] animationClips; + [Range(1, 60)] + public int fps = 24; + public int textureWidth = 512; + + public bool generateLODS = true; + public AnimationCurve lodCurve = new AnimationCurve(new Keyframe(0, 1), new Keyframe(1, 0.01f)); + public bool saveBakedDataToAsset = true; + public bool generateAnimationBook = true; + public bool generatePrefab = true; + public Shader materialShader = null; + + // Output. + public GameObject prefab = null; + public Material material = null; + public Mesh[] meshes = null; + public VA_AnimationBook book = null; + + [SerializeField] + private AnimationBaker.BakedData bakedData; + + public void Bake() + { + var target = Instantiate(model); + target.name = model.name; + + target.ConbineAndConvertGameObject(); + bakedData = target.Bake(animationClips, fps, textureWidth); + + if (generateLODS) + { + // TODO: LODs. + meshes = new Mesh[1] { bakedData.mesh }; + } + else + { + meshes = new Mesh[1] { bakedData.mesh }; + } + + DestroyImmediate(target); + } + + public void SaveAssets() + { + AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material }); + + // TODO: LODs + AssetDatabase.AddObjectToAsset(bakedData.mesh, this); + + foreach (var pm in bakedData.positionMaps) + { + AssetDatabase.AddObjectToAsset(pm, this); + } + + AssetDatabase.SaveAssets(); + + if (generatePrefab) + { + GeneratePrefab(); + } + + if (generateAnimationBook) + { + GenerateBook(); + } + + 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(); + } + + public void GeneratePrefab() + { + string path = AssetDatabase.GetAssetPath(this); + int start = path.LastIndexOf('/'); + path = path.Remove(start, path.Length - start); + path += "/" + name + ".prefab"; + + // Generate Material + if (!AssetDatabaseUtils.HasChildAsset(this, material)) + { + material = AnimationMaterial.Create(name, materialShader); + AssetDatabase.AddObjectToAsset(material, this); + } + else + { + material.shader = materialShader; + } + + // Generate Prefab + prefab = AnimationPrefab.Create(path, name, meshes, material, lodCurve); + } + + public void GenerateBook() + { + if (!book) + { + book = CreateInstance(); + } + + book.name = string.Format("{0}Book", name); + book.editorData = new VA_AnimationBook.EditorData + { + materials = new Material[1] { material } + }; + + foreach (Texture2D tex in bakedData.positionMaps) + { + book.editorData.animationPages.Add(new VA_AnimationBook.EditorAnimationPage + { + name = "", + frames = 0, + textures = new List() + { + new VA_AnimationBook.EditorTextureEntry + { + texture2D = tex + } + } + }); + } + + VA_AssetBuilder.AutoFill(ref book); + + if (!AssetDatabaseUtils.HasChildAsset(this, book)) + { + AssetDatabase.AddObjectToAsset(book, this); + } + } +#endif + } +} diff --git a/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs.meta b/Editor/Scripts/ModelBaker/VA_ModelBaker.cs.meta similarity index 100% rename from Runtime/Scripts/ModelBaker/VA_ModelBaker.cs.meta rename to Editor/Scripts/ModelBaker/VA_ModelBaker.cs.meta diff --git a/Editor/Scripts/VA_AssetBuilder.cs b/Editor/Scripts/VA_AssetBuilder.cs index f9c1f4b..6010603 100644 --- a/Editor/Scripts/VA_AssetBuilder.cs +++ b/Editor/Scripts/VA_AssetBuilder.cs @@ -300,6 +300,13 @@ namespace TAO.VertexAnimation.Editor book.editorData.maxFrames = maxFrames; } } + else if (p.StartsWith("FPS-")) + { + if (int.TryParse(p.Remove(0, 4), out int fps)) + { + book.editorData.fps = fps; + } + } } } book.editorData.animationPages[i] = ap; @@ -339,6 +346,7 @@ namespace TAO.VertexAnimation.Editor { book.playData = new VA_AnimationBook.PlayData { + fps = book.editorData.fps, maxFrames = book.editorData.maxFrames, materials = book.editorData.materials }; diff --git a/Editor/TAO.VertexAnimation.Editor.asmdef b/Editor/TAO.VertexAnimation.Editor.asmdef index 0375674..60548e6 100644 --- a/Editor/TAO.VertexAnimation.Editor.asmdef +++ b/Editor/TAO.VertexAnimation.Editor.asmdef @@ -3,7 +3,9 @@ "rootNamespace": "TAO.VertexAnimation.Editor", "references": [ "TAO.VertexAnimation", - "Unity.Collections" + "Unity.Collections", + "Unity.Entities", + "Unity.Entities.Hybrid" ], "includePlatforms": [ "Editor" diff --git a/Runtime/Scripts/ModelBaker/AnimationBaker.cs b/Runtime/Scripts/ModelBaker/AnimationBaker.cs index d90fb13..2478cf9 100644 --- a/Runtime/Scripts/ModelBaker/AnimationBaker.cs +++ b/Runtime/Scripts/ModelBaker/AnimationBaker.cs @@ -3,187 +3,190 @@ using UnityEngine; namespace TAO.VertexAnimation { - public static class AnimationBaker - { - [System.Serializable] - public struct BakedData - { - public Mesh mesh; - public List positionMaps; + public static class AnimationBaker + { + [System.Serializable] + public struct BakedData + { + public Mesh mesh; + public List positionMaps; - // Returns main position map. - public Texture2D GetPositionMap - { - get - { - return positionMaps[0]; - } - } - } + // Returns main position map. + public Texture2D GetPositionMap + { + get + { + return positionMaps[0]; + } + } + } - [System.Serializable] - public struct AnimationInfo - { - public int rawFrameHeight; - public int frameHeight; - public int frameSpacing; - public int frames; - public int maxFrames; - public int textureWidth; - public int textureHeight; + [System.Serializable] + public struct AnimationInfo + { + public int rawFrameHeight; + public int frameHeight; + public int frameSpacing; + public int frames; + public int maxFrames; + public int textureWidth; + public int textureHeight; + public int fps; - // Create animation info and calculate values. - public AnimationInfo(Mesh mesh, int frames, int textureWidth) - { - this.frames = frames; - this.textureWidth = textureWidth; + // Create animation info and calculate values. + public AnimationInfo(Mesh mesh, int frames, int textureWidth, int fps) + { + this.frames = frames; + this.textureWidth = textureWidth; + this.fps = fps; - rawFrameHeight = Mathf.CeilToInt((float)mesh.vertices.Length / this.textureWidth); - frameHeight = Mathf.NextPowerOfTwo(rawFrameHeight); - frameSpacing = (frameHeight - rawFrameHeight) + 1; + rawFrameHeight = Mathf.CeilToInt((float)mesh.vertices.Length / this.textureWidth); + frameHeight = Mathf.NextPowerOfTwo(rawFrameHeight); + frameSpacing = (frameHeight - rawFrameHeight) + 1; - textureHeight = Mathf.NextPowerOfTwo(frameHeight * this.frames); + textureHeight = Mathf.NextPowerOfTwo(frameHeight * this.frames); - maxFrames = textureHeight / frameHeight; - } - } + maxFrames = textureHeight / frameHeight; + } + } - public static BakedData Bake(this GameObject model, AnimationClip[] animationClips, int fps, int textureWidth) - { - BakedData bakedData = new BakedData() - { - mesh = null, - positionMaps = new List() - }; + public static BakedData Bake(this GameObject model, AnimationClip[] animationClips, int fps, int textureWidth) + { + BakedData bakedData = new BakedData() + { + mesh = null, + positionMaps = new List() + }; - // Calculate what our max frames/time is going to be. - int maxFrames = 0; - foreach (AnimationClip ac in animationClips) - { - int frames = Mathf.FloorToInt(fps * ac.length); + // Calculate what our max frames/time is going to be. + int maxFrames = 0; + foreach (AnimationClip ac in animationClips) + { + int frames = Mathf.FloorToInt(fps * ac.length); - if (maxFrames < frames) - { - maxFrames = frames; - } - } + if (maxFrames < frames) + { + maxFrames = frames; + } + } - // Get the target mesh to calculate the animation info. - Mesh mesh = model.GetComponent().sharedMesh; + // Get the target mesh to calculate the animation info. + Mesh mesh = model.GetComponent().sharedMesh; - // Get the info for the biggest animation. - AnimationInfo animationInfo = new AnimationInfo(mesh, maxFrames, textureWidth); + // Get the info for the biggest animation. + AnimationInfo animationInfo = new AnimationInfo(mesh, maxFrames, textureWidth, fps); - foreach (AnimationClip ac in animationClips) - { - // Set the frames for this animation. - animationInfo.frames = Mathf.FloorToInt(fps * ac.length); + foreach (AnimationClip ac in animationClips) + { + // Set the frames for this animation. + animationInfo.frames = Mathf.FloorToInt(fps * ac.length); - BakedData bd = Bake(model, ac, animationInfo); - bakedData.mesh = bd.mesh; - bakedData.positionMaps.AddRange(bd.positionMaps); - } + BakedData bd = Bake(model, ac, animationInfo); + bakedData.mesh = bd.mesh; + bakedData.positionMaps.AddRange(bd.positionMaps); + } - return bakedData; - } + return bakedData; + } - public static BakedData Bake(this GameObject model, AnimationClip animationClip, AnimationInfo animationInfo) - { - Mesh mesh = new Mesh - { - name = string.Format("{0}", model.name) - }; + public static BakedData Bake(this GameObject model, AnimationClip animationClip, AnimationInfo animationInfo) + { + Mesh mesh = new Mesh + { + name = string.Format("{0}", model.name) + }; - // Bake mesh for a copy and to apply the new UV's to. - SkinnedMeshRenderer skinnedMeshRenderer = model.GetComponent(); - skinnedMeshRenderer.BakeMesh(mesh); - mesh.RecalculateBounds(); + // Bake mesh for a copy and to apply the new UV's to. + SkinnedMeshRenderer skinnedMeshRenderer = model.GetComponent(); + skinnedMeshRenderer.BakeMesh(mesh); + mesh.RecalculateBounds(); - mesh.uv3 = mesh.BakePositionUVs(animationInfo); + mesh.uv3 = mesh.BakePositionUVs(animationInfo); - BakedData bakedData = new BakedData() - { - mesh = mesh, - positionMaps = new List() { BakePositionMap(model, animationClip, animationInfo) } - }; + BakedData bakedData = new BakedData() + { + mesh = mesh, + positionMaps = new List() { BakePositionMap(model, animationClip, animationInfo) } + }; - return bakedData; - } + return bakedData; + } - public static Texture2D BakePositionMap(this GameObject model, AnimationClip animationClip, AnimationInfo animationInfo) - { - // Create positionMap Texture without MipMaps which is Linear and HDR to store values in a bigger range. - Texture2D positionMap = new Texture2D(animationInfo.textureWidth, animationInfo.textureHeight, TextureFormat.RGBAHalf, false, true); + public static Texture2D BakePositionMap(this GameObject model, AnimationClip animationClip, AnimationInfo animationInfo) + { + // Create positionMap Texture without MipMaps which is Linear and HDR to store values in a bigger range. + Texture2D positionMap = new Texture2D(animationInfo.textureWidth, animationInfo.textureHeight, TextureFormat.RGBAHalf, false, true); - // Create instance to sample from. - GameObject inst = GameObject.Instantiate(model); - SkinnedMeshRenderer skinnedMeshRenderer = inst.GetComponent(); + // Create instance to sample from. + GameObject inst = GameObject.Instantiate(model); + SkinnedMeshRenderer skinnedMeshRenderer = inst.GetComponent(); - int y = 0; - for (int f = 0; f < animationInfo.frames; f++) - { - animationClip.SampleAnimation(inst, (animationClip.length / animationInfo.frames) * f); + int y = 0; + for (int f = 0; f < animationInfo.frames; f++) + { + animationClip.SampleAnimation(inst, (animationClip.length / animationInfo.frames) * f); - Mesh sampledMesh = new Mesh(); - skinnedMeshRenderer.BakeMesh(sampledMesh); - sampledMesh.RecalculateBounds(); + Mesh sampledMesh = new Mesh(); + skinnedMeshRenderer.BakeMesh(sampledMesh); + sampledMesh.RecalculateBounds(); - int x = 0; - for (int v = 0; v < sampledMesh.vertices.Length; v++) - { - Vector3 vert = sampledMesh.vertices[v]; - Vector3 normal = sampledMesh.normals[v]; + List verts = new List(); + sampledMesh.GetVertices(verts); + List normals = new List(); + sampledMesh.GetNormals(normals); - positionMap.SetPixel(x, y, - new Color(vert.x, vert.y, vert.z, - VectorUtils.Float3ToFloat(normal)) - ); + int x = 0; + for (int v = 0; v < verts.Count; v++) + { + positionMap.SetPixel(x, y, + new Color(verts[v].x, verts[v].y, verts[v].z, + VectorUtils.Float3ToFloat(normals[v])) + ); - x++; - if (x >= animationInfo.textureWidth) - { - x = 0; - y++; - } - } - y += animationInfo.frameSpacing; - } + x++; + if (x >= animationInfo.textureWidth) + { + x = 0; + y++; + } + } + y += animationInfo.frameSpacing; + } - GameObject.DestroyImmediate(inst); + GameObject.DestroyImmediate(inst); - positionMap.name = string.Format("VA_N-{0}_F-{1}_MF-{2}", animationClip.name, animationInfo.frames, animationInfo.maxFrames); - positionMap.filterMode = FilterMode.Point; - // TODO: Make no longer readable. - positionMap.Apply(false, false); + positionMap.name = string.Format("VA_N-{0}_F-{1}_MF-{2}_FPS-{3}", animationClip.name, animationInfo.frames, animationInfo.maxFrames, animationInfo.fps); + positionMap.filterMode = FilterMode.Point; + positionMap.Apply(false, true); - return positionMap; - } + return positionMap; + } - public static Vector2[] BakePositionUVs(this Mesh mesh, AnimationInfo animationInfo) - { - Vector2[] uv3 = new Vector2[mesh.vertices.Length]; + public static Vector2[] BakePositionUVs(this Mesh mesh, AnimationInfo animationInfo) + { + Vector2[] uv3 = new Vector2[mesh.vertexCount]; - float xOffset = 1.0f / animationInfo.textureWidth; - float yOffset = 1.0f / animationInfo.textureHeight; + float xOffset = 1.0f / animationInfo.textureWidth; + float yOffset = 1.0f / animationInfo.textureHeight; - float x = xOffset / 2.0f; - float y = yOffset / 2.0f; + float x = xOffset / 2.0f; + float y = yOffset / 2.0f; - for (int v = 0; v < mesh.vertices.Length; v++) - { - uv3[v] = new Vector2(x, y); + for (int v = 0; v < uv3.Length; v++) + { + uv3[v] = new Vector2(x, y); - x += xOffset; - if (x >= 1.0f) - { - x = xOffset / 2.0f; - y += yOffset; - } - } + x += xOffset; + if (x >= 1.0f) + { + x = xOffset / 2.0f; + y += yOffset; + } + } - mesh.uv3 = uv3; + mesh.uv3 = uv3; - return uv3; - } - } + return uv3; + } + } } \ No newline at end of file diff --git a/Runtime/Scripts/ModelBaker/AnimationMaterial.cs b/Runtime/Scripts/ModelBaker/AnimationMaterial.cs new file mode 100644 index 0000000..0fe1b1c --- /dev/null +++ b/Runtime/Scripts/ModelBaker/AnimationMaterial.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace TAO.VertexAnimation +{ + public static class AnimationMaterial + { + public static Material Create(string name, Shader shader) + { + Material material = new Material(shader) + { + name = name, + enableInstancing = true + }; + + return material; + } + } +} \ No newline at end of file diff --git a/Runtime/Scripts/ModelBaker/AnimationMaterial.cs.meta b/Runtime/Scripts/ModelBaker/AnimationMaterial.cs.meta new file mode 100644 index 0000000..c2ee927 --- /dev/null +++ b/Runtime/Scripts/ModelBaker/AnimationMaterial.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c06ab1e65507bd46925ac9091097b58 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/ModelBaker/MeshCombiner.cs b/Runtime/Scripts/ModelBaker/MeshCombiner.cs index 9369336..04a8b4a 100644 --- a/Runtime/Scripts/ModelBaker/MeshCombiner.cs +++ b/Runtime/Scripts/ModelBaker/MeshCombiner.cs @@ -1,242 +1,247 @@ -using UnityEngine; +// 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 + +using UnityEngine; using System.Collections.Generic; using System.Linq; namespace TAO.VertexAnimation { - public static class MeshCombiner - { - private struct MaterialMeshGroup - { - public List skinnedMeshes; - public List<(MeshFilter mf, MeshRenderer mr)> meshes; - public Material material; - } + public static class MeshCombiner + { + private struct MaterialMeshGroup + { + public List skinnedMeshes; + public List<(MeshFilter mf, MeshRenderer mr)> meshes; + public Material material; + } - public static SkinnedMeshRenderer Combine(this SkinnedMeshRenderer target, List skinnedMeshes, List<(MeshFilter mf, MeshRenderer mr)> meshes) - { - List groups = new List(); + public static SkinnedMeshRenderer Combine(this SkinnedMeshRenderer target, List skinnedMeshes, List<(MeshFilter mf, MeshRenderer mr)> meshes) + { + List groups = new List(); - // Group skinnedMeshes. - foreach (var sm in skinnedMeshes) - { - bool hasGroup = false; - foreach (var g in groups) - { - if (sm.sharedMaterial == g.material) - { - hasGroup = true; - g.skinnedMeshes.Add(sm); - } - } + // Group skinnedMeshes. + foreach (var sm in skinnedMeshes) + { + bool hasGroup = false; + foreach (var g in groups) + { + if (sm.sharedMaterial == g.material) + { + hasGroup = true; + g.skinnedMeshes.Add(sm); + } + } - if (!hasGroup) - { - groups.Add(new MaterialMeshGroup() - { - skinnedMeshes = new List() - { - sm - }, - meshes = new List<(MeshFilter mf, MeshRenderer mr)>(), - material = sm.sharedMaterial - }); - } - } + if (!hasGroup) + { + groups.Add(new MaterialMeshGroup() + { + skinnedMeshes = new List() + { + sm + }, + meshes = new List<(MeshFilter mf, MeshRenderer mr)>(), + material = sm.sharedMaterial + }); + } + } - // Group Meshes. - foreach (var m in meshes) - { - bool hasGroup = false; - foreach (var g in groups) - { - if (m.mr.sharedMaterial == g.material) - { - hasGroup = true; - g.meshes.Add(m); - } - } + // Group Meshes. + foreach (var m in meshes) + { + bool hasGroup = false; + foreach (var g in groups) + { + if (m.mr.sharedMaterial == g.material) + { + hasGroup = true; + g.meshes.Add(m); + } + } - if (!hasGroup) - { - groups.Add(new MaterialMeshGroup() - { - skinnedMeshes = new List(), - meshes = new List<(MeshFilter mf, MeshRenderer mr)>() - { - m - }, - material = m.mr.sharedMaterial - }); - } - } + if (!hasGroup) + { + groups.Add(new MaterialMeshGroup() + { + skinnedMeshes = new List(), + meshes = new List<(MeshFilter mf, MeshRenderer mr)>() + { + m + }, + material = m.mr.sharedMaterial + }); + } + } - List tmp = new List(); - for (int i = 0; i < groups.Count; i++) - { - tmp.Add(new GameObject("tmpChild", typeof(SkinnedMeshRenderer))); - tmp[i].transform.parent = target.transform; + List tmp = new List(); + for (int i = 0; i < groups.Count; i++) + { + tmp.Add(new GameObject("tmpChild", typeof(SkinnedMeshRenderer))); + tmp[i].transform.parent = target.transform; - MaterialMeshGroup mmg = groups[i]; - tmp[i].GetComponent().Combine(mmg.skinnedMeshes, mmg.meshes, mmg.material); - } + MaterialMeshGroup mmg = groups[i]; + tmp[i].GetComponent().Combine(mmg.skinnedMeshes, mmg.meshes, mmg.material); + } - // TODO: Merge materialMergedObjects. - // TEMP: Remove when materialMergedObjects. - SkinnedMeshRenderer newSkinnedMeshRenderer = tmp[0].GetComponent(); - target.sharedMesh = newSkinnedMeshRenderer.sharedMesh; - target.sharedMaterial = newSkinnedMeshRenderer.sharedMaterial; - target.bones = newSkinnedMeshRenderer.bones; + // TODO: Merge materialMergedObjects. + // TEMP: Remove when materialMergedObjects. + SkinnedMeshRenderer newSkinnedMeshRenderer = tmp[0].GetComponent(); + target.sharedMesh = newSkinnedMeshRenderer.sharedMesh; + target.sharedMaterial = newSkinnedMeshRenderer.sharedMaterial; + target.bones = newSkinnedMeshRenderer.bones; - foreach (var go in tmp) - { - GameObject.DestroyImmediate(go); - } + foreach (var go in tmp) + { + GameObject.DestroyImmediate(go); + } - // Set a name to make it more clear. - target.sharedMesh.name = target.transform.name.Replace("(Clone)", ""); - return target; - } + // Set a name to make it more clear. + target.sharedMesh.name = target.transform.name.Replace("(Clone)", ""); + return target; + } - public static SkinnedMeshRenderer Combine(this SkinnedMeshRenderer target, List skinnedMeshes, List<(MeshFilter mf, MeshRenderer mr)> meshes, Material mainMaterial) - { - List bones = new List(); - List boneWeights = new List(); - List bindPoses = new List(); - List combineInstances = new List(); + public static SkinnedMeshRenderer Combine(this SkinnedMeshRenderer target, List skinnedMeshes, List<(MeshFilter mf, MeshRenderer mr)> meshes, Material mainMaterial) + { + List bones = new List(); + List boneWeights = new List(); + List bindPoses = new List(); + List combineInstances = new List(); - // Combine SkinnedMeshes. - int boneOffset = 0; - for (int s = 0; s < skinnedMeshes.Count; s++) - { - SkinnedMeshRenderer smr = skinnedMeshes[s]; + // Combine SkinnedMeshes. + int boneOffset = 0; + for (int s = 0; s < skinnedMeshes.Count; s++) + { + SkinnedMeshRenderer smr = skinnedMeshes[s]; - //if the skinned mesh renderer has a material other than the default - //we assume it's a one-off face material and deal with it later - if (smr.sharedMaterial != mainMaterial) - { - continue; - } + //if the skinned mesh renderer has a material other than the default + //we assume it's a one-off face material and deal with it later + if (smr.sharedMaterial != mainMaterial) + { + continue; + } - BoneWeight[] meshBoneweight = smr.sharedMesh.boneWeights; + BoneWeight[] meshBoneweight = smr.sharedMesh.boneWeights; - // May want to modify this if the renderer shares bones as unnecessary bones will get added. - // We don't care since it is going to be converted into vertex animations later anyways. - for (int i = 0; i < meshBoneweight.Length; ++i) - { - BoneWeight bWeight = meshBoneweight[i]; + // May want to modify this if the renderer shares bones as unnecessary bones will get added. + // We don't care since it is going to be converted into vertex animations later anyways. + for (int i = 0; i < meshBoneweight.Length; ++i) + { + BoneWeight bWeight = meshBoneweight[i]; - bWeight.boneIndex0 += boneOffset; - bWeight.boneIndex1 += boneOffset; - bWeight.boneIndex2 += boneOffset; - bWeight.boneIndex3 += boneOffset; + bWeight.boneIndex0 += boneOffset; + bWeight.boneIndex1 += boneOffset; + bWeight.boneIndex2 += boneOffset; + bWeight.boneIndex3 += boneOffset; - boneWeights.Add(bWeight); - } + boneWeights.Add(bWeight); + } - boneOffset += smr.bones.Length; + boneOffset += smr.bones.Length; - Transform[] meshBones = smr.bones; - for (int i = 0; i < meshBones.Length; ++i) - { - bones.Add(meshBones[i]); + Transform[] meshBones = smr.bones; + for (int i = 0; i < meshBones.Length; ++i) + { + bones.Add(meshBones[i]); - //we take the old bind pose that mapped from our mesh to world to bone, - //and take out our localToWorldMatrix, so now it's JUST the bone matrix - //since our skinned mesh renderer is going to be on the root of our object that works - bindPoses.Add(smr.sharedMesh.bindposes[i] * smr.transform.worldToLocalMatrix); - } + //we take the old bind pose that mapped from our mesh to world to bone, + //and take out our localToWorldMatrix, so now it's JUST the bone matrix + //since our skinned mesh renderer is going to be on the root of our object that works + bindPoses.Add(smr.sharedMesh.bindposes[i] * smr.transform.worldToLocalMatrix); + } - CombineInstance ci = new CombineInstance - { - mesh = smr.sharedMesh, - transform = smr.transform.localToWorldMatrix - }; - combineInstances.Add(ci); + CombineInstance ci = new CombineInstance + { + mesh = smr.sharedMesh, + transform = smr.transform.localToWorldMatrix + }; + combineInstances.Add(ci); - GameObject.DestroyImmediate(smr); - } + GameObject.DestroyImmediate(smr); + } - // Combine Meshes. - for (int s = 0; meshes != null && s < meshes.Count; s++) - { - MeshFilter filter = meshes[s].mf; - MeshRenderer renderer = meshes[s].mr; - - //if the skinned mesh renderer has a material other than the default - //we assume it's a one-off face material and deal with it later - if (renderer.sharedMaterial != mainMaterial) - { - continue; - } + // Combine Meshes. + for (int s = 0; meshes != null && s < meshes.Count; s++) + { + MeshFilter filter = meshes[s].mf; + MeshRenderer renderer = meshes[s].mr; + + //if the skinned mesh renderer has a material other than the default + //we assume it's a one-off face material and deal with it later + if (renderer.sharedMaterial != mainMaterial) + { + continue; + } - // May want to modify this if the renderer shares bones as unnecessary bones will get added. - // We don't care since it is going to be converted into vertex animations later anyways. - int vertCount = filter.sharedMesh.vertexCount; - for (int i = 0; i < vertCount; ++i) - { - BoneWeight bWeight = new BoneWeight - { - boneIndex0 = boneOffset, - boneIndex1 = boneOffset, - boneIndex2 = boneOffset, - boneIndex3 = boneOffset, - weight0 = 1 - }; + // May want to modify this if the renderer shares bones as unnecessary bones will get added. + // We don't care since it is going to be converted into vertex animations later anyways. + int vertCount = filter.sharedMesh.vertexCount; + for (int i = 0; i < vertCount; ++i) + { + BoneWeight bWeight = new BoneWeight + { + boneIndex0 = boneOffset, + boneIndex1 = boneOffset, + boneIndex2 = boneOffset, + boneIndex3 = boneOffset, + weight0 = 1 + }; - boneWeights.Add(bWeight); - } + boneWeights.Add(bWeight); + } - boneOffset += 1; + boneOffset += 1; - bones.Add(filter.transform); + bones.Add(filter.transform); - // TODO: figure out what this should be. - bindPoses.Add(filter.transform.worldToLocalMatrix); + // TODO: figure out what this should be. + bindPoses.Add(filter.transform.worldToLocalMatrix); - CombineInstance ci = new CombineInstance - { - mesh = filter.sharedMesh, - transform = filter.transform.localToWorldMatrix - }; - combineInstances.Add(ci); + CombineInstance ci = new CombineInstance + { + mesh = filter.sharedMesh, + transform = filter.transform.localToWorldMatrix + }; + combineInstances.Add(ci); - GameObject.DestroyImmediate(filter); - GameObject.DestroyImmediate(renderer); - } + GameObject.DestroyImmediate(filter); + GameObject.DestroyImmediate(renderer); + } - // Actually combine and recalculate mesh. - Mesh skinnedMesh = new Mesh(); - skinnedMesh.CombineMeshes(combineInstances.ToArray(), true, true); - skinnedMesh.RecalculateBounds(); + // Actually combine and recalculate mesh. + Mesh skinnedMesh = new Mesh(); + skinnedMesh.CombineMeshes(combineInstances.ToArray(), true, true); + skinnedMesh.RecalculateBounds(); - // Copy settings to target. - target.sharedMesh = skinnedMesh; - target.sharedMaterial = mainMaterial; - target.bones = bones.ToArray(); - target.sharedMesh.boneWeights = boneWeights.ToArray(); - target.sharedMesh.bindposes = bindPoses.ToArray(); + // Copy settings to target. + target.sharedMesh = skinnedMesh; + target.sharedMaterial = mainMaterial; + target.bones = bones.ToArray(); + target.sharedMesh.boneWeights = boneWeights.ToArray(); + target.sharedMesh.bindposes = bindPoses.ToArray(); - return target; - } + return target; + } - public static void ConbineAndConvertGameObject(this GameObject gameObject) - { - // Get Skinned Meshes. - List skinnedMeshes = gameObject.GetComponentsInChildren(true).ToList(); - // Get Meshes. - List<(MeshFilter, MeshRenderer)> meshes = new List<(MeshFilter, MeshRenderer)>(); - foreach (var mf in gameObject.GetComponentsInChildren(true)) - { - if (mf.TryGetComponent(out MeshRenderer mr)) - { - meshes.Add((mf, mr)); - } - } + public static void ConbineAndConvertGameObject(this GameObject gameObject) + { + // Get Skinned Meshes. + List skinnedMeshes = gameObject.GetComponentsInChildren(true).ToList(); + // Get Meshes. + List<(MeshFilter, MeshRenderer)> meshes = new List<(MeshFilter, MeshRenderer)>(); + foreach (var mf in gameObject.GetComponentsInChildren(true)) + { + if (mf.TryGetComponent(out MeshRenderer mr)) + { + meshes.Add((mf, mr)); + } + } - // Add target mesh. - SkinnedMeshRenderer target = gameObject.AddComponent(); - target.Combine(skinnedMeshes, meshes); - } - } + // Add target mesh. + SkinnedMeshRenderer target = gameObject.AddComponent(); + target.Combine(skinnedMeshes, meshes); + } + } } \ No newline at end of file diff --git a/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs b/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs deleted file mode 100644 index ee47b33..0000000 --- a/Runtime/Scripts/ModelBaker/VA_ModelBaker.cs +++ /dev/null @@ -1,45 +0,0 @@ -using UnityEngine; - -namespace TAO.VertexAnimation -{ - [CreateAssetMenu(fileName = "new ModelBaker", menuName = "VA_ModelBaker/ModelBaker", order = 400)] - public class VA_ModelBaker : ScriptableObject - { - 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 = 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; - public AnimationBaker.BakedData BakedData - { - get - { - return bakedData; - } - } - - public void Bake() - { - var target = Instantiate(model); - - target.ConbineAndConvertGameObject(); - bakedData = target.Bake(animationClips, fps, textureWidth); - - DestroyImmediate(target); - } - } -} \ No newline at end of file diff --git a/Runtime/Scripts/VA_AnimationBook.cs b/Runtime/Scripts/VA_AnimationBook.cs index 85973f2..018dbe0 100644 --- a/Runtime/Scripts/VA_AnimationBook.cs +++ b/Runtime/Scripts/VA_AnimationBook.cs @@ -3,173 +3,176 @@ using UnityEngine; namespace TAO.VertexAnimation { - [CreateAssetMenu(fileName = "new AnimationBook", menuName = "VA_Animation/AnimationBook", order = 400)] - public class VA_AnimationBook : ScriptableObject - { - public PlayData playData = null; + [CreateAssetMenu(fileName = "new AnimationBook", menuName = "VA_Animation/AnimationBook", order = 400)] + public class VA_AnimationBook : ScriptableObject + { + public PlayData playData = null; #if UNITY_EDITOR - public EditorData editorData = new EditorData(); + public EditorData editorData = new EditorData(); #endif - private void OnValidate() - { - // TODO: Check for naming conflicts and textures. - // TODO: Debug message box instead of debug logs. - } + private void OnValidate() + { + // TODO: Check for naming conflicts and textures. + // TODO: Debug message box instead of debug logs. + } - public void SetMaterials() - { - if (playData.materials != null) - { - foreach (Material mat in playData.materials) - { - if (mat != null) - { - if (mat.HasProperty("_MaxFrames")) - { - mat.SetFloat("_MaxFrames", playData.maxFrames); - } + public void SetMaterials() + { + if (playData.materials != null) + { + foreach (Material mat in playData.materials) + { + if (mat != null) + { + if (mat.HasProperty("_MaxFrames")) + { + mat.SetFloat("_MaxFrames", playData.maxFrames); + } - for (int i = 0; i < playData.texture2DArray.Count; i++) - { - if (mat.HasProperty(playData.textureGroups[i].shaderParamName)) - { - mat.SetTexture(playData.textureGroups[i].shaderParamName, playData.texture2DArray[i]); - } - } - } - } - } - } + for (int i = 0; i < playData.texture2DArray.Count; i++) + { + if (mat.HasProperty(playData.textureGroups[i].shaderParamName)) + { + mat.SetTexture(playData.textureGroups[i].shaderParamName, playData.texture2DArray[i]); + } + } + } + } + } + } - #region PlayData - [System.Serializable] - public class PlayData - { - public List textureGroups = new List(); - public List animationPages = new List(); + #region PlayData + [System.Serializable] + public class PlayData + { + public List textureGroups = new List(); + public List animationPages = new List(); - public int maxFrames; - public Material[] materials; - public List texture2DArray = new List(); + public int fps; + public int maxFrames; + public Material[] materials; + public List texture2DArray = new List(); - // NOTE: for some reason FixedString32 data gets lost when entering play mode. - // That is why this is here... and also the animationPages... - public List GetAnimations - { - get - { - List animations = new List(); - foreach (var ap in animationPages) - { - animations.Add(new VA_AnimationData - { - name = ap.name, - frames = ap.frames, - maxFrames = maxFrames, - frameTime = 1.0f / maxFrames, - duration = 1.0f / maxFrames * ap.frames, - animationMapIndex = GetFirstAnimationMapIndex(in ap.textures, in textureGroups), - colorMapIndex = GetFirstColorMapIndex(in ap.textures, in textureGroups) - }); - } - return animations; - } - } + // NOTE: for some reason FixedString32 data gets lost when entering play mode. + // That is why this is here... and also the animationPages... + public List GetAnimations + { + get + { + List animations = new List(); + foreach (var ap in animationPages) + { + animations.Add(new VA_AnimationData + { + name = ap.name, + frames = ap.frames, + maxFrames = maxFrames, + frameTime = 1.0f / maxFrames * fps, + // TODO: Frames -1 ????? + duration = 1.0f / maxFrames * (ap.frames - 1), + animationMapIndex = GetFirstAnimationMapIndex(in ap.textures, in textureGroups), + colorMapIndex = GetFirstColorMapIndex(in ap.textures, in textureGroups) + }); + } + return animations; + } + } - public static int GetFirstAnimationMapIndex(in List textures, in List textureGroups) - { - for (int i = 0; i < textureGroups.Count; i++) - { - if (textureGroups[i].textureType == TextureType.AnimationMap) - { - return textures[i].textureArrayIndex; - } - } + public static int GetFirstAnimationMapIndex(in List textures, in List textureGroups) + { + for (int i = 0; i < textureGroups.Count; i++) + { + if (textureGroups[i].textureType == TextureType.AnimationMap) + { + return textures[i].textureArrayIndex; + } + } - return -1; - } + return -1; + } - public static int GetFirstColorMapIndex(in List textures, in List textureGroups) - { - for (int i = 0; i < textureGroups.Count; i++) - { - if (textureGroups[i].textureType == TextureType.ColorMap) - { - return textures[i].textureArrayIndex; - } - } + public static int GetFirstColorMapIndex(in List textures, in List textureGroups) + { + for (int i = 0; i < textureGroups.Count; i++) + { + if (textureGroups[i].textureType == TextureType.ColorMap) + { + return textures[i].textureArrayIndex; + } + } - return -1; - } - } + return -1; + } + } - [System.Serializable] - public struct PlayAnimationPage - { - public string name; - public int frames; - public List textures; - } + [System.Serializable] + public struct PlayAnimationPage + { + public string name; + public int frames; + public List textures; + } - [System.Serializable] - public struct PlayTextureGroup - { - public string shaderParamName; - public TextureType textureType; - } + [System.Serializable] + public struct PlayTextureGroup + { + public string shaderParamName; + public TextureType textureType; + } - [System.Serializable] - public struct PlayTextureEntry - { - public int textureArrayIndex; - } - #endregion + [System.Serializable] + public struct PlayTextureEntry + { + public int textureArrayIndex; + } + #endregion - #region EditorData + #region EditorData #if UNITY_EDITOR - [System.Serializable] - public class EditorData - { - public List textureGroups = new List() { new EditorTextureGroup { shaderParamName = "_PositionMap", textureType = TextureType.AnimationMap, wrapMode = TextureWrapMode.Repeat, filterMode = FilterMode.Point, isLinear = false } }; - public List animationPages = new List(); + [System.Serializable] + public class EditorData + { + public List textureGroups = new List() { new EditorTextureGroup { shaderParamName = "_PositionMap", textureType = TextureType.AnimationMap, wrapMode = TextureWrapMode.Repeat, filterMode = FilterMode.Point, isLinear = false } }; + public List animationPages = new List(); - public int maxFrames; - public Material[] materials; - public List texture2DArray = null; - } + public int fps; + public int maxFrames; + public Material[] materials; + public List texture2DArray = null; + } - [System.Serializable] - public struct EditorAnimationPage - { - public string name; - public int frames; - public List textures; - } + [System.Serializable] + public struct EditorAnimationPage + { + public string name; + public int frames; + public List textures; + } - [System.Serializable] - public struct EditorTextureGroup - { - public string shaderParamName; - public TextureType textureType; - public TextureWrapMode wrapMode; - public FilterMode filterMode; - public bool isLinear; - } + [System.Serializable] + public struct EditorTextureGroup + { + public string shaderParamName; + public TextureType textureType; + public TextureWrapMode wrapMode; + public FilterMode filterMode; + public bool isLinear; + } - [System.Serializable] - public class EditorTextureEntry - { - public Texture2D texture2D = null; - public int textureArrayIndex = -1; - } + [System.Serializable] + public class EditorTextureEntry + { + public Texture2D texture2D = null; + public int textureArrayIndex = -1; + } #endif - #endregion + #endregion - public enum TextureType - { - AnimationMap, - ColorMap - } - } + public enum TextureType + { + AnimationMap, + ColorMap + } + } } \ No newline at end of file diff --git a/Runtime/Scripts/VA_AnimationLibraryComponentAuthoring.cs b/Runtime/Scripts/VA_AnimationLibraryComponentAuthoring.cs index ac61329..494c06e 100644 --- a/Runtime/Scripts/VA_AnimationLibraryComponentAuthoring.cs +++ b/Runtime/Scripts/VA_AnimationLibraryComponentAuthoring.cs @@ -30,7 +30,7 @@ namespace TAO.VertexAnimation // Set all the data. BlobBuilderArray animationDataArray = blobBuilder.Allocate(ref animationDataBlobAsset.animations, animationLib.animationLibrary.animations.Count); - for (int i = 0; i < animationDataArray.Length; i++) + for (int i = 0; i < animationDataArray.Length; i++) { // Copy data. animationDataArray[i] = animationLib.animationLibrary.animations[i]; diff --git a/Runtime/Scripts/VA_AnimationLibraryData.cs b/Runtime/Scripts/VA_AnimationLibraryData.cs index c61f2f7..69d1601 100644 --- a/Runtime/Scripts/VA_AnimationLibraryData.cs +++ b/Runtime/Scripts/VA_AnimationLibraryData.cs @@ -12,7 +12,7 @@ namespace TAO.VertexAnimation public int frames; // The maximum of frames the texture holds. public int maxFrames; - // 1.0f / maxFrames. + // 1.0f / fps. public float frameTime; // FrameTime * frames. public float duration; @@ -27,27 +27,27 @@ namespace TAO.VertexAnimation public BlobArray animations; } - public static class VA_AnimationLibraryUtils + public static class VA_AnimationLibraryUtils { public const string AnimationLibraryAssetStoreName = "VA_AnimationLibrary"; - public static int GetAnimation(ref VA_AnimationLibraryData animationsRef, FixedString32 animationName) - { - for (int i = 0; i < animationsRef.animations.Length; i++) - { - if (animationsRef.animations[i].name == animationName) - { - return i; - } - } - - return -1; - } - - public static int GetAnimationMapIndex(ref VA_AnimationLibraryData animationsRef, int animation) + public static int GetAnimation(ref VA_AnimationLibraryData animationsRef, FixedString32 animationName) { - return animationsRef.animations[animation].animationMapIndex; - } + for (int i = 0; i < animationsRef.animations.Length; i++) + { + if (animationsRef.animations[i].name == animationName) + { + return i; + } + } + + return -1; + } + + public static int GetAnimationMapIndex(ref VA_AnimationLibraryData animationsRef, int animation) + { + return animationsRef.animations[animation].animationMapIndex; + } public static int GetColorMapIndex(ref VA_AnimationLibraryData animationsRef, int animation) { diff --git a/Runtime/Scripts/VA_AnimatorComponentAuthoring.cs b/Runtime/Scripts/VA_AnimatorComponentAuthoring.cs index 24ce3e9..c28704e 100644 --- a/Runtime/Scripts/VA_AnimatorComponentAuthoring.cs +++ b/Runtime/Scripts/VA_AnimatorComponentAuthoring.cs @@ -51,9 +51,9 @@ namespace TAO.VertexAnimation Entity ent = GetPrimaryEntity(children[i]); VA_AnimationDataComponent animationData = new VA_AnimationDataComponent(); - DstEntityManager.AddComponentData(ent, animationData); - } - }); + DstEntityManager.AddComponentData(ent, animationData); + } + }); } } } diff --git a/Runtime/Scripts/VA_Texture2DArrayUtils.cs b/Runtime/Scripts/VA_Texture2DArrayUtils.cs index abcd5dc..766ae01 100644 --- a/Runtime/Scripts/VA_Texture2DArrayUtils.cs +++ b/Runtime/Scripts/VA_Texture2DArrayUtils.cs @@ -2,104 +2,104 @@ namespace TAO.VertexAnimation { - public static class VA_Texture2DArrayUtils - { - public static Texture2DArray CreateTextureArray(Texture2D[] a_textures, bool a_useMipChain, bool a_isLinear, - TextureWrapMode a_wrapMode = TextureWrapMode.Repeat, FilterMode a_filterMode = FilterMode.Bilinear, int a_anisoLevel = 1, string a_name = "") - { - if(!IsValidForTextureArray(a_textures) || !IsValidCopyTexturePlatform()) - { - return null; - } + public static class VA_Texture2DArrayUtils + { + public static Texture2DArray CreateTextureArray(Texture2D[] a_textures, bool a_useMipChain, bool a_isLinear, + TextureWrapMode a_wrapMode = TextureWrapMode.Repeat, FilterMode a_filterMode = FilterMode.Bilinear, int a_anisoLevel = 1, string a_name = "") + { + if(!IsValidForTextureArray(a_textures) || !IsValidCopyTexturePlatform()) + { + return null; + } - Texture2DArray textureArray = new Texture2DArray(a_textures[0].width, a_textures[0].height, a_textures.Length, a_textures[0].format, a_useMipChain, a_isLinear); + Texture2DArray textureArray = new Texture2DArray(a_textures[0].width, a_textures[0].height, a_textures.Length, a_textures[0].format, a_useMipChain, a_isLinear); - if (IsValidCopyTexturePlatform()) - { - for (int i = 0; i < a_textures.Length; i++) - { - Graphics.CopyTexture(a_textures[i], 0, 0, textureArray, i, 0); - } - } + if (IsValidCopyTexturePlatform()) + { + for (int i = 0; i < a_textures.Length; i++) + { + Graphics.CopyTexture(a_textures[i], 0, 0, textureArray, i, 0); + } + } - textureArray.wrapMode = a_wrapMode; - textureArray.filterMode = a_filterMode; - textureArray.anisoLevel = a_anisoLevel; - textureArray.name = a_name; + textureArray.wrapMode = a_wrapMode; + textureArray.filterMode = a_filterMode; + textureArray.anisoLevel = a_anisoLevel; + textureArray.name = a_name; - textureArray.Apply(false, false); + textureArray.Apply(false, false); - return textureArray; - } + return textureArray; + } - public static bool IsValidForTextureArray(Texture2D[] a_textures) - { - if (a_textures == null || a_textures.Length <= 0) - { - Debug.LogError("No textures assigned!"); - return false; - } + public static bool IsValidForTextureArray(Texture2D[] a_textures) + { + if (a_textures == null || a_textures.Length <= 0) + { + Debug.LogError("No textures assigned!"); + return false; + } - for (int i = 0; i < a_textures.Length; i++) - { - if (a_textures[i] == null) - { - Debug.LogError("Texture " + i.ToString() + " not assigned!"); - return false; - } + for (int i = 0; i < a_textures.Length; i++) + { + if (a_textures[i] == null) + { + Debug.LogError("Texture " + i.ToString() + " not assigned!"); + return false; + } - if (a_textures[0].width != a_textures[i].width || a_textures[0].height != a_textures[i].height) - { - Debug.LogError("Texture " + a_textures[i].name + " has a different size!"); - return false; - } + if (a_textures[0].width != a_textures[i].width || a_textures[0].height != a_textures[i].height) + { + Debug.LogError("Texture " + a_textures[i].name + " has a different size!"); + return false; + } - if (a_textures[0].format != a_textures[i].format || a_textures[0].graphicsFormat != a_textures[i].graphicsFormat) - { - Debug.LogError("Texture " + a_textures[i].name + " has a different format/graphics format!"); - return false; - } + if (a_textures[0].format != a_textures[i].format || a_textures[0].graphicsFormat != a_textures[i].graphicsFormat) + { + Debug.LogError("Texture " + a_textures[i].name + " has a different format/graphics format!"); + return false; + } - if (!a_textures[0].isReadable) - { + if (!a_textures[0].isReadable) + { #if UNITY_EDITOR - //Debug.LogWarning("Texture " + a_textures[i].name + " is not readable!"); - return true; + //Debug.LogWarning("Texture " + a_textures[i].name + " is not readable!"); + return true; #else - Debug.LogError("Texture " + a_textures[i].name + " is not readable!"); - return false; + Debug.LogError("Texture " + a_textures[i].name + " is not readable!"); + return false; #endif - } - } + } + } - return true; - } + return true; + } - public static bool IsValidCopyTexturePlatform() - { - switch (SystemInfo.copyTextureSupport) - { - case UnityEngine.Rendering.CopyTextureSupport.None: - Debug.LogError("No CopyTextureSupport on this platform!"); - return false; - case UnityEngine.Rendering.CopyTextureSupport.Basic: - return true; - case UnityEngine.Rendering.CopyTextureSupport.Copy3D: - return true; - case UnityEngine.Rendering.CopyTextureSupport.DifferentTypes: - return true; - case UnityEngine.Rendering.CopyTextureSupport.TextureToRT: - return true; - case UnityEngine.Rendering.CopyTextureSupport.RTToTexture: - return true; - default: + public static bool IsValidCopyTexturePlatform() + { + switch (SystemInfo.copyTextureSupport) + { + case UnityEngine.Rendering.CopyTextureSupport.None: + Debug.LogError("No CopyTextureSupport on this platform!"); + return false; + case UnityEngine.Rendering.CopyTextureSupport.Basic: + return true; + case UnityEngine.Rendering.CopyTextureSupport.Copy3D: + return true; + case UnityEngine.Rendering.CopyTextureSupport.DifferentTypes: + return true; + case UnityEngine.Rendering.CopyTextureSupport.TextureToRT: + return true; + case UnityEngine.Rendering.CopyTextureSupport.RTToTexture: + return true; + default: #if UNITY_EDITOR - return true; + return true; #else - Debug.LogError("No CopyTextureSupport on this platform!"); - return false; + Debug.LogError("No CopyTextureSupport on this platform!"); + return false; #endif - } - } - } + } + } + } } \ No newline at end of file