Skip to content
Voro
  1. Geometry
  2. Render

Relation

A Relation couples members of a Populate to each other or to the world. A spring, an attraction, a steering rule or a contact solver is a relation. It reads what the participants publish and writes what they should apply.

A Relation also groups its participants. They run, hold and reset together, so Reset Population restarts a member and the relation correcting it at the same moment. A plain data wire between two operators never creates that grouping.

  1. Build the module that computes the relation, for example a Warp FX that reads member poses and writes corrections.
  2. Place Relation from the Geometry view of the Voro menu, under Render. Its Status reads “Select a relation implementation”.
  3. Set Relation Implementation to that module.
  4. Add one Participant row per coupling. Pick the publication the relation reads in Source Publication and the input it writes in Destination Input. One end of every row must be the implementation itself.
  5. When a correction goes back into the member that produced the data, turn on Previous Generation for that return row.

Status reads “Resolved; coupled execution scope” once the relation is part of the network’s plan.

Relation has no wires of its own. Participant rows name each connection as an operator and a port. A destination on a Populate must be an input that the population exposes, and the source and destination types must match. Otherwise Status names the row that failed.

Relation Implementation is the module that does the work.

Participants are the couplings. Previous Generation delivers the previous step’s value instead of this one. That is what lets a loop close: a member publishes a pose, the relation reads it, and the correction comes back to the member one step later. Turn it on for the return leg only.

Lifecycle Scope is coupled by default. The relation runs, holds and resets with its participants.

Refresh Relation re-reads the implementation and its ports after you edit it in place. Expose Relations brings every relation that shares these participants onto the network so you can see and edit them.

Output from a relation reaches the members a step late. Bodies that stack, rest on each other or push both ways need a relation that owns the bodies. It reads each member’s shape and intent, solves every body together in one step, and publishes poses that each member reads back to draw. Measured on 1,000 falling cubes, impulses sent back to the members threw cubes to 205 m/s. One relation owning all the pieces as bodies kept every cube at its own free-fall speed.

A reset returns a Previous Generation input to its cold default, so a restarted member never reads a value from before the reset. Reset One Member on a Populate does not clear a shared Previous Generation input, because that belongs to the producer. The reset member picks up the producer’s current output. Reset Population restarts both.

A population and a relation joined only by their own feedback loop cannot start. Give the member one other input that publishes from the first pass.

The relation packet contract, and how a member should match packets to its handle and reset epoch, are in the Lab’s Populations guide, lab/AUTHORING_GUIDE/POPULATIONS.md in the Voro package.

Relation

Relation Implementation (Implementation) Str op('relation').par.Implementation

The module that computes this relation -- a contact solver, a spring, an attraction. It reads the participants' publications and publishes what they should apply.

Default:
None
Lifecycle Scope (Feedbackscope) Str op('relation').par.Feedbackscope

coupled: this relation runs, holds and resets together with its participants, in one interaction scope. That grouping is what makes Reset Population restart a member and the relation correcting it at the same moment, so neither is reading the other from before the reset. A data wire alone never creates it.

Default:
coupled
Refresh Relation (Refreshrelation) Pulse op('relation').par.Refreshrelation

Re-read the relation implementation and its participant ports after editing it in place.

Default:
None
Expose Relations (Exposerelations) Pulse op('relation').par.Exposerelations

Bring every relation sharing these participants onto the network as operators you can see and edit.

Default:
None

Participants

Participant: Source Publication (ParticipantFrom) Menu op('relation').par.ParticipantFrom

The publication this relation reads, as owner:port.

Default:
"" (Empty String)
Options:
Participant: Destination Input (ParticipantTo) Menu op('relation').par.ParticipantTo

The input this relation writes, as owner:port.

Default:
"" (Empty String)
Options:
Participant: Previous Generation (ParticipantTemporal) Toggle op('relation').par.ParticipantTemporal

On: deliver the previous generation (z-1) instead of this one. This is what makes a feedback loop legal -- a member publishing a pose that a relation reads, whose correction comes back to that member. Turn it on for the return leg only. A reset returns a z-1 input to its declared cold default, so a restarted producer is never rejected as older than the packet that preceded the reset.

Default:
Off
Options:
Off, On