From 1be89d1c5766fedb91f080a23bffaef6609b86c3 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Fri, 6 May 2016 23:09:50 +0200 Subject: [PATCH] Fixed single bone IK with nonuniform scale. Improved two bone IK. --- .../esotericsoftware/spine/IkConstraint.java | 66 ++++++++----------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index 0ee0c1023..9969688f1 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -122,14 +122,16 @@ public class IkConstraint implements Updatable { /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world * coordinate system. */ static public void apply (Bone bone, float targetX, float targetY, float alpha) { - float parentRotation = bone.parent == null ? 0 : bone.parent.getWorldRotationX(); - float rotation = bone.rotation; - float rotationIK = atan2(targetY - bone.worldY, targetX - bone.worldX) * radDeg - parentRotation; - if ((bone.worldSignX != bone.worldSignY) != (bone.skeleton.flipX != bone.skeleton.flipY)) rotationIK = 360 - rotationIK; + Bone pp = bone.parent; + float id = 1 / (pp.a * pp.d - pp.b * pp.c); + float x = targetX - pp.worldX, y = targetY - pp.worldY; + float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; + float rotationIK = atan2(ty, tx) * radDeg - bone.shearX; + if (bone.scaleX < 0) rotationIK += 180; if (rotationIK > 180) rotationIK -= 360; else if (rotationIK < -180) rotationIK += 360; - bone.updateWorldTransform(bone.x, bone.y, rotation + (rotationIK - rotation) * alpha, bone.appliedScaleX, + bone.updateWorldTransform(bone.x, bone.y, bone.rotation + (rotationIK - bone.rotation) * alpha, bone.appliedScaleX, bone.appliedScaleY, bone.shearX, bone.shearY); } @@ -165,22 +167,12 @@ public class IkConstraint implements Updatable { } else os2 = 0; Bone pp = parent.parent; - float tx, ty, dx, dy; - if (pp == null) { - tx = targetX - px; - ty = targetY - py; - dx = child.worldX - px; - dy = child.worldY - py; - } else { - float a = pp.a, b = pp.b, c = pp.c, d = pp.d, invDet = 1 / (a * d - b * c); - float wx = pp.worldX, wy = pp.worldY, x = targetX - wx, y = targetY - wy; - tx = (x * d - y * b) * invDet - px; - ty = (y * a - x * c) * invDet - py; - x = child.worldX - wx; - y = child.worldY - wy; - dx = (x * d - y * b) * invDet - px; - dy = (y * a - x * c) * invDet - py; - } + float ppa = pp.a, ppb = pp.b, ppc = pp.c, ppd = pp.d, id = 1 / (ppa * ppd - ppb * ppc); + float x = targetX - pp.worldX, y = targetY - pp.worldY; + float tx = (x * ppd - y * ppb) * id - px, ty = (y * ppa - x * ppc) * id - py; + x = child.worldX - pp.worldX; + y = child.worldY - pp.worldY; + float dx = (x * ppd - y * ppb) * id - px, dy = (y * ppa - x * ppc) * id - py; float l1 = (float)Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; outer: if (u) { @@ -204,7 +196,7 @@ public class IkConstraint implements Updatable { float r0 = q / c2, r1 = c0 / q; float r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; if (r * r <= dd) { - float y = (float)Math.sqrt(dd - r * r) * bendDir; + y = (float)Math.sqrt(dd - r * r) * bendDir; a1 = ta - atan2(y, r); a2 = atan2(y / psy, (r - l1) / psx); break outer; @@ -212,32 +204,33 @@ public class IkConstraint implements Updatable { } float minAngle = 0, minDist = Float.MAX_VALUE, minX = 0, minY = 0; float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; - float x = l1 + a, dist = x * x; - if (dist > maxDist) { + x = l1 + a; + d = x * x; + if (d > maxDist) { maxAngle = 0; - maxDist = dist; + maxDist = d; maxX = x; } x = l1 - a; - dist = x * x; - if (dist < minDist) { + d = x * x; + if (d < minDist) { minAngle = PI; - minDist = dist; + minDist = d; minX = x; } float angle = (float)Math.acos(-a * l1 / (aa - bb)); x = a * cos(angle) + l1; - float y = b * sin(angle); - dist = x * x + y * y; - if (dist < minDist) { + y = b * sin(angle); + d = x * x + y * y; + if (d < minDist) { minAngle = angle; - minDist = dist; + minDist = d; minX = x; minY = y; } - if (dist > maxDist) { + if (d > maxDist) { maxAngle = angle; - maxDist = dist; + maxDist = d; maxX = x; maxY = y; } @@ -251,7 +244,7 @@ public class IkConstraint implements Updatable { } float os = atan2(cy, cx) * s2; a1 = (a1 - os) * radDeg + os1; - a2 = (a2 + os) * radDeg * s2 + os2; + a2 = ((a2 + os) * radDeg - child.shearX) * s2 + os2; if (a1 > 180) a1 -= 360; else if (a1 < -180) a1 += 360; @@ -259,8 +252,7 @@ public class IkConstraint implements Updatable { a2 -= 360; else if (a2 < -180) a2 += 360; float rotation = parent.rotation; - parent.updateWorldTransform(px, py, rotation + (a1 - rotation) * alpha, parent.appliedScaleX, parent.appliedScaleY, - parent.shearX, parent.shearY); + parent.updateWorldTransform(px, py, rotation + (a1 - rotation) * alpha, parent.appliedScaleX, parent.appliedScaleY, 0, 0); rotation = child.rotation; child.updateWorldTransform(cx, cy, rotation + (a2 - rotation) * alpha, child.appliedScaleX, child.appliedScaleY, child.shearX, child.shearY);