Bend limbs and the torso along a Bézier spine #2

Merged
selimaj-dev merged 3 commits from limb-bending into master 2026-09-26 18:10:27 +00:00
Showing only changes of commit 09cfd0cc10 - Show all commits
@@ -72,8 +72,9 @@ final class TestAnimations {
} }
/** /**
* Squatting with knees out, hips pushed back and the chest leaning forward, bouncing the hips * Squatting with knees out and hips pushed back, bouncing the hips about 2.5 times a second. The
* about 2.5 times a second. The torso and knees bend with the bounce, so the back arches. * torso tips forward around the hips and bends backwards, so the lower back arches in (not a
* hunched back) and the chest comes up. The arch deepens at the top of each bounce.
*/ */
private static Pose twerk(float t) { private static Pose twerk(float t) {
// 0 at the bottom of the bounce, 1 at the top. // 0 at the bottom of the bounce, 1 at the top.
@@ -82,22 +83,39 @@ final class TestAnimations {
float thighPitch = -1.1f + 0.15f * up; float thighPitch = -1.1f + 0.15f * up;
float knee = 1.75f - 0.3f * up; float knee = 1.75f - 0.3f * up;
float splay = 0.55f; float splay = 0.55f;
float lean = 1.25f - 0.2f * up; // How far the torso tips forward at the hips, and how much of that the arch takes back by the
// chest. The chest ends up leaning forward by tilt - arch.
float tilt = 1.4f;
float arch = 0.4f + 0.3f * up;
// Lower everything by as much as the bent legs got shorter, and push the hips back so the feet // Lower everything by as much as the bent legs got shorter, and push the hips back so the feet
// stay under where they were (a rigid thigh + shin approximation of the curved leg). // stay under where they were (a rigid thigh + shin approximation of the curved leg).
float drop = 12 - 6 * (float) (Math.cos(thighPitch) + Math.cos(thighPitch + knee)) * (float) Math.cos(splay); float drop = 12 - 6 * (float) (Math.cos(thighPitch) + Math.cos(thighPitch + knee)) * (float) Math.cos(splay);
float back = -6 * (float) (Math.sin(thighPitch) + Math.sin(thighPitch + knee)); float back = -6 * (float) (Math.sin(thighPitch) + Math.sin(thighPitch + knee));
BoneTransform shift = new BoneTransform(0, drop, back, 0, 0, 0, 0, 0); // The body pivots at the neck, so tipping it forward swings the hips back. Move the pivot so
// The arms ride on the chest, which would swing them back as it leans. Tilt them forward by a // the hips stay on the legs.
// bit more than the lean so they hang down towards the knees, a little outside them. float cos = (float) Math.cos(tilt);
float armPitch = -lean * 1.1f; float sin = (float) Math.sin(tilt);
float bodyY = drop + 12 - 12 * cos;
float bodyZ = back - 12 * sin;
// The head and arms only turn with the torso's bend, not its rotation, so they get the tilt
// themselves (tilt plus the bend's turn is the chest's lean) and sit where the tipped torso puts
// them: the neck at the body's pivot, the shoulders 2 pixels down it.
float chest = tilt - arch;
float shoulderY = bodyY + 2 * cos - 2;
float shoulderZ = bodyZ + 2 * sin;
// Arms riding on a leaning chest would swing back, so tilt them forward to hang to the knees.
float armPitch = tilt - chest * 1.1f;
// Follow the chest, then look up by half its lean.
float headPitch = tilt - chest * 0.5f;
return Pose.builder() return Pose.builder()
.set(Bone.BODY, shift.withBend(lean, 0)) .set(Bone.BODY, new BoneTransform(0, bodyY, bodyZ, tilt, 0, 0, arch, (float) Math.PI))
.set(Bone.HEAD, new BoneTransform(0, drop, back, -lean * 0.5f, 0, 0, 0, 0)) .set(Bone.HEAD, new BoneTransform(0, bodyY, bodyZ, headPitch, 0, 0, 0, 0))
.set(Bone.RIGHT_ARM, new BoneTransform(0, drop, back, armPitch, 0, 0.3f, 0.5f, 0)) .set(Bone.RIGHT_ARM, new BoneTransform(0, shoulderY, shoulderZ, armPitch, 0, 0.3f, 0.5f, 0))
.set(Bone.LEFT_ARM, new BoneTransform(0, drop, back, armPitch, 0, -0.3f, 0.5f, 0)) .set(Bone.LEFT_ARM, new BoneTransform(0, shoulderY, shoulderZ, armPitch, 0, -0.3f, 0.5f, 0))
// Knees fold back and a little inwards, so the thighs splay out and the feet come in. // Knees fold back and a little inwards, so the thighs splay out and the feet come in.
.set(Bone.RIGHT_LEG, new BoneTransform(0, drop, back, thighPitch, 0, splay, knee, .set(Bone.RIGHT_LEG, new BoneTransform(0, drop, back, thighPitch, 0, splay, knee,
(float) Math.PI - 0.35f)) (float) Math.PI - 0.35f))