AnimationLibrary

AnimationLibraryBook editor setup.
AnimationLibrary AnimationData generation and material setup.
AnimationBook added support for non animation textures as well. This allows the user for example, to link Albedo maps with animations.
MaterialData is now in one component.
Note: Only 1/3th of the performance when having 4 swapping texture maps/arrays.
This commit is contained in:
max 2020-12-14 20:27:44 +01:00
parent e4ca15301b
commit ea1d2412b1
9 changed files with 247 additions and 182 deletions

View File

@ -1,10 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using UnityEditor;
using System.Runtime.CompilerServices;
using UnityEngine.Rendering.VirtualTexturing;
using System;
namespace TAO.VertexAnimation.Editor
{
@ -12,11 +7,12 @@ namespace TAO.VertexAnimation.Editor
public class VA_AnimationBookEditor : UnityEditor.Editor
{
private VA_AnimationBook animationBook = null;
private Vector2 textireGroupScollPos;
private Vector2 textureGroupScollPos;
private Vector2 animationPagesScollPos;
private UnityEditor.Editor previewEditor = null;
private int previewIndex = 0;
private int curviewIndex = 0;
void OnEnable()
{
@ -77,21 +73,26 @@ namespace TAO.VertexAnimation.Editor
SerializedProperty textureGroups = serializedObject.FindProperty("textureGroups");
int removeWidth = 16;
int nameWidth = 152;
int optionWidth = 110;
int linearWidth = 50;
using (new EditorGUILayout.VerticalScope())
{
EditorGUILayout.LabelField("TextureGroups", EditorStyles.centeredGreyMiniLabel);
textireGroupScollPos = EditorGUILayout.BeginScrollView(textireGroupScollPos, false, false);
textureGroupScollPos = EditorGUILayout.BeginScrollView(textureGroupScollPos, false, false);
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
{
EditorGUILayout.LabelField("", GUILayout.Width(removeWidth));
EditorGUILayout.LabelField("material parameter name", GUILayout.Width(nameWidth));
EditorGUILayout.LabelField("texture type", GUILayout.Width(optionWidth));
EditorGUILayout.LabelField("wrap mode", GUILayout.Width(optionWidth));
EditorGUILayout.LabelField("filter mode", GUILayout.Width(optionWidth));
EditorGUILayout.LabelField("is linear", GUILayout.MinWidth(linearWidth));
}
EditorGUILayout.EndScrollView();
textureGroupScollPos = EditorGUILayout.BeginScrollView(textureGroupScollPos, false, false);
for (int i = 0; i < textureGroups.arraySize; i++)
{
using (new EditorGUILayout.HorizontalScope())
@ -103,9 +104,13 @@ namespace TAO.VertexAnimation.Editor
}
EditorGUILayout.PropertyField(textureGroups.GetArrayElementAtIndex(i).FindPropertyRelative("shaderParamName"), GUIContent.none, GUILayout.Width(nameWidth));
EditorGUILayout.PropertyField(textureGroups.GetArrayElementAtIndex(i).FindPropertyRelative("textureType"), GUIContent.none, GUILayout.Width(optionWidth));
EditorGUILayout.PropertyField(textureGroups.GetArrayElementAtIndex(i).FindPropertyRelative("wrapMode"), GUIContent.none, GUILayout.Width(optionWidth));
EditorGUILayout.PropertyField(textureGroups.GetArrayElementAtIndex(i).FindPropertyRelative("filterMode"), GUIContent.none, GUILayout.Width(optionWidth));
EditorGUILayout.PropertyField(textureGroups.GetArrayElementAtIndex(i).FindPropertyRelative("isLinear"), GUIContent.none, GUILayout.MinWidth(linearWidth));
}
}
EditorGUILayout.EndScrollView();
if (GUILayout.Button("+", EditorStyles.miniButton))
{
@ -161,7 +166,7 @@ namespace TAO.VertexAnimation.Editor
SerializedProperty textures = animationPages.GetArrayElementAtIndex(i).FindPropertyRelative("textures");
for (int t = 0; t < textures.arraySize; t++)
{
EditorGUILayout.PropertyField(textures.GetArrayElementAtIndex(t), GUIContent.none, GUILayout.MinWidth(textureWidth));
EditorGUILayout.PropertyField(textures.GetArrayElementAtIndex(t).FindPropertyRelative("texture2D"), GUIContent.none, GUILayout.MinWidth(textureWidth));
}
}
}
@ -192,7 +197,16 @@ namespace TAO.VertexAnimation.Editor
SerializedProperty texture2DArray = serializedObject.FindProperty("texture2DArray");
EditorGUILayout.LabelField("Texture2DArray", EditorStyles.centeredGreyMiniLabel);
previewIndex = EditorGUILayout.IntSlider(previewIndex, 0, texture2DArray.arraySize - 1);
using (new EditorGUI.DisabledScope(true))
{
for (int t = 0; t < texture2DArray.arraySize; t++)
{
EditorGUILayout.PropertyField(texture2DArray.GetArrayElementAtIndex(t), GUIContent.none);
}
}
previewIndex = EditorGUILayout.IntSlider("Preview" ,previewIndex, 0, texture2DArray.arraySize - 1);
}
}
}
@ -211,9 +225,10 @@ namespace TAO.VertexAnimation.Editor
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (previewEditor == null)
if (previewEditor == null || curviewIndex != previewIndex)
{
previewEditor = UnityEditor.Editor.CreateEditor(animationBook.texture2DArray[previewIndex]);
curviewIndex = previewIndex;
previewEditor = CreateEditor(animationBook.texture2DArray[previewIndex]);
}
previewEditor.OnInteractivePreviewGUI(r, background);

