Pushed balls and barrels roll, then stop, and a barrel the player walks into starts rolling as they meet it #27

Merged
agra merged 8 commits from task/3980-balls-and-barrels-never-stop-rolling-not into master 2026-10-30 20:02:52 +02:00
Owner

Tracker: #3980

Contacts now resist a body turning on what it rests on, as Box2D v3's rollingResistance does: an angular impulse that stops the two bodies' relative spin, bounded by a rolling resistance times the radius rolled on times the contact's normal impulse. It is warm-started and solved in the relax pass between the normal impulses and the friction. Box2D resists only the roll, the one axis a plane has; this also resists the spin about the normal, or a ball stopped from rolling whirls in place and never sleeps. The first map's barrels weigh 20 kg, so a player walking into one sets it rolling at once.

  • Every body's material carries rollingResistance, by default ROLLING_RESISTANCE, 0.15. Blender's rigid bodies have no such setting, so the bake has nothing to read and the default applies. 0.15 is a hard ball's or wheel's on grass, which is the first map's ground. A body that stops on ground flatter than 8.5° stays there, and on steeper ground it rolls down.
  • A body on the map is resisted by its own coefficient times the radius it rolls on there. Two bodies are resisted by the greater coefficient times the greater of the radii they roll on. A Sphere and a Capsule roll on their radius about every axis, and so does a Cylinder where its side touches, its axis square to the contact's normal within PARALLEL (sin 2.9°, the tolerance by which the contacts judge a cylinder's side parallel to a segment). On its rim, between that and its cap lying flat (its axis along the normal as closely), a Cylinder rolls on its radius about its own axis alone: the contact resists the two bodies' relative spin along that axis only, so the cylinder still rolls to a stop on its rims and tips about its rim freely. Lying flat on its cap it rolls on none, as a Box and a Convex Hull do, so crates, stacks and players' pushes are untouched. Where one of two bodies touches by its rim, the contact resists the spin about that body's axis; two touching by their rims resist the spin about their axes when those are parallel, and none when they cross.
  • The barrels' Cylinder bodies weigh 20 kg, down from 60, set in first_map.blend and in first_map_bodies.py's masses. In a dump of every RNA property of the .blend, before and after, only the five barrels' rigid_body.mass differs. The bake's render file is byte-identical, and its world file differs in exactly the five barrels' mass bytes.

Two of the task's bounds, and its clause on starting a barrel, could not all hold. This PR makes these choices:

  • Rolling resistance 0.15, not the 0.047 a 2.5 m roll from 2 m/s needs. Rolling slows a barrel at two thirds of c g whatever its mass. "A barrel given 2 m/s rolls at least 2.5 m" needs c of at most 0.047. "It rests within 8 m of where the walking player stopped" needs at least 0.135. At 0.04, barrel 11 given 4 m/s on the clearing still rolls 135 m downhill in 30 s, and 71% of the ground within 40 m of the props is steeper than atan 0.04. So the bound is now "rolls farther than the same body would slide": 0.92 m, against 0.41 m sliding.
  • Lighter barrels, not a stronger push. The server moves the player against where the tick found each body, then steps the physics with the player's capsule pushing at most 500 N. So on each tick of a push the player advances only as far as the body moved the tick before, and a body at rest moves F dt² / 2m on its first tick. Keeping the player at 2 m/s from the first tick would take 14 kN against a 60 kg barrel. A 20 kg barrel at 500 N passes 3.6 m/s 0.17 s after the player meets it. A stronger push would also slide crates up to about 300 kg, which the 110 kg crate case holds against. The player is under 2 m/s for the first 7 ticks (0.12 s) of the push, at least 0.21 m/s, so the clause "the player keeps at least 2 m/s at every tick" is dropped.

