Finished "applied transform" for arbitrary constraint order.

This commit is contained in:
NathanSweet 2016-08-13 08:38:41 +02:00
parent 438f0028b2
commit 217aa60c4f
5 changed files with 87 additions and 68 deletions

View File

@ -45,7 +45,7 @@ public class Bone implements Updatable {
final Array<Bone> children = new Array(); final Array<Bone> children = new Array();
float x, y, rotation, scaleX, scaleY, shearX, shearY; float x, y, rotation, scaleX, scaleY, shearX, shearY;
float ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY; float ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY;
boolean appliedValid; // BOZO! - Use everywhere. boolean appliedValid;
float a, b, worldX; float a, b, worldX;
float c, d, worldY; float c, d, worldY;
@ -99,6 +99,7 @@ public class Bone implements Updatable {
ascaleY = scaleY; ascaleY = scaleY;
ashearX = shearX; ashearX = shearX;
ashearY = shearY; ashearY = shearY;
appliedValid = true;
float rotationY = rotation + 90 + shearY; float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY; float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY;
@ -162,71 +163,71 @@ public class Bone implements Updatable {
b = cos(r) * s; b = cos(r) * s;
d = sin(r) * s; d = sin(r) * s;
} else if (data.inheritScale) { // No rotation inheritance. } else if (data.inheritScale) { // No rotation inheritance.
float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, pr; // float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, pr;
if (psx > 0.0001f) { // if (psx > 0.0001f) {
float det = pa * pd - pb * pc; // float det = pa * pd - pb * pc;
psy = det / psx; // psy = det / psx;
rotationY = atan2(pa * pb + pc * pd, det) * radDeg + 90; // rotationY = atan2(pa * pb + pc * pd, det) * radDeg + 90;
pr = atan2(pc, pa) * radDeg; // pr = atan2(pc, pa) * radDeg;
} else { // } else {
psx = 0; // psx = 0;
psy = (float)Math.sqrt(pb * pb + pd * pd); // psy = (float)Math.sqrt(pb * pb + pd * pd);
rotationY = 90; // rotationY = 90;
pr = 90 - atan2(pd, pb) * radDeg; // pr = 90 - atan2(pd, pb) * radDeg;
} // }
//
// float blend;
// if (pr < -90)
// blend = 1 + (pr + 90) / 90;
// else if (pr < 0)
// blend = -pr / 90;
// else if (pr < 90)
// blend = pr / 90;
// else
// blend = 1f - (pr - 90) / 90;
//
// pa = lerp(psx, Math.abs(psy) * Math.signum(psx), blend);
// psy = lerp(psy, Math.abs(psx) * Math.signum(psy), blend);
// pb = cosDeg(rotationY) * psy;
// pc = 0;
// pd = sinDeg(rotationY) * psy;
//
// a = pa * la + pb * lc;
// b = pa * lb + pb * ld;
// c = pc * la + pd * lc;
// d = pc * lb + pd * ld;
float blend; pa = 1;
if (pr < -90) pb = 0;
blend = 1 + (pr + 90) / 90;
else if (pr < 0)
blend = -pr / 90;
else if (pr < 90)
blend = pr / 90;
else
blend = 1f - (pr - 90) / 90;
pa = lerp(psx, Math.abs(psy) * Math.signum(psx), blend);
psy = lerp(psy, Math.abs(psx) * Math.signum(psy), blend);
pb = cosDeg(rotationY) * psy;
pc = 0; pc = 0;
pd = sinDeg(rotationY) * psy; pd = 1;
do {
float cos = cosDeg(parent.arotation), sin = sinDeg(parent.arotation);
float psx = parent.ascaleX, psy = parent.ascaleY;
float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy;
float temp = pa * za + pb * zc;
pb = pb * zd - pa * zb;
pa = temp;
temp = pc * za + pd * zc;
pd = pd * zd - pc * zb;
pc = temp;
if (psx >= 0) // BOZO! - Why? Should always do this? Fix in new code?
sin = -sin;
temp = pa * cos + pb * sin;
pb = pb * cos - pa * sin;
pa = temp;
temp = pc * cos + pd * sin;
pd = pd * cos - pc * sin;
pc = temp;
if (!parent.data.inheritScale) break;
parent = parent.parent;
} while (parent != null);
a = pa * la + pb * lc; a = pa * la + pb * lc;
b = pa * lb + pb * ld; b = pa * lb + pb * ld;
c = pc * la + pd * lc; c = pc * la + pd * lc;
d = pc * lb + pd * ld; d = pc * lb + pd * ld;
// pa = 1;
// pb = 0;
// pc = 0;
// pd = 1;
// do {
// float cos = cosDeg(parent.arotation), sin = sinDeg(parent.arotation);
// float psx = parent.ascaleX, psy = parent.ascaleY;
// float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy;
// float temp = pa * za + pb * zc;
// pb = pb * zd - pa * zb;
// pa = temp;
// temp = pc * za + pd * zc;
// pd = pd * zd - pc * zb;
// pc = temp;
//
// if (psx >= 0) // BOZO! - Why? Should always do this? Fix in new code?
// sin = -sin;
// temp = pa * cos + pb * sin;
// pb = pb * cos - pa * sin;
// pa = temp;
// temp = pc * cos + pd * sin;
// pd = pd * cos - pc * sin;
// pc = temp;
//
// if (!parent.data.inheritScale) break;
// parent = parent.parent;
// } while (parent != null);
// a = pa * la + pb * lc;
// b = pa * lb + pb * ld;
// c = pc * la + pd * lc;
// d = pc * lb + pd * ld;
} else { } else {
a = la; a = la;
b = lb; b = lb;
@ -411,6 +412,7 @@ public class Bone implements Updatable {
this.b = cos * b - sin * d; this.b = cos * b - sin * d;
this.c = sin * a + cos * c; this.c = sin * a + cos * c;
this.d = sin * b + cos * d; this.d = sin * b + cos * d;
appliedValid = false;
} }
/** Computes the individual applied transform values from the world transform. This can be useful to perform processing using /** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
@ -418,6 +420,7 @@ public class Bone implements Updatable {
* <p> * <p>
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */ * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
public void updateAppliedTransform () { public void updateAppliedTransform () {
appliedValid = true;
Bone parent = this.parent; Bone parent = this.parent;
if (parent == null) { if (parent == null) {
ax = worldX; ax = worldX;

View File

@ -128,6 +128,7 @@ public class IkConstraint implements Constraint {
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world /** 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. */ * coordinate system. */
static public void apply (Bone bone, float targetX, float targetY, float alpha) { static public void apply (Bone bone, float targetX, float targetY, float alpha) {
if (!bone.appliedValid) bone.updateAppliedTransform();
Bone p = bone.parent; Bone p = bone.parent;
float id = 1 / (p.a * p.d - p.b * p.c); float id = 1 / (p.a * p.d - p.b * p.c);
float x = targetX - p.worldX, y = targetY - p.worldY; float x = targetX - p.worldX, y = targetY - p.worldY;
@ -149,11 +150,8 @@ public class IkConstraint implements Constraint {
child.updateWorldTransform(); child.updateWorldTransform();
return; return;
} }
if (!parent.appliedValid) parent.updateAppliedTransform();
// BOZO! - Only when each bone needs it. if (!child.appliedValid) child.updateAppliedTransform();
// child.updateLocalTransform();
// parent.updateLocalTransform();
float px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, csx = child.ascaleX; float px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, csx = child.ascaleX;
int os1, os2, s2; int os1, os2, s2;
if (psx < 0) { if (psx < 0) {

View File

@ -137,6 +137,7 @@ public class PathConstraint implements Constraint {
bone.c = sin * a + cos * c; bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d; bone.d = sin * b + cos * d;
} }
bone.appliedValid = false;
} }
} }

View File

@ -60,7 +60,10 @@ public class Skeleton {
float x, y; float x, y;
final Comparator<Constraint> constraintComparator = new Comparator<Constraint>() { final Comparator<Constraint> constraintComparator = new Comparator<Constraint>() {
public int compare (Constraint o1,Constraint o2){return o1.getOrder()-o2.getOrder();}}; public int compare (Constraint o1, Constraint o2) {
return o1.getOrder() - o2.getOrder();
}
};
public Skeleton (SkeletonData data) { public Skeleton (SkeletonData data) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
@ -152,11 +155,11 @@ public class Skeleton {
public void updateCache () { public void updateCache () {
Array<Updatable> updateCache = this.updateCache; Array<Updatable> updateCache = this.updateCache;
updateCache.clear(); updateCache.clear();
Array<Bone> bones = this.bones; Array<Bone> bones = this.bones;
for (int i = 0, n = bones.size; i < n; i++) for (int i = 0, n = bones.size; i < n; i++)
bones.get(i).sorted = false; bones.get(i).sorted = false;
Array<Constraint> constraints = sortedConstraints; Array<Constraint> constraints = sortedConstraints;
constraints.addAll(ikConstraints); constraints.addAll(ikConstraints);
constraints.addAll(transformConstraints); constraints.addAll(transformConstraints);
@ -172,9 +175,16 @@ public class Skeleton {
sortPathConstraint((PathConstraint)constraint); sortPathConstraint((PathConstraint)constraint);
} }
constraints.clear(); constraints.clear();
for (int i = 0, n = bones.size; i < n; i++) for (int i = 0, n = bones.size; i < n; i++)
sortBone(bones.get(i)); sortBone(bones.get(i));
// BOZO
// for (int i = 0, n = updateCache.size; i < n; i++) {
// Updatable item = updateCache.get(i);
// if (item instanceof Constraint) System.out.print(item + ", ");
// }
// System.out.println();
} }
private void sortIkConstraint (IkConstraint constraint) { private void sortIkConstraint (IkConstraint constraint) {

View File

@ -53,6 +53,7 @@ public class TransformConstraint implements Constraint {
Array<Bone> bones = this.bones; Array<Bone> bones = this.bones;
for (int i = 0, n = bones.size; i < n; i++) { for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i); Bone bone = bones.get(i);
boolean modified = false;
if (rotateMix != 0) { if (rotateMix != 0) {
float a = bone.a, b = bone.b, c = bone.c, d = bone.d; float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
@ -66,6 +67,7 @@ public class TransformConstraint implements Constraint {
bone.b = cos * b - sin * d; bone.b = cos * b - sin * d;
bone.c = sin * a + cos * c; bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d; bone.d = sin * b + cos * d;
modified = true;
} }
if (translateMix != 0) { if (translateMix != 0) {
@ -73,6 +75,7 @@ public class TransformConstraint implements Constraint {
target.localToWorld(temp.set(data.offsetX, data.offsetY)); target.localToWorld(temp.set(data.offsetX, data.offsetY));
bone.worldX += (temp.x - bone.worldX) * translateMix; bone.worldX += (temp.x - bone.worldX) * translateMix;
bone.worldY += (temp.y - bone.worldY) * translateMix; bone.worldY += (temp.y - bone.worldY) * translateMix;
modified = true;
} }
if (scaleMix > 0) { if (scaleMix > 0) {
@ -86,6 +89,7 @@ public class TransformConstraint implements Constraint {
s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0;
bone.b *= s; bone.b *= s;
bone.d *= s; bone.d *= s;
modified = true;
} }
if (shearMix > 0) { if (shearMix > 0) {
@ -99,7 +103,10 @@ public class TransformConstraint implements Constraint {
float s = (float)Math.sqrt(b * b + d * d); float s = (float)Math.sqrt(b * b + d * d);
bone.b = cos(r) * s; bone.b = cos(r) * s;
bone.d = sin(r) * s; bone.d = sin(r) * s;
modified = true;
} }
if (modified) bone.appliedValid = false;
} }
} }