View File

@ -8,7 +8,7 @@ namespace TAO.VertexAnimation
public class VA_AnimationBook : ScriptableObject
{
public int maxFrames;
public List<TextureGroup> textureGroups = new List<TextureGroup>() { new TextureGroup { shaderParamName = "_PositionMap", isLinear = false } };
public List<TextureGroup> textureGroups = new List<TextureGroup>() { new TextureGroup { shaderParamName = "_PositionMap", textureType = TextureType.AnimationMap, wrapMode = TextureWrapMode.Repeat, filterMode = FilterMode.Point, isLinear = false } };
public List<VA_AnimationPage> animationPages = new List<VA_AnimationPage>();
public Material[] materials;
@ -16,56 +16,138 @@ namespace TAO.VertexAnimation
public void Create()
{
// Create textures.
texture2DArray.Clear();
foreach (var item in GetTextures())
GenerateTextures();
SetMaterials();
}
private void OnValidate()
{
// TODO: Check for naming conflicts and textures.
// TODO: Debug message box instead of debug logs.
}
private void ReferenceDuplicates()
{
for (int i = 0; i < textureGroups.Count; i++)
{
if(VA_Texture2DArrayUtils.IsValidForTextureArray(item.Value.ToArray()))
List<Texture2D> t = new List<Texture2D>();
for (int j = 0; j < animationPages.Count; j++)
{
texture2DArray.Add(VA_Texture2DArrayUtils.CreateTextureArray(item.Value.ToArray(), false, textureGroups[item.Key].isLinear, TextureWrapMode.Repeat, FilterMode.Point, 1, name + "-" + item.Key.ToString()));
// Check if exist.
if (!t.Contains(animationPages[j].textures[i].texture2D))
{
t.Add(animationPages[j].textures[i].texture2D);
}
// Add index reference.
animationPages[j].textures[i].textureArrayIndex = t.IndexOf(animationPages[j].textures[i].texture2D);
}
}
}
private void GenerateTextures()
{
ReferenceDuplicates();
texture2DArray.Clear();
for (int i = 0; i < textureGroups.Count; i++)
{
var t = GetTextures(i).ToArray();
if (VA_Texture2DArrayUtils.IsValidForTextureArray(t))
{
texture2DArray.Add(VA_Texture2DArrayUtils.CreateTextureArray(t, false, textureGroups[i].isLinear, textureGroups[i].wrapMode, textureGroups[i].filterMode, 1, name + textureGroups[i].shaderParamName));
}
}
}
private List<Texture2D> GetTextures(int textureIndex)
{
List<Texture2D> textures = new List<Texture2D>();
foreach (var ap in animationPages)
{
// Check if exist.
if (!textures.Contains(ap.textures[textureIndex].texture2D))
{
textures.Add(ap.textures[textureIndex].texture2D);
}
}
// Assign material parameters.
if(materials != null)
return textures;
}
private void SetMaterials()
{
if (materials != null)
{
foreach (Material mat in materials)
{
if(mat != null)
if (mat != null)
{
if (mat.HasProperty("_MaxFrames"))
{
mat.SetFloat("_MaxFrames", maxFrames);
}
for (int i = 0; i < texture2DArray.Count; i++)
{
mat.SetTexture(textureGroups[i].shaderParamName, texture2DArray[i]);
if (mat.HasProperty(textureGroups[i].shaderParamName))
{
mat.SetTexture(textureGroups[i].shaderParamName, texture2DArray[i]);
}
}
}
}
}
}
private void OnValidate()
public List<VA_AnimationData> GetAnimationData()
{
foreach (var item in GetTextures())
{
VA_Texture2DArrayUtils.IsValidForTextureArray(item.Value.ToArray());
List<VA_AnimationData> data = new List<VA_AnimationData>();
foreach (var ap in animationPages)
{
data.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),
colorMapIndex = GetFirstColorMapIndex(in ap.textures)
});
}
return data;
}
private Dictionary<int, List<Texture2D>> GetTextures()
private int GetFirstAnimationMapIndex(in List<TextureEntry> textures)
{
Dictionary<int, List<Texture2D>> dict = new Dictionary<int, List<Texture2D>>();
// Group and collect the textures.
for (int i = 0; i < textureGroups.Count; i++)
{
dict.Add(i, new List<Texture2D>());
for (int j = 0; j < animationPages.Count; j++)
if(textureGroups[i].textureType == TextureType.AnimationMap)
{
dict[i].Add(animationPages[j].textures[i]);
return textures[i].textureArrayIndex;
}
}
return dict;
return -1;
}
private int GetFirstColorMapIndex(in List<TextureEntry> textures)
{
for (int i = 0; i < textureGroups.Count; i++)
{
if (textureGroups[i].textureType == TextureType.ColorMap)
{
return textures[i].textureArrayIndex;
}
}
return -1;
}
}
@ -74,13 +156,29 @@ namespace TAO.VertexAnimation
{
public string name;
public int frames;
public List<Texture2D> textures;
public List<TextureEntry> textures;
}
[System.Serializable]
public struct TextureGroup
{
public string shaderParamName;
public TextureType textureType;
public TextureWrapMode wrapMode;
public FilterMode filterMode;
public bool isLinear;
}
[System.Serializable]
public class TextureEntry
{
public Texture2D texture2D = null;
public int textureArrayIndex = -1;
}
public enum TextureType
{
AnimationMap,
ColorMap
}
}

