Skip to content

Go to a spot and stop on it (#825), stops planned on a footfall (#828), turning on the spot by steps (#827); aephysics b37fae2, Aether 0.835.0 - #831

Merged
nicolas-maman merged 10 commits into
mainfrom
feat/motion-goto
Oct 20, 2026
Merged

nicolas-maman merged 10 commits into
mainfrom
feat/motion-goto

Conversation

@nicolas-maman

@nicolas-maman nicolas-maman commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

The next slice of #825 (what a game's day asks of a figure): walking to a spot and stopping on it, facing a given way. It also turns on the spot by steps and stops on a footfall, the two locomotion defects going to a spot exposed (#827, #828).

locomotion.go_to(l, at, facing, running), with arrived, going_to and stop_going; set_input ends it too.

  • Arriving. Reynolds' arrive (1999): toward the spot at the speed it can still stop from in the distance left, braking at half its DECELERATION, so its own momentum brings it to rest there. Once there it stays until moved more than 0.3 m off. Steered again for every drift instead, the box man turned to face each correction and ended 104 degrees off.
  • Coming in along the facing. As a GTA scenario point's or an Unreal Smart Object slot's entry brings a character in: it heads for a point a metre back along the facing, then walks that line, so it arrives facing the way already. Turned on the spot at the end instead, its body was walked round its planted foot 0.26 m off the spot, and it circled the spot.

Stopping on a footfall (#828). Distance Matching's aim (Paragon, GDC 2016): a move ends on its mark with its feet where they land.

  • At attach, the walk's footfalls are read from the clip: the moments its lowest foot changes to the other.
  • The walk is paced to the body, so the distance to each coming footfall follows from the clip's phase. The stop is planned onto the footfall nearest the spot that it can still brake to, and it ends with both feet down.
  • Cut wherever the speed ran out instead, the walk ended mid-stride and ae3d.feet carried the lifted foot 8 cm low over the ground to the idle's place. Going to a spot behind it, a toe slid 82 mm; now 8.4.
  • A run brakes into the walk before its stop is planned: a run's step is long, and its footfall nearest the spot was 0.38 m off.

Keeping its gait. The walk and run swap only GAIT_BAND (0.15 m/s) past the middle of their speeds. Switched at the middle itself, a figure braking from a run changed clip every frame, each change a new blend, and a foot was flung up to its hips (18.3 m/s in a frame; 7.0 now).

Turning on the spot by steps (#827), opt-in with locomotion.set_turn_steps(l, true), for a figure on ae3d.feet. This is procedural legs' plant-and-step.

  • Turning on the spot, it plays its idle and turns at TURN_SPOT_RATE (2.5 rad/s, about a second and a quarter for a turn round).
  • The feet stay planted and step themselves round about every 45 degrees, as ae3d.feet steps a standing figure's feet.
  • Off, as before, the walk is played at a slow pace and held on its planted foot, which carries the body round it.

ae3d.feet, for every figure:

  • A foot's own step needs the body still where it stands: the clip's ankle still in the figure's own frame, and the root not going over the ground (turning in place counts as still). Measured in the world, a turning body moved every ankle and no foot stepped until the turn was over. Measured in the clip alone, a body carried over a held foot stepped it by itself (test_feet's carried foot caught it).
  • A step is over its place by 80% of its way (STEP_PLACE) before it is set down, as a foot reaches its place before it lands. Carried the whole way, a turning figure's foot came down still going 13 mm a frame.

Measured (tests/test_go_to.ae, the box man on ae3d.feet, to a spot 10 m off five ways):

arrived in off the spot toe slid in a plant, at the most
straight ahead 10.7 s 6.0 cm 4.1 mm
ahead, then turned a quarter 11.7 s 16.3 cm 5.0 mm
to its side 11.8 s 19.8 cm 7.7 mm
behind it 11.3 s 10.3 cm 8.4 mm
ahead at a run 5.6 s 7.8 cm 15.6 mm

Every case faces the way asked to the degree, no bone goes faster than 7 m/s in the figure's frame, and its toes move under 5 mm in the 1.5 s after it arrives. #825's bar is 5 mm of toe slide a plant. Walking straight there meets it. Setting off and turning while walking (#827) and braking a run (#828) still slide a toe further, and the test holds each case to what it slides now until those are fixed.

Tested locally: on aephysics f0bd6d6 and Aether 0.834.0, main's: the motion gate (34 suites) plus test_go_to, test_sit, test_lie, test_locomotion, test_characters_meet and test_physics all pass, 40 of 40. They passed 40 of 40 on aephysics b37fae2 and Aether 0.835.0 too, where all 252 programs compile without a warning at -O2.

Dependencies: unchanged, held. This PR moved to aephysics b37fae2 and Aether 0.835.0, then went back.

  • b37fae2 puts AVX2 code (its @target("avx2") copies of sat and contact_solver_wide) into every x86 build. GCC on Win64 cannot realign the stack to 32 bytes, so a function with an f32x8 local is an internal compiler error at -O0 (expand_one_stack_var_1, GCC 15.2 and 16.2 alike).
  • ae3d builds its suites at -O0, so every Windows suite that links aephysics failed to build.
  • The fix is Aether's codegen: aether#3023 (GCC bug 54412), being fixed in Aether PR #3019. The move waits for that release.
  • aephysics f0bd6d6 does not build on 0.835.0 (E0303), so both pins went back.
  • aether-ui went back with them to dcc1bd48. 6890549f, which 0.835 needs (E0305), warns -Wformat-truncation in its GTK4 backend (aether-ui#220), and the editor builds with warnings as errors.

Plaza scorecard against main: 20, 24 and 28 walkers, seeds 1 to 8, 60 s each, on aephysics f0bd6d6 and Aether 0.834 so the comparison is this change alone. Over seeds 5 to 8 (the confirm run):

main branch
knees backwards 0.28 s 0.08 s
figures inside each other 4.92 s 3.33 s
in the car 2.58 s 1.53 s
heads spinning 5.53 s 3.05 s
bodies walked through 1.40 s 0.52 s
toes skating, cm per walker-second 0.554 0.548
time toes skate faster than 0.2 m/s 76.4 s 68.2 s
legs splayed 2.58 s 3.37 s

Seeds 1 to 4 lean the same way, a little less clearly. Splay is the one that goes up. The scorecard now splits it into walking and struck figures (tools/plaza_showcase.ae), as it already did for knees and sinking. On the 18 seeds where both sides ran cleanly, walking splay is 1.07 s on main and 1.68 s on the branch (worse in 9, better in 6), out of about 26,000 walker-seconds. Struck figures' splay is 4.3 s against 6.5 s: those are ragdolls, which nothing here touches, struck at other moments because the walkers' paths changed. Eleven of that rerun's 48 runs failed, across six of its seed pairs, which are left out: ten could not start because the GPU was out of memory at the time (Vulkan init failed), and one stopped at 25 s. Every seed that ran in both batches gave the same numbers to the last digit, so the plaza is deterministic and the paired seeds compare fairly.

Part of #825, #827, #828 and #790.

…ing on the spot and the run's stop still slide
…foot's own step judged by the clip's motion in the root's frame
…Distance Matching's aim): behind it 82 mm to 8 mm, every walk arrives
…rom a run it changed clip every frame and flung a foot to its hips
…lking and struck

aephysics b37fae2 (#183) closes every open aephysics issue and needs Aether
0.835.0, which removes std's long names (aether#2976); ae3d itself calls none
of them. The plaza scorecard now says how much of its legs-splayed time was
struck figures', as it already did for knees and sinking: a change to how
figures walk moves which are struck, and with it the struck part.
…at -O0 on Win64

aephysics b37fae2 puts AVX2 code (its @target("avx2") copies of sat and
contact_solver_wide) into every x86 build. GCC on Win64 cannot realign the
stack to 32 bytes, so a function with an f32x8 local is an internal compiler
error at -O0 (expand_one_stack_var_1, GCC 15.2 and 16.2 alike). ae3d builds
its suites at -O0, and every Windows suite that links aephysics failed to
build. The fix is Aether's codegen; the move to b37fae2 and Aether 0.835.0
waits for the release that carries it. aephysics f0bd6d6 does not build on
0.835.0 (E0303), so both pins go back, and aether-ui with them to dcc1bd48
(6890549f warns -Wformat-truncation in its GTK4 backend).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant