Class Tree#
main - nodes - nodes menus
A geometry nodes tree.
A Tree class encapsulates a Blender NodeTree:
blender_tree = tree.btree # The Blender NodeTree
Modifier and custom group#
A Tree can be used for two purposes:
to be used in a Geometry Nodes modifier (default)
to be used as a custom Group called in another Tree (
group = True
)
To include a custom group into a Tree, simply initialize a Group class with its name as first parameter.
# Call of the custom group named "Reusable Computation"
# After the name, use keyword arguments to feed the input sockets of the custom group
node = Group("Resusable Computation", ...)
# The node is supposed to return two sockets "Total value", "Average value"
total = node.total_value
avg = node.average_value
Tree creation#
Once the tree is completed, the arrange method makes the whole tree of nodes quite readable. Building a tree is made between the two instructions:
tree = Tree(tree_name)
: creation / opening of the Blender NodeTreetree.close()
: arrange the nodes
It is recommended to use the with
context:
with Tree("Geometry Nodes") as tree:
# ... nodes creation
# Tree is created and arranged
Layout#
For a better clarity of the resulting tree, it is possible to put the newly created nodes in a layout.
The layout creation makes use of the with
context (see layout):
with Tree("Geometry Nodes") as tree:
# Nodes created here are placed directly on the tree background
with tree.layout("Some tricky computation"):
# Nodes created here are placed in the current layout
with tree.layout("The most difficult part"):
# Layouts can be imbricated
# Back to standard creation
Input and output geometries#
The input geometry is read with the Tree property input_geometry or its short version ig.
The output geometry is defined by setting the Tree property output_geometry or its short version og.
The do nothing modifier can be written:
import geonodes as gn
with gn.Tree("Do nothing") as tree:
tree.og = tree.ig
Input sockets#
The Tree input sockets are defined with the Input class method of data classes.
For instance, to create an input socket of type Float:
import geonodes as gn
with gn.Tree("Test") as tree:
user_param = gn.Float.Input(.5, "Volume density", val_min=0.1, val_max=20., description="Which density do you want ?")
Output sockets#
To create output sockets, call the to_output method of data classes.
For instance, to create an output socket of type Vector:
import geonodes as gn
with gn.Tree("Test") as tree:
vect = gn.Vector((1, 2, 3))
vect.to_output("Some vector")
Constructor#
Tree(self, tree_name, clear=False, group=False, fake_user=False, prefix=None)
Args:#
Content#
Properties
cur_frame | frame | ig | input_geometry | og | output_geometry | scene | seconds
Methods
activate | arrange | check_attributes | close | get_bnode | get_bnode_wrapper | get_bsocket_wrapper | layout | new_group_input | new_group_output | new_input | prev_node | register_node | to_output
Properties#
cur_frame#
Get the current layout for the newly created nodes.
Go to top - main - nodes - nodes menus
frame#
The “Scene Time” output socket “frame”.
Go to top - main - nodes - nodes menus
ig#
Shortcut for input_geometry.
Go to top - main - nodes - nodes menus
input_geometry#
The group input geometry.
my_geometry = tree.input_geometry
Go to top - main - nodes - nodes menus
og#
Shortcut for output_geometry.
Go to top - main - nodes - nodes menus
output_geometry#
The group output geometry.
tree.output_geometry = my_geometry
Go to top - main - nodes - nodes menus
scene#
Maintain a single instance of the node :class:SceneTime
.
Go to top - main - nodes - nodes menus
seconds#
The “Scene Time” output socket “seconds”.
Go to top - main - nodes - nodes menus
Methods#
activate#
def activate(self)
Set this tree as the current one.
The Tree class property TREE
is set to self
Go to top - main - nodes - nodes menus
arrange#
def arrange(self)
Arrange the created nodes in the tree background for more lisibility
Go to top - main - nodes - nodes menus
check_attributes#
def check_attributes(self)
Check the attributes
This utility function is called when closing the tree to “solve” the attribute input nodes, i.e. to determine if a ‘Capture Attribute’ node is required.
In geonodes, attributes are initialized as properties of a geometry. For instance, in the following piece of code, the node ‘Position’ is to be the position of the vertices of my_mesh:
v = my_mesh.verts.position # Create the node 'Position'
To actually get these vertices, a ‘Capture Attribute’ can be necessary. This is determined
by check_attribute
method.
The insertion is made with the following algorithm
Check if capture is needed
for each fed node:
if the node has an input geometry:
if the input geometry is the expected one:
ok
else
insertion is needed
else:
continue exploration with the nodes fed by this node
If insertion is needed
Create the ‘Capture Attribute’ node
Set the proper parameters
Input geometry with the owning socket
Output geometry to the sockets the owning socket was linked to
Output attribute to the sockets the attribute was connected to
Note that by initializing an attribute with geometry and domain, we have what we need to insert a ‘Capture Attribute’ node:
# Get the position of the vertices of my_mesh
v = my_mesh.verts.position
# Create the capture node
capture_node = nodes.CaptureNode(
geometry = my_mesh,
value = (output socket of Position node),
data_type = 'VECTOR', # We deal with position which is a Vector
domain = 'POINT', # my_mesh.verts.position --> 'POINT'
# my_mesh.edges.position --> 'EDGE'
# my_mesh.faces.position --> 'FACE'
)
Flag to colorize the dependancies
Go to top - main - nodes - nodes menus
close#
def close(self)
Call to indicate that the tree is completed and that it can be finalized
Three actions are performed:
Insertion of “Capture Attribute” nodes for attributes which require it, see :func:
check_attributes
.Insert group input nodes in frame when ok_capture_inputs is set to True
Nodes arrangement, see :func:
arrange
.
—– Capture attributes
Go to top - main - nodes - nodes menus
get_bnode#
def get_bnode(self, bl_idname, label=None)
Get an existing, or create a new, Blender node in the tree.
Args:#
bl_idname (str): the node bl_idname
label (str): Node label
Returns:#
the blender node (bpy.types.GeometryNode)
At initialization time, some nodes (the ones which can be changed by UX) are kept
in old_bnodes
list. Before creating a new node, this list is scaned to find a node
of the proper type and the proper label.
Go to top - main - nodes - nodes menus
get_bnode_wrapper#
def get_bnode_wrapper(self, bnode)
Get the Node instance wrapping the Blender node passed in argument.
Args:#
bnode (bpy.types.NodeSocket): a blender node
Returns:#
The wrapping node (Node)
Go to top - main - nodes - nodes menus
get_bsocket_wrapper#
def get_bsocket_wrapper(self, bsocket)
Get the DataSocket instance wrapping the Blender socket passed in argument.
Args:#
bsocket (bpy.types.NodeSocket): a blender socket
Returns:#
The node wrapping the socket (Node)
Go to top - main - nodes - nodes menus
layout#
def layout(self, label="Layout", color=None, capture_inputs=None)
Create a new layout where the newly created nodes will be placed.
Args:#
label (str): the layout label
color (str or color): the layout background color
capture_inputs (bool): if True, create a new instance fo group inputs in the frame
To be used in a with
block:
with tree.layout("My layout"): # Create a layout
mesh = Mesh.UVSphere() # The node is parented in the layout
mesh.set_shade_smooth() # "Set Shade Smooth" node is created in the tree background
Go to top - main - nodes - nodes menus
new_group_input#
def new_group_input(self)
Create a new instance in group input.
Go to top - main - nodes - nodes menus
new_group_output#
def new_group_output(self)
Create a new instance in group output.
Go to top - main - nodes - nodes menus
new_input#
def new_input(self, class_name, value=None, name=None, min_value=None, max_value=None, description="")
Create a new input socket.
Args:#
class_name (str): class name of the value to get
value (any): initial value
name (str): name of the socket to create
min_value (any): minimum value
max_value (any): maximum value
description (str): user tip
Returns:#
DataSocket
res = tree.new_input('Integer', 10, "Resolution", min_value=2, max_value=100, description="Grid resolution")
Don’t use it directly, better call the constructor
Input
of data classes.
res = Integer.Input(10, "Resolution", min_value=2, max_value=100, description="Grid resolution")
Go to top - main - nodes - nodes menus
prev_node#
def prev_node(self, index)
Utility which prints the configuration of a node in the console.
Args:#
index (int) : the unique id of the node to print
Returns:#
None
When a node is tweaked to obtain the expected result, the changes will be lost
next time the script will be run. By calling prev_node
the parameters are printed
in the console and can be copied/pasted.
Go to top - main - nodes - nodes menus
register_node#
def register_node(self, node)
Register the node passed in parameter in the current tree.
Args:#
node (Node): The node to register
Returns:#
node
When registered, a unique id is provided to the node. This allows the users to more clearly distinguish the nodes.
Go to top - main - nodes - nodes menus
to_output#
def to_output(self, socket)
Create a new output socket linked to the data class.
Args:#
socket (DataSocket): the socket to connect to an output of the tree Returns:
None
tree.to_output(value)
Don’t use it directly, better call method to_output
of data classes.
value.to_output()
Go to top - main - nodes - nodes menus