1
$\begingroup$

Newbie here

I was recently working on a project that required dynamically generated 3D terrain. I am currently a computer science student but have some experience in blender and had seen what was possible with geometry nodes. With the knowledge that blender is open-source and has an API I could use, I had the following idea:

If I created a geometry node inside blender that would take some inputs and created my desired geometry, would it at all be possible to somehow call that node from an outside python script with input values and get back the output geometry?

My thinking here is that blender is probably doing just that in the background somewhere, so can I access it from outside?

To be clear, I have no experience with the programming side of blender. At the moment I feel like it is unlikely this is possible. So before I dive into the documentation and learning the blender API, I thought that maybe some more experienced people could either encourage me or crush these dreams before I start pouring my time into it.

Further explanation of what I'm trying to do if the above is confusing:

As an example I made this small node cube_grid in the file cube_grid.blend that simply creates a grid of cubes, with inputs for the size of the cubes and size of the grid in x- and y-direction:

cube grid generation geometry node

The output would simply look like this for a 10x10 grid of 1x1x1m cubes:

10x10 cube grid

Now I would like to do something like this:
pseudo-code, I have never touched the blender API

import blender

file = blender.open_file('cube_grid.blend')

geometry_node = file.geometry_nodes('cube_grid')

mesh = geometry_node(cube_size=1, size_x=10, size_y=10)

mesh.save_to_file('my_cube_grid.dae')
$\endgroup$

2 Answers 2

3
$\begingroup$

Sure. Lib is called bpy:

import bpy

First, you get the modifier:

obj = bpy.data.objects['Cube'] # or get the object in other way
gnmod = None
for gnmod in obj.modifiers:
    if gnmod.type == "NODES":
        break
# if modifier doesn't exsists make new one:
if (gnmod is None) or (gnmod.type != "NODES"):
        gnmod = obj.modifiers.new("My GeoNodes Modifier", "NODES")

Or if you're sure that you have no modifier, just create it:

obj = bpy.data.objects['Cube'] 
gnmod = obj.modifiers.new("My GeoNodes Modifier", "NODES")

Then you have to assign a node group to the modifier if the modifier is just created:

 g.node_group = bpy.data.node_groups['My Geometry Nodes']

"My Geometry Nodes" is the name of the node group that you have prepared.

Then you get identifier of socket. (Since the name of identifier (like "Input_3") is quite random number, you have to get identifier from socket name) Let's say you want to set "cube_size":

inputs = gnmod.node_group.inputs
id = inputs["cube_size"].identifier

Then you can use attribute and set it:

gnmod[id] = 10

For open and saving files you can use ops commands. You can get it by enabling python tooltips in user preferences:

enter image description here

$\endgroup$
1
  • $\begingroup$ Yep, I'm not so great in python, maybe you are right. $\endgroup$
    – Crantisz
    Apr 7, 2022 at 14:46
2
$\begingroup$

For step 1, you can make a bat to open a blend file if you are window user.
For safety reason, blender does not run script automatically. You need find a way to run it automatically.

Here is the script, click run script and the node setup will appear.

import bpy

# select and del all object
bpy.ops.object.select_all(action = "SELECT")
bpy.ops.object.delete(use_global=True, confirm=False)

# add cube
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))

# add GeometryNodes modifier
bpy.ops.object.modifier_add(type='NODES')

# access active object node_group
node_group = bpy.context.object.modifiers[0].node_group

# add socket
inputs = node_group.inputs
inputs.new(type = "NodeSocketFloat", name = "cube_size")
# remove first socket
inputs.remove(inputs[0])

inputs.new(type = "NodeSocketFloat", name = "size_x")
inputs.new(type = "NodeSocketFloat", name = "size_y")

# add node
nodes       = node_group.nodes
comXYZ_1    = nodes.new(type="ShaderNodeCombineXYZ")
comXYZ_1.location.x -= 100
comXYZ_1.location.y -= 200

comXYZ_2 = nodes.new(type="ShaderNodeCombineXYZ")

meshline_1 = nodes.new(type="GeometryNodeMeshLine")
meshline_1.location.x += 200
meshline_1.location.y += 100

meshline_2 = nodes.new(type="GeometryNodeMeshLine")
meshline_2.location.x += 200
meshline_2.location.y -= 130

meshpoint = nodes.new(type="GeometryNodeMeshToPoints")
meshpoint.location.x += 400
meshpoint.location.y -= 50

cube = nodes.new(type="GeometryNodeMeshCube")
cube.location.x += 450
cube.location.y -= 300

insonpoint_1 = nodes.new(type="GeometryNodeInstanceOnPoints")
insonpoint_1.location.x += 600
insonpoint_1.location.y += 100

insonpoint_2 = nodes.new(type="GeometryNodeInstanceOnPoints")
insonpoint_2.location.x += 850
insonpoint_2.location.y -= 100

nodes["Group Output"].location.x += 850

# connect
links = node_group.links
links.new(nodes["Group Input"].outputs["cube_size"],    comXYZ_1.inputs[0])
links.new(nodes["Group Input"].outputs["cube_size"],    comXYZ_2.inputs[1])
links.new(nodes["Group Input"].outputs["size_y"],       meshline_1.inputs["Count"])
links.new(comXYZ_2.outputs["Vector"],                   meshline_1.inputs["Offset"])
links.new(comXYZ_1.outputs["Vector"],                   meshline_2.inputs["Offset"])
links.new(nodes["Group Input"].outputs["size_x"],       meshline_2.inputs["Count"])
links.new(nodes["Group Input"].outputs["cube_size"],    cube.inputs["Size"])
links.new(meshline_2.outputs["Mesh"],                   meshpoint.inputs["Mesh"])
links.new(meshline_1.outputs["Mesh"],                   insonpoint_1.inputs["Instance"])
links.new(meshpoint.outputs["Points"],                  insonpoint_1.inputs["Points"])
links.new(cube.outputs["Mesh"],                         insonpoint_2.inputs["Instance"])
links.new(insonpoint_2.outputs["Instances"],            nodes["Group Output"].inputs["Geometry"])
links.new(insonpoint_1.outputs["Instances"],            insonpoint_2.inputs["Points"])

enter image description here blender verson: 3.2 a

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .