7
$\begingroup$

I'm trying to determine if it's possible to define custom attributes associated with vertices or edges of a mesh and then assign values to them manually as part of the mesh creation process, much like how edges can be (un)marked as sharp in edit mode, or vertices in groups can be assigned weights.

When initially skimming the user guide for 3.2 as a new user, it sounded like custom attributes provided exactly the ability I was looking for. But as best as I can tell, these named custom attributes exist only as locations to which geometry nodes can write procedurally calculated intermediate values. E.g., the Spreadsheet editor type displays any added custom attributes for a mesh and their values, and has separate views for "evaluated" and "original," but there seems to be no way in this or any other interface to assign values to the starting mesh.

Are custom attributes exclusively derived / procedural state, or is there a way (including through the Python API) to assign custom attribute values to mesh elements as part of the authoring process, similar to built-in properties like edge sharp/smooth? Are there any other Blender features suitable for assigning custom data manually to vertices / edges / etc. of a mesh?

$\endgroup$

3 Answers 3

9
$\begingroup$

Custom attributes can be set through the python API. For example, to add a float attribute to each vertex of the default cube:

mesh = bpy.context.collection.objects["Cube"].data
attribute = mesh.attributes.new(name="new attribute", type="FLOAT", domain="POINT")
attribute_values = [i for i in range(len(mesh.vertices))]
attribute.data.foreach_set("value", attribute_values)

You can access the attribute (or any other existing attribute) using its name, be careful when an attribute with the same name exists, Blender will choose a different name for the attribute, for example "new attribute.001"

mesh.attributes['new attribute']

in general it is a good idea to try not to rely on names for accessing properties

See docs for more details on the options

enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ Has something changed in the API, or something like that? (Testing with 3.4 here) This does not seem to work for me, the foreach_set always fail, giving the error: RuntimeError: internal error setting the array, with this message: Error: Array length mismatch (expected 0, got 68) The attribute data is always a collection of 0 elements, and I can't use foreach_set to add values in it. $\endgroup$
    – JulienH
    Commented Nov 2, 2022 at 14:59
  • 4
    $\begingroup$ Answering my own question above: The attribute data array will stay empty if you are in EDIT mode, so, don't forget to go in object mode before doign anything related to attributes. $\endgroup$
    – JulienH
    Commented Nov 2, 2022 at 15:10
  • 1
    $\begingroup$ I found that the active attribute might change when going between object and edit mode. I think the position attribute throws it off $\endgroup$ Commented Jul 20, 2023 at 0:23
1
$\begingroup$

To iterate on the other answer, you can access and edit attributes in edit mode, but you have to use the Bmesh API. One caveat is you can't use foreach_set and foreach_get so this might be slow on dense meshes. You have to loop over mesh elements (verts, edges, corner or faces) and for each element, access the layer.

Same thing as @Linus' answer but in edit mode :

import bpy
import bmesh

mesh = bpy.data.objects["Cube"].data
attribute = mesh.attributes.new(name="new attribute", type="FLOAT", domain="POINT")
attribute_values = [i for i in range(len(mesh.vertices))]

bm = bmesh.from_edit_mesh(mesh)
layer = bm.verts.layers.float.get(attribute.name)

for vert in bm.verts:
    print(f"Previous value for {vert} : {vert[layer]}")
    vert[layer] = attribute_values[vert.index]
    print(f"New value for {vert} : {vert[layer]}")

bmesh.update_edit_mesh(mesh)

https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMLayerAccessVert

$\endgroup$
1
$\begingroup$

But as best as I can tell, these named custom attributes exist only as locations to which geometry nodes can write procedurally calculated intermediate values

Attributes do not have be procedurally calculated. If you do not want an attribute to be a calculation of something else, assign it a constant value; if you want it to be calculated only from static values, calculate it only from static values:

enter image description here

Both "ind" and "zero" are now attributes on the mesh.

If your attributes are not going to be recalculated, you can store them by applying the modifier:

enter image description here

After applying the modifier, these attributes remain stored as mesh data, and continue to work in other geometry nodes modifiers:

enter image description here

possible to define custom attributes associated with vertices or edges of a mesh and then assign values to them manually as part of the mesh creation process

I can't conceive of any definitions where creating modifiers and applying them is not part the manual mesh creation process-- just like a lot of my characters have a live mirror modifier until late in the mesh creation process, and then I apply it.

What can be tricky is assigning attributes their values in an intuitive way, but what's intuitive depends on what kind of data those attributes are, and how they're going to be used. Thankfully, there are a huge variety of ways to assign data, of various types, which can be converted into attributes.

For 1D vertex data, we can use the existing tools to set vertex weight. If we want attributes outside of the 0,1 range, we can map the desired range into the 0,1 range (mentally perhaps), assign vertex group weights, and then map back into the attribute range in the GN modifier (the one that we apply, or the one that reads those "written" attributes, either will work.)

For 2D vertex or face corner data, we can use UV. For 3D or 4D vertex or face corner data, we can use vertex color. For 3D data that is easiest to visualize as position, we can set this by transferring the attribute, by index, from an edited copy of the mesh. For edge data, we might use edge_crease as an input to our GN-- there should be others that work, but quick testing guarantees that one works. For face data, we can use any face-corner data cast to face data.

And if some technique is intuitive, but it's the wrong dimensionality, we can ignore some channels; and if we want more dimensions, we can use more instances of that data. We can use 2 UV maps or 4 vertex groups to specify 4D attributes, for example.

Do any of these collide with other uses of that data? Let's say you want to write some edge data to the mesh, a mesh which is already using edge_crease. No problem: write the current edge crease data to a new attribute, and you can restore it when you're done writing the other edge crease data. Using attributes, any limits regarding the number of edge_crease "channels" nearly disappear. (Also true for UV and vertex color, mesh data where Blender's limits can be relevant even without the use of GN.)

So not only can we set attributes manually, we can "paint" them using almost any of Blender's tools for painting data, often interchangeably.

$\endgroup$

You must log in to answer this question.

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