Fixed single bone IK with nonuniform scale. Improved two bone IK.

This commit is contained in:
NathanSweet 2016-05-06 23:09:50 +02:00
parent a92b54b7f0
commit 1be89d1c57

View File

@ -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);