Model Baker

Model Baker ScriptableObject, bakes models and outputs the data. Can also generate prefab and animation books for quick setup.
Updated GUI.
This commit is contained in:
max 2021-01-11 20:59:40 +01:00
parent abd6cc9e9e
commit cab2c4ad12
11 changed files with 271 additions and 129 deletions

View File

@ -0,0 +1,20 @@
using UnityEditor;
using UnityEngine;
namespace TAO.VertexAnimation.Editor
{
public static class EditorGUILayoutUtils
{
public static readonly Color horizontalLineColor = Color.white;
public static void HorizontalLine(Color color)
{
Color prev = GUI.color;
GUI.color = color;
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
GUI.color = prev;
}
public static void HorizontalLine() => HorizontalLine(horizontalLineColor);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a78d6eea6c7f534b8361125e43eacc9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,109 +0,0 @@
using UnityEngine;
using UnityEditor;
namespace TAO.VertexAnimation.Editor
{
[CustomEditor(typeof(VA_ModelBaker))]
public class VA_ModelBakerEditor : UnityEditor.Editor
{
private VA_ModelBaker modelBaker = null;
void OnEnable()
{
modelBaker = target as VA_ModelBaker;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
InputGUI();
BakeGUI();
OutputGUI();
serializedObject.ApplyModifiedProperties();
}
private void InputGUI()
{
//public GameObject model;
//public AnimationClip[] animationClips;
//public int fps = 24;
//public int textureWidth = 512;
//public bool saveBakedDataToAsset = true;
//public bool generateAnimationBook = false;
EditorGUILayout.PropertyField(serializedObject.FindProperty("model"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("animationClips"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("fps"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("textureWidth"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("saveBakedDataToAsset"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("generateAnimationBook"));
}
private void BakeGUI()
{
if (GUILayout.Button("Bake"))
{
ClearBakedData();
modelBaker.Bake();
if (modelBaker.saveBakedDataToAsset)
{
SaveBakedData();
}
}
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("SaveBakedData", EditorStyles.miniButtonLeft))
{
SaveBakedData();
}
if (GUILayout.Button("ClearBakedData", EditorStyles.miniButtonRight))
{
ClearBakedData();
}
}
}
private void OutputGUI()
{
using (new EditorGUI.DisabledGroupScope(true))
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData"));
}
}
private void SaveBakedData()
{
AssetDatabase.AddObjectToAsset(modelBaker.BakedData.mesh, modelBaker);
foreach (var pm in modelBaker.BakedData.positionMaps)
{
AssetDatabase.AddObjectToAsset(pm, modelBaker);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private void ClearBakedData()
{
var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(modelBaker));
foreach (var a in assets)
{
if (a != modelBaker)
{
AssetDatabase.RemoveObjectFromAsset(a);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}

View File

@ -10,10 +10,6 @@ namespace TAO.VertexAnimation.Editor
private Vector2 textureGroupScollPos;
private Vector2 animationPagesScollPos;
//private UnityEditor.Editor previewEditor = null;
//private int previewIndex = 0;
//private int curviewIndex = 0;
void OnEnable()
{
animationBook = target as VA_AnimationBook;
@ -25,11 +21,16 @@ namespace TAO.VertexAnimation.Editor
// Texture Groups.
GeneralGUI();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
TextureGroupsGUI();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
SyncListSize();
AnimationPagesGUI();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
MaterialGUI();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
AssetBuilderGUI();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
Texture2DGUI();
serializedObject.ApplyModifiedProperties();

View File

@ -0,0 +1,216 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
namespace TAO.VertexAnimation.Editor
{
[CustomEditor(typeof(VA_ModelBaker))]
public class VA_ModelBakerEditor : UnityEditor.Editor
{
private VA_ModelBaker modelBaker = null;
void OnEnable()
{
modelBaker = target as VA_ModelBaker;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
InputGUI();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
BakeGUI();
serializedObject.ApplyModifiedProperties();
EditorGUILayoutUtils.HorizontalLine(color: Color.gray);
OutputGUI();
}
private void InputGUI()
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("model"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("animationClips"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("fps"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("textureWidth"));
}
private void BakeGUI()
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("saveBakedDataToAsset"));
int il = EditorGUI.indentLevel;
if (modelBaker.saveBakedDataToAsset)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(serializedObject.FindProperty("generateAnimationBook"));
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("generatePrefab"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("materialShader"), new GUIContent(""));
}
}
EditorGUI.indentLevel = il;
if (GUILayout.Button("Bake", GUILayout.Height(32)))
{
ClearBakedData();
modelBaker.Bake();
if (modelBaker.saveBakedDataToAsset)
{
SaveBakedData();
}
}
if (modelBaker.BakedData.mesh != null)
{
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Save", EditorStyles.miniButtonLeft))
{
SaveBakedData();
}
if (GUILayout.Button("Clear", EditorStyles.miniButtonRight))
{
ClearBakedData();
}
}
if (modelBaker.prefab && GUILayout.Button("Remove Prefab"))
{
DeletePrefab();
}
}
}
private void OutputGUI()
{
using (new EditorGUI.DisabledGroupScope(true))
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("bakedData"));
}
}
private void SaveBakedData()
{
ClearBakedData();
AssetDatabase.AddObjectToAsset(modelBaker.BakedData.mesh, modelBaker);
foreach (var pm in modelBaker.BakedData.positionMaps)
{
AssetDatabase.AddObjectToAsset(pm, modelBaker);
}
AssetDatabase.SaveAssets();
if (modelBaker.generatePrefab)
{
GeneratePrefab();
}
if(modelBaker.generateAnimationBook)
{
GenerateBook();
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private void ClearBakedData()
{
var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(modelBaker));
foreach (var a in assets)
{
if (a != modelBaker)
{
AssetDatabase.RemoveObjectFromAsset(a);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private void DeletePrefab()
{
string path = AssetDatabase.GetAssetPath(modelBaker.prefab);
AssetDatabase.DeleteAsset(path);
AssetDatabase.Refresh();
}
private void GeneratePrefab()
{
string path = AssetDatabase.GetAssetPath(modelBaker);
int start = path.LastIndexOf('/');
path = path.Remove(start, path.Length - start);
path += "/" + modelBaker.name + ".prefab";
// Generate Material
modelBaker.material = new Material(modelBaker.materialShader);
modelBaker.material.name = modelBaker.name;
AssetDatabase.AddObjectToAsset(modelBaker.material, modelBaker);
// Generate Object.
if (!modelBaker.prefab)
{
GameObject go = new GameObject(modelBaker.model.name, typeof(MeshFilter), typeof(MeshRenderer));
modelBaker.prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(go, path, InteractionMode.AutomatedAction);
DestroyImmediate(go);
}
GameObject inst = PrefabUtility.InstantiatePrefab(modelBaker.prefab) as GameObject;
inst.GetComponent<MeshFilter>().sharedMesh = modelBaker.BakedData.mesh;
inst.GetComponent<MeshRenderer>().sharedMaterial = modelBaker.material;
// Save.
PrefabUtility.ApplyPrefabInstance(inst, InteractionMode.UserAction);
AssetDatabase.SaveAssets();
DestroyImmediate(inst);
}
private void GenerateBook()
{
if (!modelBaker.book)
{
modelBaker.book = CreateInstance<VA_AnimationBook>();
}
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<VA_AnimationBook.EditorTextureEntry>()
{
new VA_AnimationBook.EditorTextureEntry
{
texture2D = tex
}
}
});
}
VA_AssetBuilder.AutoFill(ref modelBaker.book);
AssetDatabase.AddObjectToAsset(modelBaker.book, modelBaker);
AssetDatabase.SaveAssets();
}
}
}

View File

@ -293,6 +293,13 @@ namespace TAO.VertexAnimation.Editor
ap.frames = frames;
}
}
else if (p.StartsWith("MF-"))
{
if (int.TryParse(p.Remove(0, 3), out int maxFrames))
{
book.editorData.maxFrames = maxFrames;
}
}
}
}
book.editorData.animationPages[i] = ap;

View File

@ -1,16 +1,4 @@
// References:
// https://forum.unity.com/threads/help-combining-and-manipulating-skinned-mesh-renderers-imported-from-blender.505078/
// http://wiki.unity3d.com/index.php/CombineSkinnedMeshes
// http://wiki.unity3d.com/index.php/SkinnedMeshCombiner
// TODO:
// ---Bake ALL the MeshRenderers/SkinnedMeshRenderers and merge them together.---
// ---Bake multiple animations.---
// ---Get the longest animation to calculate the texture height, so all the textures have the same height for the 3D texture.---
// Add options and previews for texture size, animation phasing/fps.
// Either merge with the animation books or generate them from this and maybe store them as child (and then don't destroy them on re-bake to keep the reference but replace it).
using UnityEngine;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;

View File

@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TAO.VertexAnimation
@ -9,10 +7,20 @@ namespace TAO.VertexAnimation
{
public GameObject model;
public AnimationClip[] animationClips;
[Range(1, 60)]
public int fps = 24;
public int textureWidth = 512;
#if UNITY_EDITOR
public bool saveBakedDataToAsset = true;
public bool generateAnimationBook = false;
public bool generateAnimationBook = true;
public bool generatePrefab = true;
public Shader materialShader = null;
public GameObject prefab = null;
public Material material = null;
public VA_AnimationBook book = null;
#endif
[SerializeField]
private AnimationBaker.BakedData bakedData;