flutter3d_physics 0.8.1
flutter3d_physics: ^0.8.1 copied to clipboard
Collision shapes, a broadphase, queries, a character controller and an XPBD cloth solver. No Flutter, no renderer, no game.
0.8.1 #
- A sheet resists shear.
ClothMesh.gridbuilt edges along rows and columns and nothing across a quad, so every quad could fold flat into a rhombus. A square sheet dropped on a ball stretched its corners into strands that reached the floor, and what lay on the floor spread into a blot with no straight edge. The grid now carries both diagonals of every quad asClothMesh.shearPairs, solved withClothSettings.shearCompliance(5e-2 by default, soft enough that the sheet still follows a sphere). AClothMeshbuilt by hand without them shears as it did. - A sheet no longer passes through itself. Nothing kept one part of a
sheet out of another, so a square dropped on a ball folded its corners
under itself on the floor and the two layers ran into each other, drawn as
a flat grey triangle and flickering patches. Each particle is now a sphere
of
ClothSettings.selfCollisionThickness(the mesh's mean rest edge by default) that the others are pushed out of inside the iteration loop, except those already that close in the rest shape, whichClothMesh.restPositionskeeps. The close pairs come from a spatial hash and are gathered again only once a particle has moved half a skin, so on an 80×80 sheet at 12 substeps and 4 iterations a step costs 7 to 9% more (33.6 to 35.9 ms falling, 37.4 to 40.6 folded). On by default;ClothSettings.selfCollision: falseturns it off.
0.8.0 #
Moves with the stack to 0.8.0, whose flutter3d_hardware changes
PassEncoder.bindTexture to return bool and makes every backend forget its
bindings at bindPipeline. Nothing in this package changed.
Its flutter3d_* dependencies ask for ^0.8.0.
0.7.4 #
- Cloth meets a sphere and a capsule as themselves. Every obstacle pushed a
particle out through its
expandedPlanes, which is exact for a box and a wedge and the bounding cube for a sphere and a capsule: a sheet dropped on a ball draped over a box. A heightfield answered no planes at all, and the plane walk pushed by nought times infinity — every particle NaN.pushParticleOutsideis new and answers per shape, in doubles; a sphere and a capsule are their nearest surface point, a heightfield the ground under the particle.pushOutsideObstaclekeeps its signature. - A draped sheet no longer blows up. Contacts were resolved once after the
constraint sweep, and with
iterations: 1a sheet wrapped round a ball pumped itself from half a metre a second to NaN in about thirty steps — with or without wind. Contacts are solved inside the iteration loop now, as XPBD and Flex do, anditerationsdefaults to 2. - Wind is a force, relative to the cloth. It was added to a position as a
velocity — several hundred times its value at eight substeps, and growing
with the substep count — and ignored the cloth's own velocity, so a sheet in
a one-metre-a-second wind reached forty. It is
Δx = F·w·h²on the air's velocity relative to each triangle, bounded so a drag cannot reverse it in a substep. A scene tuned against the old wind needs adragin the ones where it had tenths. ClothSettings.friction, new: position-level Coulomb friction against obstacles, measured against a particle's push summed over the substep's iterations, so the iteration count does not decide how much it holds. Zero, the default, slides as before.- A heightfield obstacle holds cloth only over its own footprint. Past the edge its height is the edge's, which a body walking off the map wants and a hem hanging over the side would catch on.
dampingsays what it does: a fraction per substep, which it always was, not per step.- A particle is no longer rounded to single precision through a
Vector3for every obstacle, and the solver allocates nothing per substep.
0.7.1 #
Released with the rest of the stack at 0.7.1. Nothing in this package changed. The release it resolves against builds from pub.dev again and no longer crashes Metal on the first unlit draw.
Its flutter3d_* dependencies ask for ^0.7.1, and it asks for vector_math ^2.4.3.
0.7.0 #
Breaking. Accepted flutter3d_cloth, because a package that only ever
reacted to this one's own CollisionShapes and depended on nothing else had
no boundary left to justify standing apart — an XPBD solver, not a second
layer of physics. ClothMesh, ClothSettings, ClothObstacle,
pushOutsideObstacle and stepCloth now live under src/cloth/ and export
through this package's own barrel; flutter3d_cloth itself is gone from the
workspace. It was never published, so there is nothing to discontinue on
pub.dev.
What that is, for a reader who never saw the other package.
stepCloth(mesh, settings, dt, obstacles:) advances a ClothMesh in place by
ClothSettings.substeps XPBD substeps, 8 by default: gravity, WindSettings
and damping go into a predicted position, the structural and bending
constraints are solved against it with multipliers reset each substep, and
particles are pushed out of each ClothObstacle. ClothMesh.grid builds a
rectangular sheet. An obstacle is a CollisionShape and a position, tested
through expandedPlanes, which is right for a box, a sphere, a capsule and a
wedge and gives a CollisionHeightfield its bounding box and not its surface.
Every loop walks a typed array by index, so the same state, settings and dt
give the same output.
Nothing else moved. Shapes, the broadphase, queries and the character
controller are byte for byte 0.6.0's, and the package still depends on
vector_math and no sibling. The archive carries a skill for a coding agent,
skills/flutter3d-physics-walking-and-queries/, installed with
dart run skills@ get.
0.6.0 #
- No code, and no floor to move.
lib/is byte for byte 0.5.1's — the heightfield collision shape that arrived there is unchanged — and this package depends on no sibling, so nothing in its pubspec had to follow the set. It takes the set's number becauseflutter3d_simand both games above it now floor at^0.6.0, and a floor is only worth stating if it names a combination that was built. - Nothing added to the sealed hierarchy of collision shapes, so nothing
downstream has a new
switcharm to write.
0.5.1 #
Ground is a collision shape, and the joins in it are not surfaces.
CollisionHeightfield. A field of samples a body walks on: the fifth shape, and the first that is not one convex solid. It comes in throughCollisionShape.partsIn, which hands a query the convex pieces near it — one prism per triangle — so every sweep, push and ray is the closed-form plane walk the world already had, several times over. A sweep against ground costs four times a sweep against a brush and a step of a walking body nearly seven;tool/ground_cost.dartis the measurement.CollisionShape.partSeams, which is what makes it walkable. Where two triangles meet, each prism ends in a vertical face the other continues through. Reported, it is a wall nobody drew and a body that catches on the ground every metre. The shape names those faces andCollisionWorldrefuses a contact on one.- A sweep's normal is no longer always an axis. It stopped being one when
the wedge arrived and the documentation had not caught up; ground makes it
the ordinary case. Comparing
normal.yagainst a walkable limit is still right, and treating the vector as an axis and a sign is not. - A capsule is swept as a capsule. Growth is now the moving shape's own support function rather than the box around it, so a walking body no longer catches a shoulder on a corner it should round. Against the six faces of a box the two answers are identical, so nothing in a level of brushes moved.
- Depenetration splits its push into components. The deepest push in each of six directions is what stops a body on a seam being lifted twice, and it used to file a slanted normal's whole depth under one axis — so a body on a ramp was lifted short of the way out, every step, for as long as it stood there.
contactBetweenknows about ground, because the bounding-box fallback for a field of samples is the size of the map: every crate on the level would have been reported a hundred metres deep inside one solid.
0.5.0 #
Breaking. The contact filter takes one object.
ContactFilterisbool Function(SweptContact). A function type is frozen the day it is published, so telling a filter the contact point or how far along the sweep it happened would have broken every filter anybody had written.tool/filter_cost.dartsays what it cost: 1.932 microseconds a step became 1.953, and thelate-field version that would have cost 1.997 is what the object avoids. The number is written into the benchmark beside it.CharacterController.groundNormal. The probe that decides whether a body is standing on something reads a normal to do it and discarded it, so a caller that wanted to know which way the floor tilts had to sweep again for what this had just measured. Straight up while airborne rather than null, so arithmetic on it needs no branch.
0.4.0 #
- No changes of its own; the version moves with the workspace, whose sibling constraints name a single release. The README's closing section now says what the engine around this package is.
0.3.0 #
- No changes of its own. The workspace is released as a set, in the order
ARCHITECTURE.md§16 gives, so this package's version moves with the rest and its constraints on its siblings move with it.
0.2.0 #
- Collision shapes, a broadphase grid, ray and overlap queries, and a capsule character controller that walks slopes, steps and ramps.
- Rigid bodies with mass, gravity, impulses, pushing and rest — no rotation yet, and the character controller stays kinematic on purpose.
- No Flutter and no renderer in it, which is the boundary the package exists to
keep: it runs under
dart test.