[unity] Minor cleanup for SkeletonBaker.cs

This commit is contained in:
John 2018-04-08 23:32:04 +08:00 committed by GitHub
parent c28bbebf80
commit 7c2fb931d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -56,19 +56,16 @@ namespace Spine.Unity.Editor {
/// Attachment Timeline /// Attachment Timeline
/// ///
/// RegionAttachment /// RegionAttachment
/// MeshAttachment /// MeshAttachment (optionally Skinned)
/// SkinnedMeshAttachment
/// ///
/// [LIMITATIONS] /// [LIMITATIONS]
/// *Inverse Kinematics & Bezier Curves are baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired. /// *Bezier Curves are baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired.
/// **Non-uniform Scale Keys (ie: if ScaleX and ScaleY are not equal to eachother, it will not be accurate to Spine source) /// *Inverse Kinematics is baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired.
/// ***Events may only fire 1 type of data per event in Unity safely so priority to String data if present in Spine key, otherwise a Float is sent whether the Spine key was Int or Float with priority given to Int. /// ***Events may only fire 1 type of data per event in Unity safely so priority to String data if present in Spine key, otherwise a Float is sent whether the Spine key was Int or Float with priority given to Int.
/// ///
/// [DOES NOT SUPPORT] /// [DOES NOT SUPPORT]
/// FlipX or FlipY (Maybe one day)
/// FFD (Unity does not provide access to BlendShapes with code) /// FFD (Unity does not provide access to BlendShapes with code)
/// Color Keys (Maybe one day when Unity supports full FBX standard and provides access with code) /// Color Keys (Maybe one day when Unity supports full FBX standard and provides access with code)
/// InheritScale (Never. Unity and Spine do scaling very differently)
/// Draw Order Keyframes /// Draw Order Keyframes
/// </summary> /// </summary>
public static class SkeletonBaker { public static class SkeletonBaker {
@ -174,11 +171,11 @@ namespace Spine.Unity.Editor {
#endif #endif
#endregion #endregion
#region Baking #region Prefab and AnimationClip Baking
/// <summary> /// <summary>
/// Interval between key sampling for Bezier curves, IK controlled bones, and Inherit Rotation effected bones. /// Interval between key sampling for Bezier curves, IK controlled bones, and Inherit Rotation effected bones.
/// </summary> /// </summary>
const float bakeIncrement = 1 / 60f; const float BakeIncrement = 1 / 60f;
public static void BakeToPrefab (SkeletonDataAsset skeletonDataAsset, ExposedList<Skin> skins, string outputPath = "", bool bakeAnimations = true, bool bakeIK = true, SendMessageOptions eventOptions = SendMessageOptions.DontRequireReceiver) { public static void BakeToPrefab (SkeletonDataAsset skeletonDataAsset, ExposedList<Skin> skins, string outputPath = "", bool bakeAnimations = true, bool bakeIK = true, SendMessageOptions eventOptions = SendMessageOptions.DontRequireReceiver) {
if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(true) == null) { if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(true) == null) {
@ -351,8 +348,8 @@ namespace Spine.Unity.Editor {
for (int a = 0; a < attachments.Count; a++) { for (int a = 0; a < attachments.Count; a++) {
var attachment = attachments[a]; var attachment = attachments[a];
var attachmentName = attachmentNames[a]; string attachmentName = attachmentNames[a];
var attachmentMeshName = "[" + slotData.Name + "] " + attachmentName; string attachmentMeshName = "[" + slotData.Name + "] " + attachmentName;
Vector3 offset = Vector3.zero; Vector3 offset = Vector3.zero;
float rotation = 0; float rotation = 0;
Mesh mesh = null; Mesh mesh = null;
@ -454,18 +451,20 @@ namespace Spine.Unity.Editor {
} }
static Bone extractionBone; #region Attachment Baking
static Slot extractionSlot; static Bone DummyBone;
static Slot DummySlot;
internal static Bone GetExtractionBone () { internal static Bone GetDummyBone () {
if (extractionBone != null) if (DummyBone != null)
return extractionBone; return DummyBone;
SkeletonData skelData = new SkeletonData(); SkeletonData skelData = new SkeletonData();
BoneData data = new BoneData(0, "temp", null); BoneData data = new BoneData(0, "temp", null) {
data.ScaleX = 1; ScaleX = 1,
data.ScaleY = 1; ScaleY = 1,
data.Length = 100; Length = 100
};
skelData.Bones.Add(data); skelData.Bones.Add(data);
@ -474,25 +473,25 @@ namespace Spine.Unity.Editor {
Bone bone = new Bone(data, skeleton, null); Bone bone = new Bone(data, skeleton, null);
bone.UpdateWorldTransform(); bone.UpdateWorldTransform();
extractionBone = bone; DummyBone = bone;
return extractionBone; return DummyBone;
} }
internal static Slot GetExtractionSlot () { internal static Slot GetDummySlot () {
if (extractionSlot != null) if (DummySlot != null)
return extractionSlot; return DummySlot;
Bone bone = GetExtractionBone(); Bone bone = GetDummyBone();
SlotData data = new SlotData(0, "temp", bone.Data); SlotData data = new SlotData(0, "temp", bone.Data);
Slot slot = new Slot(data, bone); Slot slot = new Slot(data, bone);
extractionSlot = slot; DummySlot = slot;
return extractionSlot; return DummySlot;
} }
internal static Mesh ExtractRegionAttachment (string name, RegionAttachment attachment, Mesh mesh = null, bool centered = true) { internal static Mesh ExtractRegionAttachment (string name, RegionAttachment attachment, Mesh mesh = null, bool centered = true) {
var bone = GetExtractionBone(); var bone = GetDummyBone();
if (centered) { if (centered) {
bone.X = -attachment.X; bone.X = -attachment.X;
@ -532,7 +531,7 @@ namespace Spine.Unity.Editor {
} }
internal static Mesh ExtractMeshAttachment (string name, MeshAttachment attachment, Mesh mesh = null) { internal static Mesh ExtractMeshAttachment (string name, MeshAttachment attachment, Mesh mesh = null) {
var slot = GetExtractionSlot(); var slot = GetDummySlot();
slot.Bone.X = 0; slot.Bone.X = 0;
slot.Bone.Y = 0; slot.Bone.Y = 0;
@ -731,7 +730,9 @@ namespace Spine.Unity.Editor {
return arr; return arr;
} }
#endregion
#region Animation Baking
static AnimationClip ExtractAnimation (string name, SkeletonData skeletonData, Dictionary<int, List<string>> slotLookup, bool bakeIK, SendMessageOptions eventOptions, AnimationClip clip = null) { static AnimationClip ExtractAnimation (string name, SkeletonData skeletonData, Dictionary<int, List<string>> slotLookup, bool bakeIK, SendMessageOptions eventOptions, AnimationClip clip = null) {
var animation = skeletonData.FindAnimation(name); var animation = skeletonData.FindAnimation(name);
@ -755,7 +756,7 @@ namespace Spine.Unity.Editor {
foreach (Bone b in i.Bones) { foreach (Bone b in i.Bones) {
int index = skeleton.FindBoneIndex(b.Data.Name); int index = skeleton.FindBoneIndex(b.Data.Name);
ignoreRotateTimelineIndexes.Add(index); ignoreRotateTimelineIndexes.Add(index);
BakeBone(b, animation, clip); BakeBoneConstraints(b, animation, clip);
} }
} }
} }
@ -766,7 +767,7 @@ namespace Spine.Unity.Editor {
if (ignoreRotateTimelineIndexes.Contains(index) == false) { if (ignoreRotateTimelineIndexes.Contains(index) == false) {
ignoreRotateTimelineIndexes.Add(index); ignoreRotateTimelineIndexes.Add(index);
BakeBone(b, animation, clip); BakeBoneConstraints(b, animation, clip);
} }
} }
} }
@ -813,122 +814,13 @@ namespace Spine.Unity.Editor {
low = current + 1; low = current + 1;
else else
high = current; high = current;
if (low == high) return (low + 1); if (low == high) return (low + 1);
current = (int)((uint)(low + high) >> 1); current = (int)((uint)(low + high) >> 1);
} }
} }
static void ParseEventTimeline (EventTimeline timeline, AnimationClip clip, SendMessageOptions eventOptions) { static void BakeBoneConstraints (Bone bone, Spine.Animation animation, AnimationClip clip) {
float[] frames = timeline.Frames;
var events = timeline.Events;
List<AnimationEvent> animEvents = new List<AnimationEvent>();
for (int i = 0; i < frames.Length; i++) {
var ev = events[i];
AnimationEvent ae = new AnimationEvent();
//MITCH: left todo: Deal with Mecanim's zero-time missed event
ae.time = frames[i];
ae.functionName = ev.Data.Name;
ae.messageOptions = eventOptions;
if (!string.IsNullOrEmpty(ev.String)) {
ae.stringParameter = ev.String;
} else {
if (ev.Int == 0 && ev.Float == 0) {
//do nothing, raw function
} else {
if (ev.Int != 0)
ae.floatParameter = (float)ev.Int;
else
ae.floatParameter = ev.Float;
}
}
animEvents.Add(ae);
}
AnimationUtility.SetAnimationEvents(clip, animEvents.ToArray());
}
static void ParseAttachmentTimeline (Skeleton skeleton, AttachmentTimeline timeline, Dictionary<int, List<string>> slotLookup, AnimationClip clip) {
var attachmentNames = slotLookup[timeline.SlotIndex];
string bonePath = GetPath(skeleton.Slots.Items[timeline.SlotIndex].Bone.Data);
string slotPath = bonePath + "/" + skeleton.Slots.Items[timeline.SlotIndex].Data.Name;
Dictionary<string, AnimationCurve> curveTable = new Dictionary<string, AnimationCurve>();
foreach (string str in attachmentNames) {
curveTable.Add(str, new AnimationCurve());
}
float[] frames = timeline.Frames;
if (frames[0] != 0) {
string startingName = skeleton.Slots.Items[timeline.SlotIndex].Data.AttachmentName;
foreach (var pair in curveTable) {
if (startingName == "" || startingName == null) {
pair.Value.AddKey(new Keyframe(0, 0, float.PositiveInfinity, float.PositiveInfinity));
} else {
if (pair.Key == startingName) {
pair.Value.AddKey(new Keyframe(0, 1, float.PositiveInfinity, float.PositiveInfinity));
} else {
pair.Value.AddKey(new Keyframe(0, 0, float.PositiveInfinity, float.PositiveInfinity));
}
}
}
}
float currentTime = timeline.Frames[0];
float endTime = frames[frames.Length - 1];
int f = 0;
while (currentTime < endTime) {
float time = frames[f];
int frameIndex = (time >= frames[frames.Length - 1] ? frames.Length : BinarySearch(frames, time)) - 1;
string name = timeline.AttachmentNames[frameIndex];
foreach (var pair in curveTable) {
if (name == "") {
pair.Value.AddKey(new Keyframe(time, 0, float.PositiveInfinity, float.PositiveInfinity));
} else {
if (pair.Key == name) {
pair.Value.AddKey(new Keyframe(time, 1, float.PositiveInfinity, float.PositiveInfinity));
} else {
pair.Value.AddKey(new Keyframe(time, 0, float.PositiveInfinity, float.PositiveInfinity));
}
}
}
currentTime = time;
f += 1;
}
foreach (var pair in curveTable) {
string path = slotPath + "/" + pair.Key;
string prop = "m_IsActive";
clip.SetCurve(path, typeof(GameObject), prop, pair.Value);
}
}
static float GetUninheritedRotation (Bone b) {
Bone parent = b.Parent;
float angle = b.AppliedRotation;
while (parent != null) {
angle -= parent.AppliedRotation;
parent = parent.Parent;
}
return angle;
}
static void BakeBone (Bone bone, Spine.Animation animation, AnimationClip clip) {
Skeleton skeleton = bone.Skeleton; Skeleton skeleton = bone.Skeleton;
bool inheritRotation = bone.Data.TransformMode.InheritsRotation(); bool inheritRotation = bone.Data.TransformMode.InheritsRotation();
@ -942,7 +834,7 @@ namespace Spine.Unity.Editor {
float rotation = bone.AppliedRotation; float rotation = bone.AppliedRotation;
if (!inheritRotation) if (!inheritRotation)
rotation = GetUninheritedRotation(bone); rotation = GetUninheritedAppliedRotation(bone);
keys.Add(new Keyframe(0, rotation, 0, 0)); keys.Add(new Keyframe(0, rotation, 0, 0));
@ -950,13 +842,13 @@ namespace Spine.Unity.Editor {
float r = rotation; float r = rotation;
int steps = Mathf.CeilToInt(duration / bakeIncrement); int steps = Mathf.CeilToInt(duration / BakeIncrement);
float currentTime = 0; float currentTime = 0;
float angle = rotation; float angle = rotation;
for (int i = 1; i <= steps; i++) { for (int i = 1; i <= steps; i++) {
currentTime += bakeIncrement; currentTime += BakeIncrement;
if (i == steps) if (i == steps)
currentTime = duration; currentTime = duration;
@ -969,7 +861,7 @@ namespace Spine.Unity.Editor {
pk = keys[pIndex]; pk = keys[pIndex];
rotation = inheritRotation ? bone.AppliedRotation : GetUninheritedRotation(bone); rotation = inheritRotation ? bone.AppliedRotation : GetUninheritedAppliedRotation(bone);
angle += Mathf.DeltaAngle(angle, rotation); angle += Mathf.DeltaAngle(angle, rotation);
@ -1026,10 +918,7 @@ namespace Spine.Unity.Editor {
while (currentTime < endTime) { while (currentTime < endTime) {
int pIndex = listIndex - 1; int pIndex = listIndex - 1;
float curveType = timeline.GetCurveType(frameIndex - 1); float curveType = timeline.GetCurveType(frameIndex - 1);
if (curveType == 0) { if (curveType == 0) {
//linear //linear
Keyframe px = xKeys[pIndex]; Keyframe px = xKeys[pIndex];
@ -1092,10 +981,10 @@ namespace Spine.Unity.Editor {
float time = frames[f]; float time = frames[f];
int steps = Mathf.FloorToInt((time - px.time) / bakeIncrement); int steps = Mathf.FloorToInt((time - px.time) / BakeIncrement);
for (int i = 1; i <= steps; i++) { for (int i = 1; i <= steps; i++) {
currentTime += bakeIncrement; currentTime += BakeIncrement;
if (i == steps) if (i == steps)
currentTime = time; currentTime = time;
@ -1138,13 +1027,6 @@ namespace Spine.Unity.Editor {
clip.SetCurve(path, typeof(Transform), propertyName + ".z", zCurve); clip.SetCurve(path, typeof(Transform), propertyName + ".z", zCurve);
} }
static AnimationCurve EnsureCurveKeyCount (AnimationCurve curve) {
if (curve.length == 1)
curve.AddKey(curve.keys[0].time + 0.25f, curve.keys[0].value);
return curve;
}
static void ParseScaleTimeline (Skeleton skeleton, ScaleTimeline timeline, AnimationClip clip) { static void ParseScaleTimeline (Skeleton skeleton, ScaleTimeline timeline, AnimationClip clip) {
var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex]; var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones.Items[timeline.BoneIndex]; var bone = skeleton.Bones.Items[timeline.BoneIndex];
@ -1234,10 +1116,10 @@ namespace Spine.Unity.Editor {
float time = frames[f]; float time = frames[f];
int steps = Mathf.FloorToInt((time - px.time) / bakeIncrement); int steps = Mathf.FloorToInt((time - px.time) / BakeIncrement);
for (int i = 1; i <= steps; i++) { for (int i = 1; i <= steps; i++) {
currentTime += bakeIncrement; currentTime += BakeIncrement;
if (i == steps) if (i == steps)
currentTime = time; currentTime = time;
@ -1367,10 +1249,10 @@ namespace Spine.Unity.Editor {
angle += Mathf.DeltaAngle(angle, rotation); angle += Mathf.DeltaAngle(angle, rotation);
float r = angle; float r = angle;
int steps = Mathf.FloorToInt((time - pk.time) / bakeIncrement); int steps = Mathf.FloorToInt((time - pk.time) / BakeIncrement);
for (int i = 1; i <= steps; i++) { for (int i = 1; i <= steps; i++) {
currentTime += bakeIncrement; currentTime += BakeIncrement;
if (i == steps) if (i == steps)
currentTime = time; currentTime = time;
@ -1412,18 +1294,132 @@ namespace Spine.Unity.Editor {
AnimationUtility.SetEditorCurve(clip, zBind, curve); AnimationUtility.SetEditorCurve(clip, zBind, curve);
} }
static void ParseEventTimeline (EventTimeline timeline, AnimationClip clip, SendMessageOptions eventOptions) {
float[] frames = timeline.Frames;
var events = timeline.Events;
List<AnimationEvent> animEvents = new List<AnimationEvent>();
for (int i = 0; i < frames.Length; i++) {
var ev = events[i];
AnimationEvent ae = new AnimationEvent();
//MITCH: left todo: Deal with Mecanim's zero-time missed event
ae.time = frames[i];
ae.functionName = ev.Data.Name;
ae.messageOptions = eventOptions;
if (!string.IsNullOrEmpty(ev.String)) {
ae.stringParameter = ev.String;
} else {
if (ev.Int == 0 && ev.Float == 0) {
//do nothing, raw function
} else {
if (ev.Int != 0)
ae.floatParameter = (float)ev.Int;
else
ae.floatParameter = ev.Float;
}
}
animEvents.Add(ae);
}
AnimationUtility.SetAnimationEvents(clip, animEvents.ToArray());
}
static void ParseAttachmentTimeline (Skeleton skeleton, AttachmentTimeline timeline, Dictionary<int, List<string>> slotLookup, AnimationClip clip) {
var attachmentNames = slotLookup[timeline.SlotIndex];
string bonePath = GetPath(skeleton.Slots.Items[timeline.SlotIndex].Bone.Data);
string slotPath = bonePath + "/" + skeleton.Slots.Items[timeline.SlotIndex].Data.Name;
Dictionary<string, AnimationCurve> curveTable = new Dictionary<string, AnimationCurve>();
foreach (string str in attachmentNames) {
curveTable.Add(str, new AnimationCurve());
}
float[] frames = timeline.Frames;
if (frames[0] != 0) {
string startingName = skeleton.Slots.Items[timeline.SlotIndex].Data.AttachmentName;
foreach (var pair in curveTable) {
if (startingName == "" || startingName == null) {
pair.Value.AddKey(new Keyframe(0, 0, float.PositiveInfinity, float.PositiveInfinity));
} else {
if (pair.Key == startingName) {
pair.Value.AddKey(new Keyframe(0, 1, float.PositiveInfinity, float.PositiveInfinity));
} else {
pair.Value.AddKey(new Keyframe(0, 0, float.PositiveInfinity, float.PositiveInfinity));
}
}
}
}
float currentTime = timeline.Frames[0];
float endTime = frames[frames.Length - 1];
int f = 0;
while (currentTime < endTime) {
float time = frames[f];
int frameIndex = (time >= frames[frames.Length - 1] ? frames.Length : BinarySearch(frames, time)) - 1;
string name = timeline.AttachmentNames[frameIndex];
foreach (var pair in curveTable) {
if (name == "") {
pair.Value.AddKey(new Keyframe(time, 0, float.PositiveInfinity, float.PositiveInfinity));
} else {
if (pair.Key == name) {
pair.Value.AddKey(new Keyframe(time, 1, float.PositiveInfinity, float.PositiveInfinity));
} else {
pair.Value.AddKey(new Keyframe(time, 0, float.PositiveInfinity, float.PositiveInfinity));
}
}
}
currentTime = time;
f += 1;
}
foreach (var pair in curveTable) {
string path = slotPath + "/" + pair.Key;
string prop = "m_IsActive";
clip.SetCurve(path, typeof(GameObject), prop, pair.Value);
}
}
static AnimationCurve EnsureCurveKeyCount (AnimationCurve curve) {
if (curve.length == 1)
curve.AddKey(curve.keys[0].time + 0.25f, curve.keys[0].value);
return curve;
}
static float GetUninheritedAppliedRotation (Bone b) {
Bone parent = b.Parent;
float angle = b.AppliedRotation;
while (parent != null) {
angle -= parent.AppliedRotation;
parent = parent.Parent;
}
return angle;
}
#endregion
#endregion
static string GetPath (BoneData b) { static string GetPath (BoneData b) {
return GetPathRecurse(b).Substring(1); return GetPathRecurse(b).Substring(1);
} }
static string GetPathRecurse (BoneData b) { static string GetPathRecurse (BoneData b) {
if (b == null) { if (b == null) return "";
return "";
}
return GetPathRecurse(b.Parent) + "/" + b.Name; return GetPathRecurse(b.Parent) + "/" + b.Name;
} }
#endregion
static void SetAnimationSettings (AnimationClip clip, AnimationClipSettings settings) { static void SetAnimationSettings (AnimationClip clip, AnimationClipSettings settings) {
AnimationUtility.SetAnimationClipSettings(clip, settings); AnimationUtility.SetAnimationClipSettings(clip, settings);