Refactoring bone transforms.

This commit is contained in:
NathanSweet 2016-09-07 22:34:06 +02:00
parent 56797953c2
commit dfe8e3b826
8 changed files with 179 additions and 72 deletions

2
.gitignore vendored
View File

@ -102,3 +102,5 @@ spine-starling/spine-starling-example/lib/.spine-starling.swc.stamp
spine-turbulenz/spine-js/spine.js
spine-threejs/spine-js/spine.js
spine-ts/.vscode/*

View File

@ -33,7 +33,7 @@ org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
@ -84,6 +84,7 @@ org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning

View File

@ -721,35 +721,33 @@ public class Animation {
// BOZO - Test.
if (alpha == 1) {
// Absolute.
// Vertex positions or deform offsets, no alpha.
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] = prev + (nextVertices[i] - prev) * percent;
}
} else {
if (setupPose) {
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
if (vertexAttachment.getBones() == null) {
// Vertex positions.
float[] setupVertices = vertexAttachment.getVertices();
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i], setup = setupVertices[i];
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
}
} else {
// Deform offsets.
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
}
} else if (setupPose) {
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
if (vertexAttachment.getBones() == null) {
// Unweighted vertex positions, with alpha.
float[] setupVertices = vertexAttachment.getVertices();
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i], setup = setupVertices[i];
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
}
} else {
// Additive.
// Weighted deform offsets, with alpha.
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
}
}
} else {
// Vertex positions or deform offsets, with alpha.
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
}
}
}
}
@ -918,6 +916,8 @@ public class Animation {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
// BOZO - Finish timelines handling setupPose and mixingOut from here down.
IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex);
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.

View File

@ -37,6 +37,7 @@ import static com.badlogic.gdx.math.Matrix3.*;
import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.esotericsoftware.spine.BoneData.TransformMode;
public class Bone implements Updatable {
final BoneData data;
@ -100,12 +101,13 @@ public class Bone implements Updatable {
ashearY = shearY;
appliedValid = true;
float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY;
float lc = sinDeg(rotation + shearX) * scaleX, ld = sinDeg(rotationY) * scaleY;
Bone parent = this.parent;
if (parent == null) { // Root bone.
float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX;
float lb = cosDeg(rotationY) * scaleY;
float lc = sinDeg(rotation + shearX) * scaleX;
float ld = sinDeg(rotationY) * scaleY;
Skeleton skeleton = this.skeleton;
if (skeleton.flipX) {
x = -x;
@ -130,28 +132,99 @@ public class Bone implements Updatable {
worldX = pa * x + pb * y + parent.worldX;
worldY = pc * x + pd * y + parent.worldY;
if (data.inheritRotation && data.inheritScale) {
switch (data.transformMode) {
case normal: {
float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX;
float lb = cosDeg(rotationY) * scaleY;
float lc = sinDeg(rotation + shearX) * scaleX;
float ld = sinDeg(rotationY) * scaleY;
a = pa * la + pb * lc;
b = pa * lb + pb * ld;
c = pc * la + pd * lc;
d = pc * lb + pd * ld;
} else {
if (data.inheritRotation) { // No scale inheritance.
float psx = (float)Math.sqrt(pa * pa + pc * pc);
float psy = (float)Math.sqrt(pb * pb + pd * pd);
if (psx > 0.0001f) {
pa /= psx;
pc /= psx;
}
if (psy > 0.0001f) {
pb /= psy;
pd /= psy;
return;
}
case onlyTranslation: {
float rotationY = rotation + 90 + shearY;
a = cosDeg(rotation + shearX) * scaleX;
b = cosDeg(rotationY) * scaleY;
c = sinDeg(rotation + shearX) * scaleX;
d = sinDeg(rotationY) * scaleY;
break;
}
case noRotation: {
if (false) {
// Summing parent rotations.
// 1) Negative parent scale causes bone to rotate.
float sum = 0;
Bone current = parent;
while (current != null) {
sum += current.arotation;
current = current.parent;
}
rotation -= sum;
float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX;
float lb = cosDeg(rotationY) * scaleY;
float lc = sinDeg(rotation + shearX) * scaleX;
float ld = sinDeg(rotationY) * scaleY;
a = pa * la + pb * lc;
b = pa * lb + pb * ld;
c = pc * la + pd * lc;
d = pc * lb + pd * ld;
} else if (data.inheritScale) { // No rotation inheritance.
} else if (true) {
// Old way.
// 1) Immediate parent scale is applied in wrong direction.
// 2) Negative parent scale causes bone to rotate.
pa = 1;
pb = 0;
pc = 0;
pd = 1;
float rotationY, la, lb, lc, ld;
outer:
do {
if (!parent.appliedValid) parent.updateAppliedTransform();
float pr = parent.arotation, psx = parent.ascaleX;
rotationY = pr + 90 + parent.ashearY;
la = cosDeg(pr + parent.shearX);
lb = cosDeg(rotationY);
lc = sinDeg(pr + parent.shearX);
ld = sinDeg(rotationY);
float temp = (pa * la + pb * lc) * psx;
pb = (pb * ld + pa * lb) * parent.ascaleY;
pa = temp;
temp = (pc * la + pd * lc) * psx;
pd = (pd * ld + pc * lb) * parent.ascaleY;
pc = temp;
if (psx < 0) lc = -lc;
temp = pa * la - pb * lc;
pb = pb * ld - pa * lb;
pa = temp;
temp = pc * la - pd * lc;
pd = pd * ld - pc * lb;
pc = temp;
switch (parent.data.transformMode) {
case noScale:
case noScaleOrReflection:
break outer;
}
parent = parent.parent;
} while (parent != null);
rotationY = rotation + 90 + shearY;
la = cosDeg(rotation + shearX) * scaleX;
lb = cosDeg(rotationY) * scaleY;
lc = sinDeg(rotation + shearX) * scaleX;
ld = sinDeg(rotationY) * scaleY;
a = pa * la + pb * lc;
b = pa * lb + pb * ld;
c = pc * la + pd * lc;
d = pc * lb + pd * ld;
} else {
// New way.
// 1) Negative scale can cause bone to flip.
float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, pr;
if (psx > 0.0001f) {
float det = pa * pd - pb * pc;
@ -173,24 +246,57 @@ public class Bone implements Updatable {
blend = 1 - (pr - 90) / 90;
pa = psx + (Math.abs(psy) * Math.signum(psx) - psx) * blend;
pd = psy + (Math.abs(psx) * Math.signum(psy) - psy) * blend;
a = pa * la;
b = pa * lb;
c = pd * lc;
d = pd * ld;
} else {
a = la;
b = lb;
c = lc;
d = ld;
float rotationY = rotation + 90 + shearY;
a = pa * cosDeg(rotation + shearX) * scaleX;
b = pa * cosDeg(rotationY) * scaleY;
c = pd * sinDeg(rotation + shearX) * scaleX;
d = pd * sinDeg(rotationY) * scaleY;
}
if (skeleton.flipX) {
a = -a;
break;
}
case noScale:
case noScaleOrReflection: {
float cos = cosDeg(rotation), sin = sinDeg(rotation);
float za = pa * cos + pb * sin, zb = za;
float zc = pc * cos + pd * sin, zd = zc;
float s = (float)Math.sqrt(za * za + zc * zc);
if (s > 0.00001f) s = 1 / s;
za *= s;
zc *= s;
s = (float)Math.sqrt(zb * zb + zd * zd);
if (s > 0.00001f) s = 1 / s;
zb *= s;
zd *= s;
float by = atan2(zd, zb), r = PI / 2 - (by - atan2(zc, za));
if (r > PI)
r -= PI2;
else if (r < -PI) r += PI2;
r += by;
s = (float)Math.sqrt(zb * zb + zd * zd);
zb = cos(r) * s;
zd = sin(r) * s;
float la = cosDeg(shearX) * scaleX;
float lb = cosDeg(90 + shearY) * scaleY;
float lc = sinDeg(shearX) * scaleX;
float ld = sinDeg(90 + shearY) * scaleY;
a = za * la + zb * lc;
b = za * lb + zb * ld;
c = zc * la + zd * lc;
d = zc * lb + zd * ld;
if (data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
b = -b;
}
if (skeleton.flipY) {
c = -c;
d = -d;
}
return;
}
}
if (skeleton.flipX) {
a = -a;
b = -b;
}
if (skeleton.flipY) {
c = -c;
d = -d;
}
}

View File

@ -39,7 +39,7 @@ public class BoneData {
final BoneData parent;
float length;
float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY;
boolean inheritRotation = true, inheritScale = true;
TransformMode transformMode = TransformMode.normal;
// Nonessential.
final Color color = new Color(0.61f, 0.61f, 0.61f, 1);
@ -157,20 +157,12 @@ public class BoneData {
this.shearY = shearY;
}
public boolean getInheritRotation () {
return inheritRotation;
public TransformMode getTransformMode () {
return transformMode;
}
public void setInheritRotation (boolean inheritRotation) {
this.inheritRotation = inheritRotation;
}
public boolean getInheritScale () {
return inheritScale;
}
public void setInheritScale (boolean inheritScale) {
this.inheritScale = inheritScale;
public void setTransformMode (TransformMode transformMode) {
this.transformMode = transformMode;
}
public Color getColor () {
@ -180,4 +172,10 @@ public class BoneData {
public String toString () {
return name;
}
static public enum TransformMode {
normal, onlyTranslation, noRotation, noScale, noScaleOrReflection;
static public final TransformMode[] values = TransformMode.values();
}
}

View File

@ -58,6 +58,7 @@ import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.BoneData.TransformMode;
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
@ -186,8 +187,7 @@ public class SkeletonBinary {
data.shearX = input.readFloat();
data.shearY = input.readFloat();
data.length = input.readFloat() * scale;
data.inheritRotation = input.readBoolean();
data.inheritScale = input.readBoolean();
data.transformMode = TransformMode.values[input.readInt(true)];
if (nonessential) Color.rgba8888ToColor(data.color, input.readInt());
skeletonData.bones.add(data);
}

View File

@ -56,6 +56,7 @@ import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.BoneData.TransformMode;
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
@ -129,8 +130,7 @@ public class SkeletonJson {
data.scaleY = boneMap.getFloat("scaleY", 1);
data.shearX = boneMap.getFloat("shearX", 0);
data.shearY = boneMap.getFloat("shearY", 0);
data.inheritRotation = boneMap.getBoolean("inheritRotation", true);
data.inheritScale = boneMap.getBoolean("inheritScale", true);
data.transformMode = TransformMode.valueOf(boneMap.getString("transform", TransformMode.normal.name()));
String color = boneMap.getString("color", null);
if (color != null) data.getColor().set(Color.valueOf(color));

View File

@ -79,14 +79,14 @@ public class TransformConstraint implements Constraint {
}
if (scaleMix > 0) {
float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
float s = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
float ts = (float)Math.sqrt(ta * ta + tc * tc);
float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0;
if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleX) * scaleMix) / s;
bone.a *= s;
bone.c *= s;
bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
s = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
ts = (float)Math.sqrt(tb * tb + td * td);
s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0;
if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleY) * scaleMix) / s;
bone.b *= s;
bone.d *= s;
modified = true;