Measured with the first map's barrel and cannon ball and their baked damping, on level ground of 2 m cells:

  • Given 4 m/s, the barrel comes to rest 3.5 m on and the ball 3.7 m on; both sleep by 3.0 s. At 5af4834 they are 20.1 and 21.7 m on after 10 s, still rolling.
  • Given 2 m/s, the barrel rolls 0.92 m. A box at that friction slides 0.41 m.
  • Released on a 10° slope, undamped, both roll down and gain speed. After 4 s the barrel is at 0.69 m/s, against two thirds of g (sin 10° − c cos 10°) × 4 s = 0.68, and the ball is at 0.75 m/s, against five sevenths of it, 0.73.
  • The player walks at 4 m/s into the barrel lying across the walk. The barrel passes 3.6 m/s 0.17 s after they first meet; at 5af4834 it takes 0.65 s. The player walks on into it for 3 s and stops, and the barrel rests 7.4 m from where they stopped; at 5af4834 it rests 19.2 m away.
  • On the first map, in the task's probe, the player meets barrel 11 on tick 21. The barrel passes 3.6 m/s 10 ticks later (47 at 60 kg). It rests 8.8 m from where the player stopped (9.4 m at 60 kg), because the ground falls away past the clearing.
  • A barrel set on its rim tips over. Tilted to its balance ± 0.01 to ± 0.12 rad on level ground, it falls back onto its end short of its balance and onto its side past it; resisted about every axis on its rim, it stayed balanced from −0.11 to +0.11 rad. Of 200 barrels dropped 0.3–2.5 m with random turns and spins onto level ground, none rests tilted, against 18 on their rim with the rim resisted about every axis.
  • A barrel lying across a level gully touches its two sides by its rims and rolls on them. Given 2 m/s or 4 m/s along a gully whose sides rise 0°, 1°, 2°, 2.8°, 3.5°, 4°, 6°, 10° or 20°, the first map's barrel with its damping rests 0.92–0.94 m or 3.40–3.53 m on and sleeps within 1.9 s and 3.1 s, as on level ground (0.92 m and 3.51 m). With its rims rolling on none, as at 3af784a, from 3.5° up it rolled on to the gully's end.
  • A barrel tilted past its balance on a 5000 kg log of radius 1.5 m lying on the map falls onto its side. At 3af784a, where the log's side made the contact resist every axis by the log's radius, it stayed on its rim.
  • Lying barrels on the first map's terrain roll to rest across its creases. Over 150 barrels laid on random spots of the terrain within 5.7° of level and given 4 m/s across their axes, they rest 4.36 m on on average, all 150 asleep within 30 s; at 3af784a, whose rims rolled on none, 4.39 m, 149 asleep.
  • Physics bench, built and run under taskpolicy -b, three rounds each, interleaved: worst tick 0.49–0.50 ms, median 0.13 ms, against 0.50–0.51 ms and 0.42 ms at master 2f937ab. The dummies' capsules sleep sooner. In full gate run 993 at this head, which passed all 44 tests: worst tick 0.50 ms, median 0.13 ms.

This merges master 2f937ab, #3935's skeleton dummies. first_map.blend.md conflicted on its Props and Dummies lines; it keeps master's Dummies line and this branch's 20 kg Props line. Master did not change first_map.blend, so it merges as this branch's. tests/dummy_draws.sx's free skeleton falls for 240 ticks, its 12 capsules now resisted rolling, and settles in another pose: as before, on its side with its head to the right, its limbs placed a little differently. Its golden, tests/pixels/dummy-metal.png, is regenerated, and no other golden changes.

What else moves, by a diff of every figure the physics and sim tests print against master 2f937ab: only round bodies' figures change, each within its bound. physics_stack, physics_contacts, physics_queries, physics_shapes, physics_determinism, solids and sim_bodies print the same figures, and the slides and bounces are unchanged. Against 3af784a, rolling on the rims about the cylinder's axis moves only barrels.sx's figures: the valleys, the barrel on the crate (its axis at −0.000063 against −0.000114) and the barrel whirled on its rim (2.36 mm deep against 2.52 mm); the other thirteen physics and sim tests print the same figures, and dummy-metal.png does not move again.

  • The hung dummy sleeps at 0.63 s, against 0.98 s; walked into, it swings its pelvis 0.574 m (0.572 m) and sleeps again 9.98 s after (9.95 s).
  • In the bench scene, the deepest body is 7.4 mm, as at master, and the joints pass their limits by 3.54°, against 5.50°.
  • The chain over the crate passes its limits by 1.14–1.30°, against 1.24–1.78°.