View File

@ -33,22 +33,9 @@ namespace TAO.VertexAnimation
if (animationBooks != null)
{
for (int b = 0; b < animationBooks.Length; b++)
foreach (var ab in animationBooks)
{
if(animationBooks[b].animationPages != null)
{
for (int p = 0; p < animationBooks[b].animationPages.Count; p++)
{
animations.Add(new VA_AnimationData
{
name = new Unity.Collections.FixedString32(animationBooks[b].animationPages[p].name),
maxFrames = animationBooks[b].maxFrames,
frames = animationBooks[b].animationPages[p].frames,
frameTime = 1.0f / animationBooks[b].maxFrames,
duration = 1.0f / animationBooks[b].maxFrames * animationBooks[b].animationPages[p].frames
});
}
}
animations.AddRange(ab.GetAnimationData());
}
}
}

View File

@ -6,13 +6,20 @@ namespace TAO.VertexAnimation
[System.Serializable]
public struct VA_AnimationData
{
// The name of the animation.
public FixedString32 name;
// The frames in this animation.
public int frames;
// The maximum of frames the texture holds.
public int maxFrames;
// 1.0f / maxFrames.
public float frameTime;
// frameTime * frames.
// FrameTime * frames.
public float duration;
// The index of the related animation texture.
public int animationMapIndex;
// The index of the related color textures if/when added.
public int colorMapIndex;
}
public struct VA_AnimationLibraryData
@ -22,8 +29,8 @@ namespace TAO.VertexAnimation
public static class VA_AnimationLibraryUtils
{
public static int GetAnimation(ref VA_AnimationLibraryData animationsRef, FixedString32 animationName)
{
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)
@ -32,7 +39,17 @@ namespace TAO.VertexAnimation
}
}
return -1;
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)
{
return animationsRef.animations[animation].colorMapIndex;
}
}
}

