Selaa lähdekoodia

[unity] Spine.BoneMatrix struct.

pharan 7 vuotta sitten
vanhempi
commit
1c3f6b1b32
1 muutettua tiedostoa jossa 142 lisäystä ja 0 poistoa
  1. 142 0
      spine-unity/Assets/spine-unity/SkeletonExtensions.cs

+ 142 - 0
spine-unity/Assets/spine-unity/SkeletonExtensions.cs

@@ -283,8 +283,150 @@ namespace Spine.Unity {
 }
 
 namespace Spine {
+	using System;
 	using System.Collections.Generic;
 
+	public struct BoneMatrix {
+		public float a, b, c, d, x, y;
+
+		/// <summary>Recursively calculates a worldspace bone matrix based on BoneData.</summary>
+		public static BoneMatrix CalculateSetupWorld (BoneData boneData) {
+			if (boneData == null)
+				return default(BoneMatrix);
+
+			// End condition: isRootBone
+			if (boneData.parent == null)
+				return GetInheritedInternal(boneData, default(BoneMatrix));
+
+			BoneMatrix result = CalculateSetupWorld(boneData.parent);
+			return GetInheritedInternal(boneData, result);
+		}
+
+		static BoneMatrix GetInheritedInternal (BoneData boneData, BoneMatrix parentMatrix) {
+			var parent = boneData.parent;
+			if (parent == null) return new BoneMatrix(boneData); // isRootBone
+
+			float pa = parentMatrix.a, pb = parentMatrix.b, pc = parentMatrix.c, pd = parentMatrix.d;
+			BoneMatrix result = default(BoneMatrix);
+			result.x = pa * boneData.x + pb * boneData.y + parentMatrix.x;
+			result.y = pc * boneData.x + pd * boneData.y + parentMatrix.y;
+
+			switch (boneData.transformMode) {
+				case TransformMode.Normal: {
+					float rotationY = boneData.rotation + 90 + boneData.shearY;
+					float la = MathUtils.CosDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
+					float lb = MathUtils.CosDeg(rotationY) * boneData.scaleY;
+					float lc = MathUtils.SinDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
+					float ld = MathUtils.SinDeg(rotationY) * boneData.scaleY;
+					result.a = pa * la + pb * lc;
+					result.b = pa * lb + pb * ld;
+					result.c = pc * la + pd * lc;
+					result.d = pc * lb + pd * ld;
+					break;
+				}
+				case TransformMode.OnlyTranslation: {
+					float rotationY = boneData.rotation + 90 + boneData.shearY;
+					result.a = MathUtils.CosDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
+					result.b = MathUtils.CosDeg(rotationY) * boneData.scaleY;
+					result.c = MathUtils.SinDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
+					result.d = MathUtils.SinDeg(rotationY) * boneData.scaleY;
+					break;
+				}
+				case TransformMode.NoRotationOrReflection: {
+					float s = pa * pa + pc * pc, prx;
+					if (s > 0.0001f) {
+						s = Math.Abs(pa * pd - pb * pc) / s;
+						pb = pc * s;
+						pd = pa * s;
+						prx = MathUtils.Atan2(pc, pa) * MathUtils.RadDeg;
+					} else {
+						pa = 0;
+						pc = 0;
+						prx = 90 - MathUtils.Atan2(pd, pb) * MathUtils.RadDeg;
+					}
+					float rx = boneData.rotation + boneData.shearX - prx;
+					float ry = boneData.rotation + boneData.shearY - prx + 90;
+					float la = MathUtils.CosDeg(rx) * boneData.scaleX;
+					float lb = MathUtils.CosDeg(ry) * boneData.scaleY;
+					float lc = MathUtils.SinDeg(rx) * boneData.scaleX;
+					float ld = MathUtils.SinDeg(ry) * boneData.scaleY;
+					result.a = pa * la - pb * lc;
+					result.b = pa * lb - pb * ld;
+					result.c = pc * la + pd * lc;
+					result.d = pc * lb + pd * ld;
+					break;
+				}
+				case TransformMode.NoScale:
+				case TransformMode.NoScaleOrReflection: {
+					float cos = MathUtils.CosDeg(boneData.rotation), sin = MathUtils.SinDeg(boneData.rotation);
+					float za = pa * cos + pb * sin;
+					float zc = pc * cos + pd * sin;
+					float s = (float)Math.Sqrt(za * za + zc * zc);
+					if (s > 0.00001f)
+						s = 1 / s;
+					za *= s;
+					zc *= s;
+					s = (float)Math.Sqrt(za * za + zc * zc);
+					float r = MathUtils.PI / 2 + MathUtils.Atan2(zc, za);
+					float zb = MathUtils.Cos(r) * s;
+					float zd = MathUtils.Sin(r) * s;
+					float la = MathUtils.CosDeg(boneData.shearX) * boneData.scaleX;
+					float lb = MathUtils.CosDeg(90 + boneData.shearY) * boneData.scaleY;
+					float lc = MathUtils.SinDeg(boneData.shearX) * boneData.scaleX;
+					float ld = MathUtils.SinDeg(90 + boneData.shearY) * boneData.scaleY;
+					if (boneData.transformMode != TransformMode.NoScaleOrReflection ? pa * pd - pb * pc < 0 : false) {
+						zb = -zb;
+						zd = -zd;
+					}
+					result.a = za * la + zb * lc;
+					result.b = za * lb + zb * ld;
+					result.c = zc * la + zd * lc;
+					result.d = zc * lb + zd * ld;
+					break;
+				}
+			}
+
+			return result;
+		}
+
+		/// <summary>Constructor for a local bone matrix based on Setup Pose BoneData.</summary>
+		public BoneMatrix (BoneData boneData) {
+			float rotationY = boneData.rotation + 90 + boneData.shearY;
+			float rotationX = boneData.rotation + boneData.shearX;
+
+			a = MathUtils.CosDeg(rotationX) * boneData.scaleX;
+			c = MathUtils.SinDeg(rotationX) * boneData.scaleX;
+			b = MathUtils.CosDeg(rotationY) * boneData.scaleY;
+			d = MathUtils.SinDeg(rotationY) * boneData.scaleY;
+			x = boneData.x;
+			y = boneData.y;
+		}
+
+		/// <summary>Constructor for a local bone matrix based on a bone instance's current pose.</summary>
+		public BoneMatrix (Bone bone) {
+			float rotationY = bone.rotation + 90 + bone.shearY;
+			float rotationX = bone.rotation + bone.shearX;
+
+			a = MathUtils.CosDeg(rotationX) * bone.scaleX;
+			c = MathUtils.SinDeg(rotationX) * bone.scaleX;
+			b = MathUtils.CosDeg(rotationY) * bone.scaleY;
+			d = MathUtils.SinDeg(rotationY) * bone.scaleY;
+			x = bone.x;
+			y = bone.y;
+		}
+
+		public BoneMatrix TransformMatrix (BoneMatrix local) {
+			return new BoneMatrix {
+				a = this.a * local.a + this.b * local.c,
+				b = this.a * local.b + this.b * local.d,
+				c = this.c * local.a + this.d * local.c,
+				d = this.c * local.b + this.d * local.d,
+				x = this.a * local.x + this.b * local.y + this.x,
+				y = this.c * local.x + this.d * local.y + this.y
+			};
+		}
+	}
+
 	public static class SkeletonExtensions {
 		public static bool IsWeighted (this VertexAttachment va) {
 			return va.bones != null && va.bones.Length > 0;