diff --git a/src/testmod/java/org/saturnclient/emotes/testmod/TestAnimations.java b/src/testmod/java/org/saturnclient/emotes/testmod/TestAnimations.java index ac2023b..3203423 100644 --- a/src/testmod/java/org/saturnclient/emotes/testmod/TestAnimations.java +++ b/src/testmod/java/org/saturnclient/emotes/testmod/TestAnimations.java @@ -72,8 +72,9 @@ final class TestAnimations { } /** - * Squatting with knees out, hips pushed back and the chest leaning forward, bouncing the hips - * about 2.5 times a second. The torso and knees bend with the bounce, so the back arches. + * Squatting with knees out and hips pushed back, bouncing the hips about 2.5 times a second. The + * 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) { // 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 knee = 1.75f - 0.3f * up; 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 // 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 back = -6 * (float) (Math.sin(thighPitch) + Math.sin(thighPitch + knee)); - BoneTransform shift = new BoneTransform(0, drop, back, 0, 0, 0, 0, 0); - // The arms ride on the chest, which would swing them back as it leans. Tilt them forward by a - // bit more than the lean so they hang down towards the knees, a little outside them. - float armPitch = -lean * 1.1f; + // The body pivots at the neck, so tipping it forward swings the hips back. Move the pivot so + // the hips stay on the legs. + float cos = (float) Math.cos(tilt); + 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() - .set(Bone.BODY, shift.withBend(lean, 0)) - .set(Bone.HEAD, new BoneTransform(0, drop, back, -lean * 0.5f, 0, 0, 0, 0)) - .set(Bone.RIGHT_ARM, new BoneTransform(0, drop, back, 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.BODY, new BoneTransform(0, bodyY, bodyZ, tilt, 0, 0, arch, (float) Math.PI)) + .set(Bone.HEAD, new BoneTransform(0, bodyY, bodyZ, headPitch, 0, 0, 0, 0)) + .set(Bone.RIGHT_ARM, new BoneTransform(0, shoulderY, shoulderZ, 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. .set(Bone.RIGHT_LEG, new BoneTransform(0, drop, back, thighPitch, 0, splay, knee, (float) Math.PI - 0.35f))