Skip to content

Zones

Zones are made of paired nodes:

  • Simulation
  • Repeat
  • For Each Element
  • Closure
  • Bundle

The loop zones are implemented with the for syntax when Closure and Bundle are implemented with with context.

Closure

The two Closure zone nodes are created when instantiating a Closure class. To create the nodes, use the with context:

    # Create a closure adding 1 to the input
    with Closure() as cl:
        a = Float(1.0, "Float")
        a += 1
        a.out("Plus One")

The closure evaluation is made using the evaluate method. This method takes a signature argument which is a dict describing the closure inputs and outputs.

with GeoNodes("Closure"):

    # Create a closure adding to two entries 
    with Closure() as cl0:
        a = Float(1.0, "A")
        b = Float(1.0, "B")
        (a + b).out("Sum")

    # If evaluated immediately, the signature is read from the previous nodes.
    cl0.evaluate().out(panel = "Separate 0")

    # We can get the closure signature for future use
    sig = cl0.get_signature()

    # We can evaluate a closure using this signature
    cl1 = Closure(name="Closure 1")
    cl1.evaluate(signature=sig).out(panel="Signature 1")

    # We can evaluate another closure using a manual signature:
    # a couple of dicts for input and output
    sig = (
        {'A': 'Float', 'B': 'Float'},
        {'Sum': 'Float'})

    cl2 = Closure(name="Closure 2")
    cl2.evaluate(signature=sig).out(panel="Signature 2")

    # Selecting a closure
    # Note that since the closure coming from MenuSwitch
    # doesn't come from a zone, the ***with*** context relates
    # to the 'Menu Switch', not the zone (compare to the creation of cl0).

    with Closure.MenuSwitch() as cl:
        cl0.out("Closure 0")
        cl1.out("Closure 1")
        cl2.out("Closure 2")

    cl.node.menu = Input(default_value="Closure 0")

    cl.out()

Loops

To make the code as clear and pythonistic as possible, the Geometry nodes loop zones Simulation, Repeat and For Each Element are implemented as python iterator.

  • Simulation and Repeat : Socket iterator
  • For Each Element : Domain iterator
    mesh = Mesh()

    for simul in mesh.simulation():
        # Nodes are created in the Simulation zone
        pass

    for rep in mesh.repeat(10):
        # Nodes are created in the Repeat zone
        pass

    for feel in mesh.points.for_each():
        # nodes are created in the For Each Element zone
        pass

The object returned by the iterator exposes the input and output sockets.

Note

Within the for iteration, the ouput sockets come from input node and the input sockets are those of the output node. Outside the for, the ouput sockets come from output node and the input sockets are those of the input node.

Note

Within the for iteration, the geometry is the geometry to compute. The for iteration must end with xxx.out() where xxx is the name of the Geometry class. Outside the for iteration, the geometry has jumped to the zone output node and cand be used to continue.

Simulation

with GeoNodes("Simulation"):

    # Two input parameters
    count  = Integer(10, "Count", 1, 100)
    radius = Float(.1, "Radius", 0, 2)

    # Cloud of points
    cloud = Cloud.Points(count=count, position=Vector.Random((-5, -5, 5), (5, 5, 15)))

    # Gravity simulation with initial random speed
    for sim in simulation(cloud=cloud, Speed=Vector.Random(-1, 1)):

        # One speed per point
        speed = sim.cloud.points.capture_attribute(sim.speed)

        # Increment the posiion
        sim.cloud.position += speed*sim.delta_time

        # Acceleration
        speed += sim.delta_time*(0, 0, -9.81)

        # Bounce onfloor
        x, y, z = speed.xyz
        speed = speed.switch(nd.position.z.less_than(radius), (.9*x, .9*y, -.7*z))

        # Next iteration
        speed.out("Speed")

    # Getting the simulation result
    cloud = sim.cloud

    with Layout("Instantiate the balls"):
        mesh = Mesh.Grid(20, 20)
        mesh += cloud.instance_on(instance=Mesh.UVSphere(radius=radius))

    # Outside de the loop, out to Group Output Node
    mesh.out()

Repeat

with GeoNodes("Repeat"):

    # Parameters
    levels = Integer(5, "Levels", 1, 10)
    size = Float(5, "Size", .1, 10)

    delta = size/levels

    cube = Mesh.Cube(size=(size, size, 1))

    for rep in cube.repeat(levels):

        sz = size - rep.iteration*delta
        floor = Mesh.Cube(size=(sz, sz, 1))
        floor.transform(translation=(0, 0, rep.iteration ))

        cube += floor

    cube.out()

For Each Element

with GeoNodes("For Eeach"):

    # Let's assume the input geometry is a mesh
    mesh = Mesh()

    # The geometry to add at the center of each face
    sph = Mesh.UVSphere(radius=Input("Sphere Radius", default_value=.2))

    # Loop on the faces
    for feel in mesh.faces.for_each():
        # Position of the face
        pos = mesh.faces.sample_index(nd.position, 0)

        # Move the to the center
        sph.transform(translation=pos)

        # By default, out in the generated panel
        sph.out()

    # Join the generated geometry
    mesh += feel.generated

    mesh.out()