Skip to content
Voro
  1. Geometry
  2. Guides

Populations

A population places one network you built many times. Each copy is a member with its own state. Two operators do the work, both in the Geometry view of the Voro menu, under Render. Populate places the members, and Relation couples them to each other or to the world.

You wantUse
One object where you put itGeometry, or Asset Import for a file
Many copies of a few variants of a module, such as rocks, props or treesPlace. It builds the variants and draws them, with no population of your own
Copies that each keep their own state and behaviourPopulate

Bodies that touch or stack are a special case. See Contact below.

A member is an ordinary network of Voro operators inside a COMP. Nothing in it knows it is a member. Build it as a single thing, test it, and then point a Populate’s Member Source at the COMP.

The member keeps everything private except what you choose to share. Binding rows name the controls and inputs that come from outside. Publication rows name the outputs other operators can read.

When you edit the member network in place, press Refresh Member. That re-reads the network and its controls and leaves every member’s state alone. Pointing Member Source at a different network admits the population again.

These are three different numbers.

NumberWhat it is
CountHow many members you asked for. It seeds the population when it starts.
CapacityHow many member rows the Engine allocated. 0 means exactly Count.
LiveHow many members exist right now, after births and retirements.

Status on the Voro page shows all three, plus births, retirements, refusals and the last refusal reason. Trust Status over Count. If Count says 50 and Status says 10 rows admitted, the Engine refused something, and the refusal text says what.

Membership can change while the population runs, without restarting anything:

  • Emit Members adds Emit Count members. A request that does not fit in Capacity is refused as a whole, so set Capacity above Count if you plan to emit.
  • Retire Member removes the member whose handle is in Member Handle. Its siblings keep running.
  • Lifecycle Packets does both from the network. Pick an operator whose published points are read as commands, one per row.

Inspect Member opens a view of the live members, their handles and reset counts, their bindings and the last refusal. A handle belongs to one member for the whole session. When a member retires, the next birth reuses its row under a new handle, so a stale handle is refused instead of reaching somebody else.

A binding row says where one control or input of the member gets its value.

ModeEach member gets
constantThe same value
sequenceValue i % length from a list, so a short list repeats
seededA value between a minimum and a maximum, drawn from Seed and the member index. The same Seed gives the same values every run
resourceAnother operator’s output, such as a static mesh, a field or another population’s publication

The Value field is JSON. Write a constant as 0.5, a sequence as [0.2, 0.5, 0.9] and a seeded range as [min, max].

The repeat is the part people misread. It applies to the rows as well as the values. With ten binding rows and fifty members, member i uses row i % 10, five times over. That is how a few rows drive a large population. The population did not stop at ten. If you need fifty different values, give one row a sequence of fifty values.

Do not use a repeating control as an address. If members look up their own part of a shared publication by a control that repeats every ten members, five members read the same part. Address by the member’s own handle or row instead.

For a resource binding, Input Semantics picks how the data arrives:

  • shared sends the whole publication to the population once, and each member reads its own part. This is the usual choice for a Relation’s output or for static world geometry.
  • per_member feeds each member its own row. That needs an explicit list saying which member is which. Two populations of fifty are not paired just because their counts match.

A population does not step until one of its inputs has published. If the member’s only input is feedback from a Relation, nothing starts. Give it one input that publishes from the first pass, such as a static mesh.

A Relation is a module that reads what members publish and writes back what they should apply. Springs, attractions and steering rules are relations. On the Relation operator, set Relation Implementation to the module that computes it, then add one Participant row per connection, naming the publication it reads and the input it writes.

A Relation also groups its participants. They run, hold and reset together. A plain data wire between operators never groups them.

When a correction goes back to the member that produced the data, the loop needs a one-step delay. Turn on Previous Generation for that return row only.

A relation’s output reaches the members a step late. For springs and steering, that is fine. For bodies that stack, rest on each other or push both ways, it is not. Each correction lands on a body that has already moved, and a pile keeps gaining speed. Let the relation own the bodies instead. It reads each member’s shape and intent, solves every body together in one step, and publishes poses that the members read back to draw. On 1,000 falling cubes, corrections sent back to the members threw cubes to 205 m/s. One relation owning the bodies kept every cube at its own free-fall speed.

Run off holds the population and everything grouped with it. Members keep their state. Emit, Retire and Reset still queue up and take effect when Run comes back on. Hold is different from Bypass, which takes the population out of the plan.

Resetting has three scopes:

  • Reset Population returns every live member to its first state and restarts every relation grouped with it, so a member and the relation correcting it start over at the same moment. Membership stays the same.
  • Reset One Member restarts only the member in Member Handle. Its siblings and its relations keep running, so it picks up their output from where they are now. A Previous Generation input shared by the population is not cleared, because the producer owns it.
  • Reset State on the Voro page is the reset every operator has. On Populate, use Reset Population, because it names what it restarts.

After a reset, a Previous Generation input goes back to its cold default, so a restarted member never reads a value from before the reset.

The Lab ships the full method for anyone writing member or relation modules. That covers declarations, per-member spans, publishing placement lists and colours from members, and the relation packet contract. Open lab/AUTHORING_GUIDE/POPULATIONS.md in the Voro package. INSTANCING.md next to it covers placement lists and Place.