Răsfoiți Sursa

[unity] Animation filling SkeletonData modifier asset.

pharan 7 ani în urmă
părinte
comite
5c25239ff1

+ 1 - 1
spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterialsAsset.cs

@@ -37,7 +37,7 @@ using Spine;
 using Spine.Unity;
 
 namespace Spine.Unity {
-	[CreateAssetMenu(menuName = "Spine/Blend Mode Materials Asset", order = 200)]
+	[CreateAssetMenu(menuName = "Spine/SkeletonData Modifiers/Blend Mode Materials", order = 200)]
 	public class BlendModeMaterialsAsset : SkeletonDataModifierAsset {
 		public Material multiplyMaterialTemplate;
 		public Material screenMaterialTemplate;

+ 9 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: bdfae2bc4b385b84eb4f5f6855d0f991
+folderAsset: yes
+timeCreated: 1537527020
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 265 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier/AnimationMatchModifierAsset.cs

@@ -0,0 +1,265 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+using Spine;
+using Spine.Unity;
+
+namespace Spine.Unity.Modules {
+
+	//[CreateAssetMenu(menuName = "Spine/SkeletonData Modifiers/Animation Match", order = 200)]
+	public class AnimationMatchModifierAsset : SkeletonDataModifierAsset {
+
+		public bool matchAllAnimations = true;
+
+		public override void Apply (SkeletonData skeletonData) {
+			if (matchAllAnimations)
+				AnimationTools.MatchAnimationTimelines(skeletonData.animations, skeletonData);
+		}
+
+		public static class AnimationTools {
+
+			#region Filler Timelines
+			/// <summary>
+			/// Matches the animation timelines across the given set of animations.
+			/// This allows unkeyed properties to assume setup pose when animations are naively mixed using Animation.Apply.
+			/// </summary>
+			/// <param name="animations">An enumerable collection animations whose timelines will be matched.</param>
+			/// <param name="skeletonData">The SkeletonData where the animations belong.</param>
+			public static void MatchAnimationTimelines (IEnumerable<Spine.Animation> animations, SkeletonData skeletonData) {
+				if (animations == null) return;
+				if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "Timelines can't be matched without a SkeletonData source.");
+
+				// Build a reference collection of timelines to match
+				// and a collection of dummy timelines that can be used to fill-in missing items.
+				var timelineDictionary = new Dictionary<int, Spine.Timeline>();
+				foreach (var animation in animations) {
+					foreach (var timeline in animation.timelines) {
+						if (timeline is EventTimeline) continue;
+
+						int propertyID = timeline.PropertyId;
+						if (!timelineDictionary.ContainsKey(propertyID)) {
+							timelineDictionary.Add(propertyID, GetFillerTimeline(timeline, skeletonData));
+						}
+					}
+				}
+				var idsToMatch = new List<int>(timelineDictionary.Keys);
+
+				// For each animation in the list, check for and add missing timelines.
+				var currentAnimationIDs = new HashSet<int>();
+				foreach (var animation in animations) {
+					currentAnimationIDs.Clear();
+					foreach (var timeline in animation.timelines) {
+						if (timeline is EventTimeline) continue;
+						currentAnimationIDs.Add(timeline.PropertyId);
+					}
+
+					var animationTimelines = animation.timelines;
+					foreach (int propertyID in idsToMatch) {
+						if (!currentAnimationIDs.Contains(propertyID))
+							animationTimelines.Add(timelineDictionary[propertyID]);
+					}
+				}
+
+				// These are locals, but sometimes Unity's GC does weird stuff. So let's clean up.
+				timelineDictionary.Clear();
+				timelineDictionary = null;
+				idsToMatch.Clear();
+				idsToMatch = null;
+				currentAnimationIDs.Clear();
+				currentAnimationIDs = null;
+			}
+
+			static Timeline GetFillerTimeline (Timeline timeline, SkeletonData skeletonData) {
+				int propertyID = timeline.PropertyId;
+				int tt = propertyID >> 24;
+				var timelineType = (TimelineType)tt;
+
+				switch (timelineType) {
+					// Bone
+					case TimelineType.Rotate:
+						return GetFillerTimeline((RotateTimeline)timeline, skeletonData);
+					case TimelineType.Translate:
+						return GetFillerTimeline((TranslateTimeline)timeline, skeletonData);
+					case TimelineType.Scale:
+						return GetFillerTimeline((ScaleTimeline)timeline, skeletonData);
+					case TimelineType.Shear:
+						return GetFillerTimeline((ShearTimeline)timeline, skeletonData);
+
+					// Slot
+					case TimelineType.Attachment:
+						return GetFillerTimeline((AttachmentTimeline)timeline, skeletonData);
+					case TimelineType.Color:
+						return GetFillerTimeline((ColorTimeline)timeline, skeletonData);
+					case TimelineType.TwoColor:
+						return GetFillerTimeline((TwoColorTimeline)timeline, skeletonData);
+					case TimelineType.Deform:
+						return GetFillerTimeline((DeformTimeline)timeline, skeletonData);
+
+					// Skeleton
+					case TimelineType.DrawOrder:
+						return GetFillerTimeline((DrawOrderTimeline)timeline, skeletonData);
+
+					// IK Constraint
+					case TimelineType.IkConstraint:
+						return GetFillerTimeline((IkConstraintTimeline)timeline, skeletonData);
+
+					// TransformConstraint
+					case TimelineType.TransformConstraint:
+						return GetFillerTimeline((TransformConstraintTimeline)timeline, skeletonData);
+
+					// Path Constraint
+					case TimelineType.PathConstraintPosition:
+						return GetFillerTimeline((PathConstraintPositionTimeline)timeline, skeletonData);
+					case TimelineType.PathConstraintSpacing:
+						return GetFillerTimeline((PathConstraintSpacingTimeline)timeline, skeletonData);
+					case TimelineType.PathConstraintMix:
+						return GetFillerTimeline((PathConstraintMixTimeline)timeline, skeletonData);
+				}
+
+				return null;
+			}
+
+			static RotateTimeline GetFillerTimeline (RotateTimeline timeline, SkeletonData skeletonData) {
+				var t = new RotateTimeline(1);
+				t.boneIndex = timeline.boneIndex;
+				t.SetFrame(0, 0, 0);
+				return t;
+			}
+
+			static TranslateTimeline GetFillerTimeline (TranslateTimeline timeline, SkeletonData skeletonData) {
+				var t = new TranslateTimeline(1);
+				t.boneIndex = timeline.boneIndex;
+				t.SetFrame(0, 0, 0, 0);
+				return t;
+			}
+
+			static ScaleTimeline GetFillerTimeline (ScaleTimeline timeline, SkeletonData skeletonData) {
+				var t = new ScaleTimeline(1);
+				t.boneIndex = timeline.boneIndex;
+				t.SetFrame(0, 0, 0, 0);
+				return t;
+			}
+
+			static ShearTimeline GetFillerTimeline (ShearTimeline timeline, SkeletonData skeletonData) {
+				var t = new ShearTimeline(1);
+				t.boneIndex = timeline.boneIndex;
+				t.SetFrame(0, 0, 0, 0);
+				return t;
+			}
+
+			static AttachmentTimeline GetFillerTimeline (AttachmentTimeline timeline, SkeletonData skeletonData) {
+				var t = new AttachmentTimeline(1);
+				t.slotIndex = timeline.slotIndex;
+				var slotData = skeletonData.slots.Items[t.slotIndex];
+				t.SetFrame(0, 0, slotData.attachmentName);
+				return t;
+			}
+
+			static ColorTimeline GetFillerTimeline (ColorTimeline timeline, SkeletonData skeletonData) {
+				var t = new ColorTimeline(1);
+				t.slotIndex = timeline.slotIndex;
+				var slotData = skeletonData.slots.Items[t.slotIndex];
+				t.SetFrame(0, 0, slotData.r, slotData.g, slotData.b, slotData.a);
+				return t;
+			}
+
+			static TwoColorTimeline GetFillerTimeline (TwoColorTimeline timeline, SkeletonData skeletonData) {
+				var t = new TwoColorTimeline(1);
+				t.slotIndex = timeline.slotIndex;
+				var slotData = skeletonData.slots.Items[t.slotIndex];
+				t.SetFrame(0, 0, slotData.r, slotData.g, slotData.b, slotData.a, slotData.r2, slotData.g2, slotData.b2);
+				return t;
+			}
+
+			static DeformTimeline GetFillerTimeline (DeformTimeline timeline, SkeletonData skeletonData) {
+				var t = new DeformTimeline(1);
+				t.slotIndex = timeline.slotIndex;
+				t.attachment = timeline.attachment;
+				var slotData = skeletonData.slots.Items[t.slotIndex];
+
+				if (t.attachment.IsWeighted()) {
+					t.SetFrame(0, 0, new float[t.attachment.vertices.Length]);
+				} else {
+					t.SetFrame(0, 0, t.attachment.vertices.Clone() as float[]);
+				}
+
+				return t;
+			}
+
+			static DrawOrderTimeline GetFillerTimeline (DrawOrderTimeline timeline, SkeletonData skeletonData) {
+				var t = new DrawOrderTimeline(1);
+				t.SetFrame(0, 0, null); // null means use setup pose in DrawOrderTimeline.Apply.
+				return t;
+			}
+
+			static IkConstraintTimeline GetFillerTimeline (IkConstraintTimeline timeline, SkeletonData skeletonData) {
+				var t = new IkConstraintTimeline(1);
+				var ikConstraintData = skeletonData.ikConstraints.Items[timeline.ikConstraintIndex];
+				t.SetFrame(0, 0, ikConstraintData.mix, ikConstraintData.bendDirection, ikConstraintData.compress, ikConstraintData.stretch);
+				return t;
+			}
+
+			static TransformConstraintTimeline GetFillerTimeline (TransformConstraintTimeline timeline, SkeletonData skeletonData) {
+				var t = new TransformConstraintTimeline(1);
+				var data = skeletonData.transformConstraints.Items[timeline.transformConstraintIndex];
+				t.SetFrame(0, 0, data.rotateMix, data.translateMix, data.scaleMix, data.shearMix);
+				return t;
+			}
+
+			static PathConstraintPositionTimeline GetFillerTimeline (PathConstraintPositionTimeline timeline, SkeletonData skeletonData) {
+				var t = new PathConstraintPositionTimeline(1);
+				var data = skeletonData.pathConstraints.Items[timeline.pathConstraintIndex];
+				t.SetFrame(0, 0, data.position);
+				return t;
+			}
+
+			static PathConstraintSpacingTimeline GetFillerTimeline (PathConstraintSpacingTimeline timeline, SkeletonData skeletonData) {
+				var t = new PathConstraintSpacingTimeline(1);
+				var data = skeletonData.pathConstraints.Items[timeline.pathConstraintIndex];
+				t.SetFrame(0, 0, data.spacing);
+				return t;
+			}
+
+			static PathConstraintMixTimeline GetFillerTimeline (PathConstraintMixTimeline timeline, SkeletonData skeletonData) {
+				var t = new PathConstraintMixTimeline(1);
+				var data = skeletonData.pathConstraints.Items[timeline.pathConstraintIndex];
+				t.SetFrame(0, 0, data.rotateMix, data.translateMix);
+				return t;
+			}
+			#endregion
+		}
+
+	}
+
+}

+ 12 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier/AnimationMatchModifierAsset.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: df7d457928e0f4041a439f9847f72290
+timeCreated: 1537527074
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 6 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier/AnimationMatchModifierAsset.txt

@@ -0,0 +1,6 @@
+AnimationMatchModifierAsset
+===========================
+
+This is a SkeletonDataModifierAsset. Add it to a SkeletonDataAsset to apply its effects when its SkeletonData is loaded.
+
+AnimationMatchModifierAsset processes animations so that their timelines match. This allows them to function with naive Animation Apply systems such as SkeletonMecanim without the need for autoreset functionality.

+ 8 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier/AnimationMatchModifierAsset.txt.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b4436c0c78cc5ee469089ed864f4e1ea
+timeCreated: 1537528259
+licenseType: Pro
+TextScriptImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier/Default Match All Animations.asset


+ 9 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AnimationMatchModifier/Default Match All Animations.asset.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 8623082208cae724e88314ec951691e1
+timeCreated: 1537527914
+licenseType: Pro
+NativeFormatImporter:
+  mainObjectFileID: 11400000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: