from nodebpy import geometry as gWriting Node Trees
Adding Nodes
Adding nodes must be done inside of a context. We enter a context using the with keyword. While inside of this context, whenever you call a node class (g.SetPosition()) a node of that type will be added to the current tree.
This first example creates a new tree and adds two new nodes, linking the Set Position node into the Transform Geometry node. The output and input sockets for each are inferred based on simple heuristics around socket type and order.
with g.tree("NewTree") as tree:
g.SetPosition() >> g.TransformGeometry()
treeThese nodes can be saved as variables for re-use later in the node tree as well. After instantiating a class you can access the input and output sockets through the .i and .o accessors on the class.
These two approaches are equivalent:
with g.tree("AnotherTree") as tree:
pos = g.SetPosition()
g.Position() * 0.5 >> pos.i.position
g.Vector() >> pos.i.offsetwith g.tree("AnotherAnotherTree") as tree:
g.SetPosition(
offset = g.Vector(),
position = g.Position() * 0.5
)Interface Sockets
The tree’s interface defines what sockets are available as inputs and outputs of the node tree.
We declare them with tree.inputs and tree.outputs — for example tree.inputs.geometry() or tree.outputs.float("Result") — which add the interface socket and return it for linking with other nodes.
with g.tree("NewTree") as tree:
geom_inputs = [tree.inputs.geometry(f"Geometry_{i}") for i in range(5)]
g.JoinGeometry(geom_inputs) >> tree.outputs.geometry("The Output Socket")
treewith g.tree() as tree:
(
tree.inputs.integer("Count", 10)
>> g.Points(position=g.RandomValue.vector(min=(-0.1,-0.1,-0.2)))
>> tree.outputs.geometry()
)
treewith g.tree() as tree:
count = tree.inputs.integer("Count", 10)
pos = g.RandomValue.vector() * 0.5 * g.Position()
g.Points(count, pos) >> tree.outputs.geometry()
treeZones
Zones like the repeat and simulation zone are initialized with their SimulationZone() and RepeatZone() constructors. You can add individual RepeatInput() and output nodes, but they require additional setup to be actually linked. The repeat zone can be initialized with a repeat count, which can also be linked to from elsewhere.
We can access the input and output nodes with zone.input and zone.output. The repeat zone has zone.iteration, which is the iteration number of the current zone. The simulation zone has zone.delta_time, which is the time between the previous and current simulation loop.
Because of the complexity of zones, we have the Item helper which gives access to the input & output sockets on the input and output nodes (4 sockets total). For the Simulation and Repeat zones, we have the:
| Code | Socket |
|---|---|
item.initial |
zone.input.i["Geometry"] |
item.current |
zone.input.o["Geometry"] |
item.next |
zone.output.i["Geometry"] |
item.result |
zone.output.o["Geometry"] |
with g.tree() as tree:
zone = g.RepeatZone(10)
random_pos = g.RandomValue.vector(seed=zone.iteration)
geo = zone.item("Geometry", type="GEOMETRY")
g.JoinGeometry([geo.current, g.Points(10, random_pos)]) >> geo.next
geo.result >> tree.outputs.geometry()
treewith g.tree() as tree:
# this initializes the zone with two socket inputs for each of the values
# we manually specify the socket names
zone = g.SimulationZone({"Value": g.Value(), "Vector": g.Vector()})
zone.input.o["Value"] + 10 >> zone.output
# this should automatically pick the vector input socket because we are
# explicit about the VectorMath and it will be the most compatible
zone.input >> g.VectorMath.add(..., (0.2, 0.4, 0.6)) >> zone.output
tree