Tests:

  • tests/barrels.sx and tests/physics_bodies.sx check rolling by its arithmetic with the rolling resistance: slipping, then rolling to rest, and rolling down slopes. They also check that a ball spun in place stops, and that a ball rolling on another body slows as it does on the map. barrels.sx gives the barrel and the cannon ball 4 m/s each, and releases each on the 10° slope.
  • barrels.sx tilts a standing barrel 0.05 rad short of its balance, and one 0.05 rad past it standing on its other end; the first falls back onto its end and the second onto its side. It tilts a barrel 0.05 rad past its balance on a 200 kg crate and on a log lying on the map, and it falls onto its side on each. A barrel lying across a valley whose sides rise 2°, 4° or 10°, touching each by its rim, rolls along it and comes to rest where rolling takes it on level ground. Two barrels whose rims touch corner to corner resist each other's turning by c r about their common axis when their axes are parallel, and resist none when they cross.
  • barrels.sx lays a barrel on its side, where its contact resists every axis, and pivots it up about one end's rim, so that the rim presses on the ground as it rises. The contact on its rim, which carries the side's rolling impulse from the tick before (both are its contact with the same triangle), holds its rolling impulse along the barrel's axis.
  • physics_bodies.sx rolls a ball along a slab, along a wide disc lying flat on its cap, and along the top of a log lying on its side, each resting on the map; it slows at 5/7 c g times the greater of the two radii over its own.
  • tests/sim_push.sx walks the player into the first map's barrel, as the bake reads it. The barrel must pass nine tenths of the walking speed within 0.3 s of first contact, and must come to rest within 8 m of where the player stops.
  • At 5af4834 the 4 m/s, slope, start and walk cases fail. The start case also fails at this branch's first commit, whose barrels still weigh 60 kg (0.78 s). At a0bc735, before the rim rule, the tilted standing barrels and the barrel on the crate stay on their rims and fail. At 3af784a, whose rims rolled on none, the barrels across the 4° and 10° valleys roll 3.18 m on, not asleep, against 0.96 m, and the barrel on the log stays on its rim.
  • Mutants of the rim rule, each failing barrels.sx or physics_bodies.sx: the rim rolling on none (3af784a's rule) or on its radius about every axis (a0bc735's); the solve resisting every axis whatever the contact's axis; the map's or the pair's contact dropping the axis; the cap rolling on its radius about its axis or about every axis; the pair taking the greater radius's axis and, on a tie, the side's; the pair taking A's axis alone; two rims taking A's axis, or rolling on none when parallel; the pair taking the lesser radius; the side never judged, or judged within 0.7 or without the absolute value; the axis taken along local X; and no rolling solve. The rim's stop keeping the part of its carried impulse off the axis fails the pivoted barrel's case, up to 0.029 N·m·s off the axis over its 37 ticks on the rim: every substep's warm start applies that part again, so for as long as the rim presses it holds the barrel against tipping about the rim. These survive, each rolling every case as the head does: the side judged within 0.01 rather than PARALLEL, and the cap within 0.3, since a cylinder on its rim and one on its side or its cap roll alike in every case here; and the rim's stop computed from the whole turning mass and then projected on the axis. On the map that is the same stop, since the cylinder's axis is a principal axis of its inertia; between two bodies it differs a little, since the axis need not be a principal axis of the other body's.