View File

@ -15,7 +15,8 @@ namespace TAO.VertexAnimation
public struct VA_AnimatorComponent : IComponentData
{
public int animationIndex;
public int animationIndexSchedule;
// TODO: Animation blending.
//public int animationIndexSchedule;
public float animationTime;
public BlobAssetReference<VA_AnimationLibraryData> animationLibrary;
}
@ -35,7 +36,7 @@ namespace TAO.VertexAnimation
VA_AnimatorComponent animatorComponent = new VA_AnimatorComponent
{
animationIndex = 0,
animationIndexSchedule = -1,
//animationIndexSchedule = -1,
animationTime = 0,
animationLibrary = animLib
};
@ -47,12 +48,10 @@ namespace TAO.VertexAnimation
{
Entity ent = GetPrimaryEntity(children[i]);
VA_AnimationIndexComponent animationIndex = new VA_AnimationIndexComponent { Value = 0 };
DstEntityManager.AddComponentData(ent, animationIndex);
VA_AnimationTimeComponent animationTime = new VA_AnimationTimeComponent { Value = 0 };
DstEntityManager.AddComponentData(ent, animationTime);
}
});
VA_AnimationDataComponent animationData = new VA_AnimationDataComponent();
DstEntityManager.AddComponentData(ent, animationData);
}
});
}
}
}

View File

@ -1,17 +1,15 @@
using Unity.Collections;
using Unity.Entities;
using Unity.Rendering;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
namespace TAO.VertexAnimation
{
// System to update all the animations.
public class VA_AnimatorSystem : SystemBase
{
protected override void OnUpdate()
{
var atc = GetComponentDataFromEntity<VA_AnimationTimeComponent>(false);
var aic = GetComponentDataFromEntity<VA_AnimationIndexComponent>(false);
var animationData = GetComponentDataFromEntity<VA_AnimationDataComponent>(false);
Entities.ForEach((ref VA_AnimatorComponent ac, in DynamicBuffer<Child> children) =>
{
@ -20,68 +18,23 @@ namespace TAO.VertexAnimation
// Get child.
Entity child = children[i].Value;
atc[child] = new VA_AnimationTimeComponent { Value = ac.animationTime };
// Get the animation lib data.
ref VA_AnimationLibraryData animationsRef = ref ac.animationLibrary.Value;
//// Get a copy of the time Component of the child.
//VA_AnimationTimeComponent atcCopy = atc[child];
//// Set new value.
//atcCopy.Value = ac.animationTime;
//// Update original.
//atc[child] = atcCopy;
aic[child] = new VA_AnimationIndexComponent { Value = ac.animationIndex };
//VA_AnimationIndexComponent aicCopy = aic[child];
//aicCopy.Value = ac.animationIndex;
//aic[child] = aicCopy;
animationData[child] = new VA_AnimationDataComponent
{
Value = new float4
{
x = ac.animationTime,
y = VA_AnimationLibraryUtils.GetAnimationMapIndex(ref animationsRef, ac.animationIndex),
z = VA_AnimationLibraryUtils.GetColorMapIndex(ref animationsRef, ac.animationIndex),
w = 0
}
};
}
})
.WithNativeDisableContainerSafetyRestriction(atc)
.WithNativeDisableContainerSafetyRestriction(aic)
.WithNativeDisableContainerSafetyRestriction(animationData)
.ScheduleParallel();
}
}
// Example systems to update animation parameters.
[UpdateBefore(typeof(VA_AnimatorSystem))]
public class VA_AnimationTimeSystem : SystemBase
{
protected override void OnUpdate()
{
float deltaTime = UnityEngine.Time.deltaTime;
Entities.ForEach((ref VA_AnimatorComponent ac) =>
{
// Get the animation lib data.
ref VA_AnimationLibraryData animationsRef = ref ac.animationLibrary.Value;
ac.animationTime += deltaTime;
if (ac.animationTime > animationsRef.animations[ac.animationIndex].duration)
{
ac.animationTime = ac.animationTime - animationsRef.animations[ac.animationIndex].duration;
}
}).ScheduleParallel();
}
}
[UpdateBefore(typeof(VA_AnimatorSystem))]
public class VA_AnimationIndexSystem : SystemBase
{
protected override void OnUpdate()
{
Entities.ForEach((Entity entity, ref VA_AnimatorComponent ac) =>
{
// Get the animation lib data.
ref VA_AnimationLibraryData animationLib = ref ac.animationLibrary.Value;
int animationIndex = VA_AnimationLibraryUtils.GetAnimation(ref animationLib, "Shoot");
//int index = entity.Index % 2;
//ac.animationIndex = index;
ac.animationIndex = animationIndex;
}).ScheduleParallel();
}
}
}

