With Geometry Nodes in Blender is easy to create additional custom attributes for objects and transfer the necessary data to them. However, there is no direct access to such created attributes.
If we try to read the object’s attribute created in Geometry Nodes by name:
1 |
bpy.context.object.data.attributes['_attribute_name_'] |
Blender will throw an error:
KeyError: ‘bpy_prop_collection [key]: key “_attribute_name_” not found’
This occurs because Geometry Nodes works like a modifier appended to an object. Modifiers do not affect the object’s source, overlaying changes above.
Like other modifiers, all the results of the Geometry Nodes, including the attributes created in them, can be obtained from the evaluated object.
Let’s add a cube to the scene and assign the Geometry Nodes modifier to it.
Add an Attribute Convert node (shift+a – Attributes – Attribute Convert) to the Geometry Nodes node tree. In the “Attribute” field set the “position” attribute. In the “Result” field type any name for the new attribute, for example, “my_pos”. As a result, Geometry Nodes will create a new attribute with this name and will translate the current position of the object to it.
If we try to access this attribute right now:
1 |
bpy.context.object.data.attributes['my_pos'] |
Blender will throw the same error informing that the specified attribute is missing for this object.
We can check that the object has no attributes by printing the list of its attributes.
1 2 3 |
print(object_.data.attributes[:]) # [] |
To access the Geometry Nodes attributes, we first need to evaluate the object – get its final evaluated copy.
1 2 3 |
obj = bpy.context.object.evaluated_get(bpy.context.evaluated_depsgraph_get()).data # <bpy_struct, Mesh("Cube") at 0x0000024E8E0F0108> |
The “obj” object now contains a fully evaluated copy of the active object with all changes made by modifiers and Geometry Nodes.
The required attribute already exists in the evaluated object:
1 2 3 |
print(obj.attributes[:]) # [bpy.data.meshes['Cube'].attributes['my_pos']] |
Now we can get all the data we need from the attribute by its name.
For example, the position of the first vertex of the mesh:
1 2 3 |
obj.attributes['my_pos'].data[0].vector # Vector((-1.0, -1.0, -1.0)) |
or a list of positions of all mesh vertices:
1 2 3 4 5 |
print([pos.vector for pos in obj.attributes['my_pos'].data]) # [Vector((-1.0, -1.0, -1.0)), Vector((-1.0, -1.0, 1.0)), Vector((-1.0, 1.0, -1.0)), Vector((-1.0, 1.0, 1.0)), Vector((1.0, -1.0, -1.0)), Vector((1.0, -1.0, 1.0)), Vector((1.0, 1.0, -1.0)), Vector((1.0, 1.0, 1.0))] |
*.blend file with the code example for my Patreon subscribers
Hi there! Thanks so much, this is really useful. I was wondering if there is a similar process for getting “Instances” data from the Spreadsheet. I found that something like :
Could at least read position, scale… of the instances, but I can’t read other attributes that might be stored on the instances plus it feels that your way is much cleaner and efficient.
Thanks
Hi!
I think this is the same way to do the same thing. Your way with bmesh is good too.
This is great, thanks. How can I then put this into a driver?
I’m trying to use a float value (from an index of a point along a curve) to drive the frame number of an image sequence.
thanks!
Try to set the attrubute value to a driver input field
For example:
bpy.context.object.data.attributes[_attr_name_].data[0].vector
Where’s attribute convert node? I can only see capture, transfer and statistic attribute nodes… 3.0 release
It was removed in the last builds of 3.0. You don’t need to use it to create attributes now. In the last version use fields – just connect the required node output to the Group Output node and name the created attribute in the modifier panel.
All the code to access the attribute in the last version stays the same.
Nice! very usefull info, thank you.
What if I wanted to edit (set) an attribute of a single vertex (selected vertex)? How could it be done via python?
Vertices are not an ID-objects, they can’t have attributes. Layers may be useful for this https://b3d.interplanety.org/en/assigning-custom-properties-to-vertexes/
what if I’ve already created this layer using bmesh, set its vertex values and pass it back to the mesh data? can I then recover those values and edit them again?
I think – yes, but this needs the experimental check.
Yes, it works. I just tried. Thanks