Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commite8beb5604c

README.md

sim.particles (procNode)

The particle solver: every particle from every source wired in, held on the GPU and stepped over the graph's timeline, born, pushed by the forces, moved, bounced off the colliders and aged until it dies. It is built on the runtime's g:state and g:step and steps at a fixed 1/60 s, so the result at a frame depends on the frames cooked before it in the same node cache (a Generator's play, or proc.eval called frame after frame with one nodeCache).

Every particle from every source lives in one set of device columns at the solver's capacity, a slot per particle for its life. At each step the free slots are numbered and handed to the sources in order, and a free slot whose number a source owns is born from it with draws keyed by the source's seed and its birth serial; the forces are fields evaluated where each particle stands; velocity takes the forces, gravity and drag, then position moves; the move is met against the shape table of the colliders (which starts with one plane too far below to be reached, so it is never empty), and a hit pushes the particle out with bounce and friction; age and life advance, and a particle whose lifetime is up dies. A source whose points move between presents births along the path they travelled, by perMeter for the distance and at each step's place in the present (sim.spawn).

Inputs

  • sources (List<Record>): the sim.spawn records particles are born from, all in one solver. Each names the stream its particles carry.
  • forces (List<Record>, default empty): the sim.force records that push the particles; they sum.
  • colliders (List<Record>, default empty): the sim.collider and sim.scene_colliders records the particles bounce off.
  • capacity (Float, default 10000, min 1): the most particles alive at once. A birth past it is dropped.
  • gravity (Vec3, default (0, 0, 0)): an acceleration every particle takes beside the forces, in m/s^2.
  • drag (Float, default 0, min 0): the share of its velocity a particle loses per second.
  • seed (Float, default 0): which of the possible sequences of births every source makes.
  • trails (Bool, default false): on, each particle remembers where it has been, and the trails output holds a curve through its last trailLength positions; off, nothing is remembered and trails is empty.
  • trailLength (Float, default 16, 2 to 512): how many positions each particle remembers while trails is on, one for each fixed step, newest first.

Outputs

A call answers a record by output name: g.sim.particles({ ... }).points.

  • points (Points): the particles alive now, carrying P, v, age, life (0 at birth to 1 at death), lifetime, seed (a draw in 0..1 for each particle), size, id, stream (the index of the particle's source in sources; the detail's labels.stream lists the sources' stream names in that order) and slot, the place it holds in the solver for its life.
  • births (Points): the particles born in the present, at the place and velocity they were born with, carrying the same attributes as points.
  • deaths (Points): the particles that died in the present, as they stood when they died.
  • hits (Points): the particles that hit a collider in the present, carrying P, v (the velocity going into the hit), N (the surface normal), collider (the place of the collider record in colliders), id, stream and slot.
  • trails (Curves): with trails on, one open curve per particle alive, through its remembered positions newest first; its points carry P, trail (0 at the newest to 1 at the oldest), particle (the particle's id), size, life, seed and stream. geometry.ribbon lays a ribbon along it.

The events are kept for each slot over a present: a slot is born and dies at most once in a present and a dead slot is held until the next one, so births and deaths are one row for each particle, and a particle that bounces more than once in a present is one hit, the last. All four point outputs are held at the solver's capacity, with how many are live counted on the device.

Stamped attributes

Every number or vector point attribute a source's points carry, other than the particle's own (P, N, id, v, age, life, lifetime, seed, size, stream, alive, slot), is a state column of the solver (stamped_<name>, typed as the first source carrying it holds it), taken at birth from the point the particle is born at and held for its life; a source whose points do not carry it gives zero. The names are read from the sources while the graph is planned. points, births and deaths carry each one under its own name.

Example

local source = g.sim.spawn({ points = g.points.grid({ countX = 1, countZ = 1, y = 1 }), rate = 60,
    velocity = vector.create(0, 3, 0), jitter = 1 })
local floor = g.sim.collider({ shape = "plane" })
local sim = g.sim.particles({ sources = { source }, colliders = { floor }, gravity = vector.create(0, -9.8, 0),
    capacity = 2000 })
g:output("particles", sim.points)