[libgdx] Constraints only updateLocalTransform when necessary.

This commit is contained in:
Nathan Sweet 2025-04-20 01:02:55 -04:00
parent db69ea75ce
commit 913e694e22
7 changed files with 36 additions and 17 deletions

View File

@ -36,9 +36,6 @@ public class BoneLocal implements Pose<BoneLocal> {
float x, y, rotation, scaleX, scaleY, shearX, shearY; float x, y, rotation, scaleX, scaleY, shearX, shearY;
Inherit inherit; Inherit inherit;
BoneLocal () {
}
public void set (BoneLocal pose) { public void set (BoneLocal pose) {
if (pose == null) throw new IllegalArgumentException("pose cannot be null."); if (pose == null) throw new IllegalArgumentException("pose cannot be null.");
x = pose.x; x = pose.x;

View File

@ -16,9 +16,7 @@ public class BonePose extends BoneLocal implements Update {
float a, b, worldX; float a, b, worldX;
float c, d, worldY; float c, d, worldY;
int update; int update;
boolean localDirty;
BonePose () {
}
/** Called by {@link Skeleton#updateCache()} to compute the world transform, if needed. */ /** Called by {@link Skeleton#updateCache()} to compute the world transform, if needed. */
public void update (Skeleton skeleton, Physics physics) { public void update (Skeleton skeleton, Physics physics) {
@ -31,6 +29,7 @@ public class BonePose extends BoneLocal implements Update {
* Runtimes Guide. */ * Runtimes Guide. */
public void updateWorldTransform (Skeleton skeleton) { public void updateWorldTransform (Skeleton skeleton) {
update = skeleton.update; update = skeleton.update;
localDirty = false;
if (bone.parent == null) { // Root bone. if (bone.parent == null) { // Root bone.
float sx = skeleton.scaleX, sy = skeleton.scaleY; float sx = skeleton.scaleX, sy = skeleton.scaleY;
@ -140,6 +139,7 @@ public class BonePose extends BoneLocal implements Update {
* calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */ * calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */
public void updateLocalTransform (Skeleton skeleton) { public void updateLocalTransform (Skeleton skeleton) {
update = skeleton.update; update = skeleton.update;
localDirty = false;
if (bone.parent == null) { if (bone.parent == null) {
x = worldX - skeleton.x; x = worldX - skeleton.x;
@ -218,6 +218,12 @@ public class BonePose extends BoneLocal implements Update {
} }
} }
/** When true, the world transform has been modified and the local transform no longer matches. Call
* {@link #updateLocalTransform(Skeleton)} before using the local transform. */
public boolean isLocalDirty () {
return localDirty;
}
/** Part of the world transform matrix for the X axis. If changed, {@link #updateLocalTransform(Skeleton)} should be called. */ /** Part of the world transform matrix for the X axis. If changed, {@link #updateLocalTransform(Skeleton)} should be called. */
public float getA () { public float getA () {
return a; return a;

View File

@ -114,6 +114,7 @@ public class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkC
static public void apply (Skeleton skeleton, BonePose bone, float targetX, float targetY, boolean compress, boolean stretch, static public void apply (Skeleton skeleton, BonePose bone, float targetX, float targetY, boolean compress, boolean stretch,
boolean uniform, float alpha) { boolean uniform, float alpha) {
if (bone == null) throw new IllegalArgumentException("bone cannot be null."); if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
if (bone.localDirty) bone.updateLocalTransform(skeleton);
BonePose p = bone.bone.parent.applied; BonePose p = bone.bone.parent.applied;
float pa = p.a, pb = p.b, pc = p.c, pd = p.d; float pa = p.a, pb = p.b, pc = p.c, pd = p.d;
float rotationIK = -bone.shearX - bone.rotation, tx, ty; float rotationIK = -bone.shearX - bone.rotation, tx, ty;
@ -176,6 +177,8 @@ public class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkC
if (parent == null) throw new IllegalArgumentException("parent cannot be null."); if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
if (child == null) throw new IllegalArgumentException("child cannot be null."); if (child == null) throw new IllegalArgumentException("child cannot be null.");
if (parent.inherit != Inherit.normal || child.inherit != Inherit.normal) return; if (parent.inherit != Inherit.normal || child.inherit != Inherit.normal) return;
if (parent.localDirty) parent.updateLocalTransform(skeleton);
if (child.localDirty) child.updateLocalTransform(skeleton);
float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX;
int os1, os2, s2; int os1, os2, s2;
if (psx < 0) { if (psx < 0) {

View File

@ -196,7 +196,7 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
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.updateLocalTransform(skeleton); bone.localDirty = true;
bone.bone.resetUpdate(skeleton); bone.bone.resetUpdate(skeleton);
} }
} }

View File

@ -263,7 +263,7 @@ public class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsCons
tx = l * bone.a; tx = l * bone.a;
ty = l * bone.c; ty = l * bone.c;
} }
bone.updateLocalTransform(skeleton); bone.localDirty = true;
bone.bone.resetUpdate(skeleton); bone.bone.resetUpdate(skeleton);
} }

View File

@ -53,14 +53,25 @@ public class Slider extends Constraint<Slider, SliderData, SliderPose> {
public void update (Skeleton skeleton, Physics physics) { public void update (Skeleton skeleton, Physics physics) {
if (pose.mix == 0) return; if (pose.mix == 0) return;
SliderPose pose = applied;
data.animation.apply(skeleton, pose.time, pose.time, false, null, pose.mix, MixBlend.replace, MixDirection.in, true);
Timeline[] timelines = data.animation.timelines.items; Timeline[] timelines = data.animation.timelines.items;
int timelineCount = data.animation.timelines.size; int timelineCount = data.animation.timelines.size;
Bone[] bones = skeleton.bones.items; Bone[] bones = skeleton.bones.items;
for (int i = 0; i < timelineCount; i++) if (pose.mix == 1) {
if (timelines[i] instanceof BoneTimeline boneTimeline) bones[boneTimeline.getBoneIndex()].resetUpdate(skeleton); for (int i = 0; i < timelineCount; i++)
if (timelines[i] instanceof BoneTimeline timeline) bones[timeline.getBoneIndex()].resetUpdate(skeleton);
} else {
for (int i = 0; i < timelineCount; i++) {
if (timelines[i] instanceof BoneTimeline timeline) {
Bone bone = bones[timeline.getBoneIndex()];
bone.resetUpdate(skeleton);
if (bone.applied.localDirty) bone.applied.updateLocalTransform(skeleton);
}
}
}
SliderPose pose = applied;
data.animation.apply(skeleton, pose.time, pose.time, false, null, pose.mix, MixBlend.replace, MixDirection.in, true);
} }
void sort (Skeleton skeleton) { void sort (Skeleton skeleton) {
@ -68,7 +79,7 @@ public class Slider extends Constraint<Slider, SliderData, SliderPose> {
int timelineCount = data.animation.timelines.size; int timelineCount = data.animation.timelines.size;
Bone[] bones = skeleton.bones.items; Bone[] bones = skeleton.bones.items;
for (int i = 0; i < timelineCount; i++) for (int i = 0; i < timelineCount; i++)
if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone(bones[boneTimeline.getBoneIndex()]); if (timelines[i] instanceof BoneTimeline timeline) skeleton.sortBone(bones[timeline.getBoneIndex()]);
skeleton.updateCache.add(this); skeleton.updateCache.add(this);

View File

@ -68,16 +68,18 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
&& pose.mixShearY == 0) return; && pose.mixShearY == 0) return;
TransformConstraintData data = this.data; TransformConstraintData data = this.data;
boolean localFrom = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp; boolean localSource = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp;
BonePose source = this.source.applied; BonePose source = this.source.applied;
if (localSource && source.localDirty) source.updateLocalTransform(skeleton);
FromProperty[] fromItems = data.properties.items; FromProperty[] fromItems = data.properties.items;
int fn = data.properties.size; int fn = data.properties.size;
BonePose[] bones = this.bones.items; BonePose[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++) { for (int i = 0, n = this.bones.size; i < n; i++) {
BonePose bone = bones[i]; BonePose bone = bones[i];
if (localTarget && bone.localDirty) bone.updateLocalTransform(skeleton);
for (int f = 0; f < fn; f++) { for (int f = 0; f < fn; f++) {
FromProperty from = fromItems[f]; FromProperty from = fromItems[f];
float value = from.value(data, source, localFrom) - from.offset; float value = from.value(data, source, localSource) - from.offset;
ToProperty[] toItems = from.to.items; ToProperty[] toItems = from.to.items;
for (int t = 0, tn = from.to.size; t < tn; t++) { for (int t = 0, tn = from.to.size; t < tn; t++) {
ToProperty to = toItems[t]; ToProperty to = toItems[t];
@ -95,8 +97,8 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
} }
if (localTarget) if (localTarget)
bone.updateWorldTransform(skeleton); bone.updateWorldTransform(skeleton);
else else
bone.updateLocalTransform(skeleton); bone.localDirty = true;
bone.bone.resetUpdate(skeleton); bone.bone.resetUpdate(skeleton);
} }
} }