From 1c3f6b1b32eb14d347454fe1c26bcdbd9bbab11d Mon Sep 17 00:00:00 2001 From: pharan Date: Tue, 17 Apr 2018 07:58:54 +0800 Subject: [PATCH] [unity] Spine.BoneMatrix struct. --- .../Assets/spine-unity/SkeletonExtensions.cs | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index 00797dc25..841209869 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/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; + + /// Recursively calculates a worldspace bone matrix based on BoneData. + 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; + } + + /// Constructor for a local bone matrix based on Setup Pose BoneData. + 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; + } + + /// Constructor for a local bone matrix based on a bone instance's current pose. + 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;