Tracker: [#3980](https://sak.swipelab.com/tasks/3980) Contacts now resist a body turning on what it rests on, as Box2D v3's `rollingResistance` does: an angular impulse that stops the two bodies' relative spin, bounded by a rolling resistance times the radius rolled on times the contact's normal impulse. It is warm-started and solved in the relax pass between the normal impulses and the friction. Box2D resists only the roll, the one axis a plane has; this also resists the spin about the normal, or a ball stopped from rolling whirls in place and never sleeps. The first map's barrels weigh 20 kg, so a player walking into one sets it rolling at once. - Every body's material carries `rollingResistance`, by default `ROLLING_RESISTANCE`, 0.15. Blender's rigid bodies have no such setting, so the bake has nothing to read and the default applies. 0.15 is a hard ball's or wheel's on grass, which is the first map's ground. A body that stops on ground flatter than 8.5° stays there, and on steeper ground it rolls down. - A body on the map is resisted by its own coefficient times the radius it rolls on there. Two bodies are resisted by the greater coefficient times the greater of the radii they roll on. A Sphere and a Capsule roll on their radius about every axis, and so does a Cylinder where its side touches, its axis square to the contact's normal within `PARALLEL` (sin 2.9°, the tolerance by which the contacts judge a cylinder's side parallel to a segment). On its rim, between that and its cap lying flat (its axis along the normal as closely), a Cylinder rolls on its radius about its own axis alone: the contact resists the two bodies' relative spin along that axis only, so the cylinder still rolls to a stop on its rims and tips about its rim freely. Lying flat on its cap it rolls on none, as a Box and a Convex Hull do, so crates, stacks and players' pushes are untouched. Where one of two bodies touches by its rim, the contact resists the spin about that body's axis; two touching by their rims resist the spin about their axes when those are parallel, and none when they cross. - The barrels' Cylinder bodies weigh 20 kg, down from 60, set in `first_map.blend` and in `first_map_bodies.py`'s masses. In a dump of every RNA property of the `.blend`, before and after, only the five barrels' `rigid_body.mass` differs. The bake's render file is byte-identical, and its world file differs in exactly the five barrels' mass bytes. Two of the task's bounds, and its clause on starting a barrel, could not all hold. This PR makes these choices: - **Rolling resistance 0.15, not the 0.047 a 2.5 m roll from 2 m/s needs.** Rolling slows a barrel at two thirds of c g whatever its mass. "A barrel given 2 m/s rolls at least 2.5 m" needs c of at most 0.047. "It rests within 8 m of where the walking player stopped" needs at least 0.135. At 0.04, barrel 11 given 4 m/s on the clearing still rolls 135 m downhill in 30 s, and 71% of the ground within 40 m of the props is steeper than atan 0.04. So the bound is now "rolls farther than the same body would slide": 0.92 m, against 0.41 m sliding. - **Lighter barrels, not a stronger push.** The server moves the player against where the tick found each body, then steps the physics with the player's capsule pushing at most 500 N. So on each tick of a push the player advances only as far as the body moved the tick before, and a body at rest moves F dt² / 2m on its first tick. Keeping the player at 2 m/s from the first tick would take 14 kN against a 60 kg barrel. A 20 kg barrel at 500 N passes 3.6 m/s 0.17 s after the player meets it. A stronger push would also slide crates up to about 300 kg, which the 110 kg crate case holds against. The player is under 2 m/s for the first 7 ticks (0.12 s) of the push, at least 0.21 m/s, so the clause "the player keeps at least 2 m/s at every tick" is dropped. Measured with the first map's barrel and cannon ball and their baked damping, on level ground of 2 m cells: - Given 4 m/s, the barrel comes to rest 3.5 m on and the ball 3.7 m on; both sleep by 3.0 s. At 5af4834 they are 20.1 and 21.7 m on after 10 s, still rolling. - Given 2 m/s, the barrel rolls 0.92 m. A box at that friction slides 0.41 m. - Released on a 10° slope, undamped, both roll down and gain speed. After 4 s the barrel is at 0.69 m/s, against two thirds of g (sin 10° − c cos 10°) × 4 s = 0.68, and the ball is at 0.75 m/s, against five sevenths of it, 0.73. - The player walks at 4 m/s into the barrel lying across the walk. The barrel passes 3.6 m/s 0.17 s after they first meet; at 5af4834 it takes 0.65 s. The player walks on into it for 3 s and stops, and the barrel rests 7.4 m from where they stopped; at 5af4834 it rests 19.2 m away. - On the first map, in the task's probe, the player meets barrel 11 on tick 21. The barrel passes 3.6 m/s 10 ticks later (47 at 60 kg). It rests 8.8 m from where the player stopped (9.4 m at 60 kg), because the ground falls away past the clearing. - A barrel set on its rim tips over. Tilted to its balance ± 0.01 to ± 0.12 rad on level ground, it falls back onto its end short of its balance and onto its side past it; resisted about every axis on its rim, it stayed balanced from −0.11 to +0.11 rad. Of 200 barrels dropped 0.3–2.5 m with random turns and spins onto level ground, none rests tilted, against 18 on their rim with the rim resisted about every axis. - A barrel lying across a level gully touches its two sides by its rims and rolls on them. Given 2 m/s or 4 m/s along a gully whose sides rise 0°, 1°, 2°, 2.8°, 3.5°, 4°, 6°, 10° or 20°, the first map's barrel with its damping rests 0.92–0.94 m or 3.40–3.53 m on and sleeps within 1.9 s and 3.1 s, as on level ground (0.92 m and 3.51 m). With its rims rolling on none, as at 3af784a, from 3.5° up it rolled on to the gully's end. - A barrel tilted past its balance on a 5000 kg log of radius 1.5 m lying on the map falls onto its side. At 3af784a, where the log's side made the contact resist every axis by the log's radius, it stayed on its rim. - Lying barrels on the first map's terrain roll to rest across its creases. Over 150 barrels laid on random spots of the terrain within 5.7° of level and given 4 m/s across their axes, they rest 4.36 m on on average, all 150 asleep within 30 s; at 3af784a, whose rims rolled on none, 4.39 m, 149 asleep. - Physics bench, built and run under `taskpolicy -b`, three rounds each, interleaved: worst tick 0.49–0.50 ms, median 0.13 ms, against 0.50–0.51 ms and 0.42 ms at master 2f937ab. The dummies' capsules sleep sooner. In full gate run 993 at this head, which passed all 44 tests: worst tick 0.50 ms, median 0.13 ms. This merges master 2f937ab, #3935's skeleton dummies. `first_map.blend.md` conflicted on its Props and Dummies lines; it keeps master's Dummies line and this branch's 20 kg Props line. Master did not change `first_map.blend`, so it merges as this branch's. `tests/dummy_draws.sx`'s free skeleton falls for 240 ticks, its 12 capsules now resisted rolling, and settles in another pose: as before, on its side with its head to the right, its limbs placed a little differently. Its golden, `tests/pixels/dummy-metal.png`, is regenerated, and no other golden changes. What else moves, by a diff of every figure the physics and sim tests print against master 2f937ab: only round bodies' figures change, each within its bound. physics_stack, physics_contacts, physics_queries, physics_shapes, physics_determinism, solids and sim_bodies print the same figures, and the slides and bounces are unchanged. Against 3af784a, rolling on the rims about the cylinder's axis moves only `barrels.sx`'s figures: the valleys, the barrel on the crate (its axis at −0.000063 against −0.000114) and the barrel whirled on its rim (2.36 mm deep against 2.52 mm); the other thirteen physics and sim tests print the same figures, and `dummy-metal.png` does not move again. - The hung dummy sleeps at 0.63 s, against 0.98 s; walked into, it swings its pelvis 0.574 m (0.572 m) and sleeps again 9.98 s after (9.95 s). - In the bench scene, the deepest body is 7.4 mm, as at master, and the joints pass their limits by 3.54°, against 5.50°. - The chain over the crate passes its limits by 1.14–1.30°, against 1.24–1.78°. Tests: - `tests/barrels.sx` and `tests/physics_bodies.sx` check rolling by its arithmetic with the rolling resistance: slipping, then rolling to rest, and rolling down slopes. They also check that a ball spun in place stops, and that a ball rolling on another body slows as it does on the map. `barrels.sx` gives the barrel and the cannon ball 4 m/s each, and releases each on the 10° slope. - `barrels.sx` tilts a standing barrel 0.05 rad short of its balance, and one 0.05 rad past it standing on its other end; the first falls back onto its end and the second onto its side. It tilts a barrel 0.05 rad past its balance on a 200 kg crate and on a log lying on the map, and it falls onto its side on each. A barrel lying across a valley whose sides rise 2°, 4° or 10°, touching each by its rim, rolls along it and comes to rest where rolling takes it on level ground. Two barrels whose rims touch corner to corner resist each other's turning by c r about their common axis when their axes are parallel, and resist none when they cross. - `barrels.sx` lays a barrel on its side, where its contact resists every axis, and pivots it up about one end's rim, so that the rim presses on the ground as it rises. The contact on its rim, which carries the side's rolling impulse from the tick before (both are its contact with the same triangle), holds its rolling impulse along the barrel's axis. - `physics_bodies.sx` rolls a ball along a slab, along a wide disc lying flat on its cap, and along the top of a log lying on its side, each resting on the map; it slows at 5/7 c g times the greater of the two radii over its own. - `tests/sim_push.sx` walks the player into the first map's barrel, as the bake reads it. The barrel must pass nine tenths of the walking speed within 0.3 s of first contact, and must come to rest within 8 m of where the player stops. - At 5af4834 the 4 m/s, slope, start and walk cases fail. The start case also fails at this branch's first commit, whose barrels still weigh 60 kg (0.78 s). At a0bc735, before the rim rule, the tilted standing barrels and the barrel on the crate stay on their rims and fail. At 3af784a, whose rims rolled on none, the barrels across the 4° and 10° valleys roll 3.18 m on, not asleep, against 0.96 m, and the barrel on the log stays on its rim. - Mutants of the rim rule, each failing `barrels.sx` or `physics_bodies.sx`: the rim rolling on none (3af784a's rule) or on its radius about every axis (a0bc735's); the solve resisting every axis whatever the contact's axis; the map's or the pair's contact dropping the axis; the cap rolling on its radius about its axis or about every axis; the pair taking the greater radius's axis and, on a tie, the side's; the pair taking A's axis alone; two rims taking A's axis, or rolling on none when parallel; the pair taking the lesser radius; the side never judged, or judged within 0.7 or without the absolute value; the axis taken along local X; and no rolling solve. The rim's stop keeping the part of its carried impulse off the axis fails the pivoted barrel's case, up to 0.029 N·m·s off the axis over its 37 ticks on the rim: every substep's warm start applies that part again, so for as long as the rim presses it holds the barrel against tipping about the rim. These survive, each rolling every case as the head does: the side judged within 0.01 rather than `PARALLEL`, and the cap within 0.3, since a cylinder on its rim and one on its side or its cap roll alike in every case here; and the rim's stop computed from the whole turning mass and then projected on the axis. On the map that is the same stop, since the cylinder's axis is a principal axis of its inertia; between two bodies it differs a little, since the axis need not be a principal axis of the other body's.
A contact's angular impulse stops the two bodies' relative spin, bounded by the greater rolling resistance times the greater radius times its normal impulse, warm-started and solved between the normal impulses and the friction, as Box2D v3's rolling resistance is, about the normal too. Every body takes ROLLING_RESISTANCE, 0.15, since Blender's rigid bodies carry none; a Box and a Convex Hull have no radius and are not resisted.
agra changed title from Round bodies meet a rolling resistance, so pushed balls and barrels roll, then stop to Pushed balls and barrels roll, then stop, and a barrel the player walks into starts rolling as they meet it 2026-10-30 18:30:12 +02:00
A player's push moves a body at rest at most 500 N, and the player advances each tick only as far as the body moved the tick before, so a 60 kg barrel held them under 1 m/s for a third of a second and reached 3.6 m/s only 0.65 s after they met it. At 20 kg it passes 3.6 m/s 0.17 s after. sim_push's barrel is the first map's, as the bake reads it.
The README says a pushed ball or barrel comes to rest.
agra merged commit 429d5d7a23 into master 2026-10-30 20:02:52 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sx/hulken!27
No description provided.