View File

@ -1,17 +1,13 @@
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
namespace TAO.VertexAnimation
{
[MaterialProperty("_AnimationIndex", MaterialPropertyFormat.Float)]
public struct VA_AnimationIndexComponent : IComponentData
[MaterialProperty("_AnimationData", MaterialPropertyFormat.Float4)]
public struct VA_AnimationDataComponent : IComponentData
{
public float Value;
}
[MaterialProperty("_AnimationTime", MaterialPropertyFormat.Float)]
public struct VA_AnimationTimeComponent : IComponentData
{
public float Value;
// animationTime, animationIndex, colorIndex, nan.
public float4 Value;
}
}

View File

@ -12,10 +12,10 @@ float2 VA_UV_float(float2 uv, int maxFrames, float time)
float timeInFrames = frac(time);
timeInFrames = ceil(timeInFrames * maxFrames);
timeInFrames /= maxFrames;
timeInFrames += (1 / maxFrames);
timeInFrames += round(1.0f / maxFrames);
uvPosition.x = uv.x;
uvPosition.y = (1 - (timeInFrames)) + (1 - (1 - uv.y));
uvPosition.y = (1.0f - (timeInFrames)) + (1.0f - (1.0f - uv.y));
return uvPosition;
}

View File

@ -245,7 +245,7 @@
"m_Id": "5ff96695f49e4d1182cf67a53de68be6"
},
{
"m_Id": "6cb7d5a539a9483598c17e29f13c9871"
"m_Id": "f6f46ec323d94a088f47d6ed87a8560e"
}
],
"m_Precision": 0,
@ -272,6 +272,31 @@
"m_StageCapability": 3
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot",
"m_ObjectId": "4a5cf08366814dfbb54e1ab1eacf2e33",
"m_Id": 1,
"m_DisplayName": "RGBA",
"m_SlotType": 0,
"m_Priority": 2147483647,
"m_Hidden": false,
"m_ShaderOutputName": "RGBA",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DArrayShaderProperty",
@ -446,24 +471,6 @@
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "6cb7d5a539a9483598c17e29f13c9871",
"m_Id": 5,
"m_DisplayName": "LOD",
"m_SlotType": 0,
"m_Priority": 2147483647,
"m_Hidden": false,
"m_ShaderOutputName": "LOD",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": [
"X"
]
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.SamplerStateMaterialSlot",
@ -627,7 +634,7 @@
},
"m_Slots": [
{
"m_Id": "d2d519a5c5484c799973056f62d350a2"
"m_Id": "4a5cf08366814dfbb54e1ab1eacf2e33"
}
],
"m_Precision": 0,
@ -656,31 +663,6 @@
]
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot",
"m_ObjectId": "d2d519a5c5484c799973056f62d350a2",
"m_Id": 1,
"m_DisplayName": "Out_Vector4",
"m_SlotType": 0,
"m_Priority": 2147483647,
"m_Hidden": false,
"m_ShaderOutputName": "OutVector4",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
@ -739,3 +721,21 @@
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "f6f46ec323d94a088f47d6ed87a8560e",
"m_Id": 5,
"m_DisplayName": "LOD",
"m_SlotType": 0,
"m_Priority": 2147483647,
"m_Hidden": false,
"m_ShaderOutputName": "LOD",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": [
"X"
]
}