mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 22:34:53 +08:00
Refactoring bone transforms.
This commit is contained in:
parent
56797953c2
commit
dfe8e3b826
2
.gitignore
vendored
2
.gitignore
vendored
@ -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/*
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user