Просмотр исходного кода

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

NathanSweet 9 лет назад
Родитель
Сommit
1be89d1c57

+ 29 - 37
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);