2021-01-14 00:45:25 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using UnityEngine;
|
|
|
|
using UnityEditor;
|
2022-12-04 04:18:35 +01:00
|
|
|
using UnityEngine.Experimental.Rendering;
|
2021-01-14 00:45:25 +01:00
|
|
|
|
|
|
|
namespace TAO.VertexAnimation.Editor
|
|
|
|
{
|
2021-01-18 13:42:45 +01:00
|
|
|
[CreateAssetMenu(fileName = "new ModelBaker", menuName = "TAO/VertexAnimation/ModelBaker", order = 400)]
|
2021-01-14 00:45:25 +01:00
|
|
|
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;
|
2021-01-21 10:43:33 +01:00
|
|
|
public bool applyRootMotion = false;
|
|
|
|
public bool includeInactive = false;
|
2021-01-18 13:01:47 +01:00
|
|
|
|
|
|
|
public LODSettings lodSettings = new LODSettings();
|
2021-02-18 18:29:40 +01:00
|
|
|
public bool applyAnimationBounds = true;
|
2021-01-14 00:45:25 +01:00
|
|
|
public bool generateAnimationBook = true;
|
|
|
|
public bool generatePrefab = true;
|
|
|
|
public Shader materialShader = null;
|
2021-02-09 17:21:42 +01:00
|
|
|
public bool useInterpolation = true;
|
|
|
|
public bool useNormalA = true;
|
2021-01-14 00:45:25 +01:00
|
|
|
|
|
|
|
// Output.
|
|
|
|
public GameObject prefab = null;
|
2021-01-18 13:42:45 +01:00
|
|
|
public Texture2DArray positionMap = null;
|
2021-01-14 00:45:25 +01:00
|
|
|
public Material material = null;
|
|
|
|
public Mesh[] meshes = null;
|
|
|
|
public VA_AnimationBook book = null;
|
2021-01-19 01:18:25 +01:00
|
|
|
public List<VA_Animation> animations = new List<VA_Animation>();
|
2021-01-14 00:45:25 +01:00
|
|
|
|
2021-01-18 13:01:47 +01:00
|
|
|
[System.Serializable]
|
|
|
|
public class LODSettings
|
|
|
|
{
|
|
|
|
public LODSetting[] lodSettings = new LODSetting[3] { new LODSetting(1, .4f), new LODSetting(.6f, .15f), new LODSetting(.3f, .01f) };
|
|
|
|
|
|
|
|
public float[] GetQualitySettings()
|
|
|
|
{
|
|
|
|
float[] q = new float[lodSettings.Length];
|
|
|
|
|
|
|
|
for (int i = 0; i < lodSettings.Length; i++)
|
|
|
|
{
|
|
|
|
q[i] = lodSettings[i].quality;
|
|
|
|
}
|
|
|
|
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float[] GetTransitionSettings()
|
|
|
|
{
|
|
|
|
float[] t = new float[lodSettings.Length];
|
|
|
|
|
|
|
|
for (int i = 0; i < lodSettings.Length; i++)
|
|
|
|
{
|
|
|
|
t[i] = lodSettings[i].screenRelativeTransitionHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int LODCount()
|
|
|
|
{
|
|
|
|
return lodSettings.Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
public struct LODSetting
|
|
|
|
{
|
|
|
|
[Range(1.0f, 0.0f)]
|
|
|
|
public float quality;
|
|
|
|
[Range(1.0f, 0.0f)]
|
|
|
|
public float screenRelativeTransitionHeight;
|
|
|
|
|
|
|
|
public LODSetting(float q, float t)
|
|
|
|
{
|
|
|
|
quality = q;
|
|
|
|
screenRelativeTransitionHeight = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-19 16:35:37 +01:00
|
|
|
private void OnValidate()
|
|
|
|
{
|
|
|
|
if (materialShader == null)
|
|
|
|
{
|
2021-01-21 13:59:55 +01:00
|
|
|
materialShader = Shader.Find("TAO/Lit");
|
2021-01-19 16:35:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-14 00:45:25 +01:00
|
|
|
public void Bake()
|
|
|
|
{
|
|
|
|
var target = Instantiate(model);
|
|
|
|
target.name = model.name;
|
|
|
|
|
2021-01-21 10:43:33 +01:00
|
|
|
target.ConbineAndConvertGameObject(includeInactive);
|
2021-01-21 10:13:29 +01:00
|
|
|
AnimationBaker.BakedData bakedData = target.Bake(animationClips, applyRootMotion, fps, textureWidth);
|
2021-01-14 00:45:25 +01:00
|
|
|
|
2021-01-18 14:12:43 +01:00
|
|
|
positionMap = VA_Texture2DArrayUtils.CreateTextureArray(bakedData.positionMaps.ToArray(), false, true, TextureWrapMode.Repeat, FilterMode.Point, 1, string.Format("{0}_PositionMap", name), true);
|
2021-01-18 22:59:57 +01:00
|
|
|
meshes = bakedData.mesh.GenerateLOD(lodSettings.LODCount(), lodSettings.GetQualitySettings());
|
2021-01-14 00:45:25 +01:00
|
|
|
|
|
|
|
DestroyImmediate(target);
|
2021-01-19 13:59:31 +01:00
|
|
|
|
|
|
|
SaveAssets(bakedData);
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
private void SaveAssets(AnimationBaker.BakedData bakedData)
|
2021-01-14 00:45:25 +01:00
|
|
|
{
|
|
|
|
AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material });
|
|
|
|
|
2021-02-18 03:19:07 +01:00
|
|
|
Bounds bounds = new Bounds
|
2021-01-17 04:27:57 +01:00
|
|
|
{
|
2021-02-18 03:19:07 +01:00
|
|
|
max = bakedData.maxBounds,
|
|
|
|
min = bakedData.minBounds
|
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < meshes.Length; i++)
|
|
|
|
{
|
2021-02-18 18:29:40 +01:00
|
|
|
if (applyAnimationBounds)
|
|
|
|
{
|
|
|
|
meshes[i].bounds = bounds;
|
|
|
|
}
|
|
|
|
|
2021-02-18 03:19:07 +01:00
|
|
|
meshes[i].Finalize();
|
|
|
|
AssetDatabase.AddObjectToAsset(meshes[i], this);
|
2021-01-17 04:27:57 +01:00
|
|
|
}
|
2021-01-14 00:45:25 +01:00
|
|
|
|
2021-01-18 13:42:45 +01:00
|
|
|
AssetDatabase.AddObjectToAsset(positionMap, this);
|
2021-01-14 00:45:25 +01:00
|
|
|
AssetDatabase.SaveAssets();
|
|
|
|
|
|
|
|
if (generatePrefab)
|
|
|
|
{
|
2021-01-19 13:59:31 +01:00
|
|
|
GeneratePrefab(bakedData);
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (generateAnimationBook)
|
|
|
|
{
|
2021-01-19 13:59:31 +01:00
|
|
|
GenerateBook(bakedData);
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
AssetDatabase.SaveAssets();
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
}
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
private void GeneratePrefab(AnimationBaker.BakedData bakedData)
|
2021-01-14 00:45:25 +01:00
|
|
|
{
|
|
|
|
string path = AssetDatabase.GetAssetPath(this);
|
|
|
|
int start = path.LastIndexOf('/');
|
|
|
|
path = path.Remove(start, path.Length - start);
|
|
|
|
path += "/" + name + ".prefab";
|
|
|
|
|
2021-02-17 00:49:03 +01:00
|
|
|
// Get info.
|
|
|
|
NamingConventionUtils.PositionMapInfo info = bakedData.GetPositionMap.name.GetTextureInfo();
|
|
|
|
|
2022-12-04 15:47:07 +01:00
|
|
|
//bakedData.mesh.SetTriangles( bakedData.mesh.triangles, 0 );
|
|
|
|
//meshes = new[] { bakedData.mesh };
|
2022-12-04 04:18:35 +01:00
|
|
|
|
2021-01-14 00:45:25 +01:00
|
|
|
// Generate Material
|
|
|
|
if (!AssetDatabaseUtils.HasChildAsset(this, material))
|
|
|
|
{
|
2021-02-17 00:49:03 +01:00
|
|
|
material = AnimationMaterial.Create(name, materialShader, positionMap, useNormalA, useInterpolation, info.maxFrames);
|
2021-01-14 00:45:25 +01:00
|
|
|
AssetDatabase.AddObjectToAsset(material, this);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-17 00:49:03 +01:00
|
|
|
material.Update(name, materialShader, positionMap, useNormalA, useInterpolation, info.maxFrames);
|
2021-02-09 17:21:42 +01:00
|
|
|
}
|
|
|
|
|
2021-01-14 00:45:25 +01:00
|
|
|
// Generate Prefab
|
2021-01-18 13:01:47 +01:00
|
|
|
prefab = AnimationPrefab.Create(path, name, meshes, material, lodSettings.GetTransitionSettings());
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
private void GenerateBook(AnimationBaker.BakedData bakedData)
|
2021-01-14 00:45:25 +01:00
|
|
|
{
|
2021-01-19 13:59:31 +01:00
|
|
|
// Create book.
|
2021-01-14 00:45:25 +01:00
|
|
|
if (!book)
|
|
|
|
{
|
|
|
|
book = CreateInstance<VA_AnimationBook>();
|
|
|
|
}
|
|
|
|
|
2021-01-19 01:18:25 +01:00
|
|
|
book.name = string.Format("{0}_Book", name);
|
|
|
|
book.positionMap = positionMap;
|
2021-01-19 13:59:31 +01:00
|
|
|
book.animations = new List<VA_Animation>();
|
2021-01-19 01:18:25 +01:00
|
|
|
book.TryAddMaterial(material);
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
// Save book.
|
2021-01-19 01:18:25 +01:00
|
|
|
if (!AssetDatabaseUtils.HasChildAsset(this, book))
|
2021-01-14 00:45:25 +01:00
|
|
|
{
|
2021-01-19 01:18:25 +01:00
|
|
|
AssetDatabase.AddObjectToAsset(book, this);
|
|
|
|
}
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
// Get animation info.
|
|
|
|
List<NamingConventionUtils.PositionMapInfo> info = new List<NamingConventionUtils.PositionMapInfo>();
|
2021-01-19 01:18:25 +01:00
|
|
|
foreach (var t in bakedData.positionMaps)
|
2021-01-14 00:45:25 +01:00
|
|
|
{
|
2021-01-19 01:18:25 +01:00
|
|
|
info.Add(t.name.GetTextureInfo());
|
|
|
|
}
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
// Create animations.
|
2021-01-19 01:18:25 +01:00
|
|
|
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);
|
2021-01-19 13:59:31 +01:00
|
|
|
|
|
|
|
// Either update existing animation or create a new one.
|
2021-01-19 01:18:25 +01:00
|
|
|
if (TryGetAnimationWithName(animationName, out VA_Animation animation))
|
|
|
|
{
|
|
|
|
animation.SetData(newData);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
animation = CreateInstance<VA_Animation>();
|
|
|
|
animation.name = animationName;
|
|
|
|
animation.SetData(newData);
|
|
|
|
animations.Add(animation);
|
|
|
|
}
|
|
|
|
|
|
|
|
book.TryAddAnimation(animation);
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
|
|
|
|
2021-01-19 13:59:31 +01:00
|
|
|
// Save animation objects.
|
|
|
|
foreach (var a in animations)
|
|
|
|
{
|
|
|
|
AssetDatabaseUtils.TryAddChildAsset(book, a);
|
|
|
|
}
|
2021-01-19 01:18:25 +01:00
|
|
|
}
|
2021-01-14 00:45:25 +01:00
|
|
|
|
2021-01-19 01:18:25 +01:00
|
|
|
private bool TryGetAnimationWithName(string name, out VA_Animation animation)
|
|
|
|
{
|
|
|
|
foreach (var a in animations)
|
2021-01-14 00:45:25 +01:00
|
|
|
{
|
2021-01-19 13:59:31 +01:00
|
|
|
if (a != null)
|
2021-01-19 01:18:25 +01:00
|
|
|
{
|
2021-01-19 13:59:31 +01:00
|
|
|
if (a.name == name)
|
|
|
|
{
|
|
|
|
animation = a;
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-19 01:18:25 +01:00
|
|
|
}
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
2021-01-19 01:18:25 +01:00
|
|
|
|
|
|
|
animation = null;
|
|
|
|
return false;
|
2021-01-14 00:45:25 +01:00
|
|
|
}
|
2021-01-19 13:59:31 +01:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2021-01-14 00:45:25 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|