2
$\begingroup$

How do I write an integer attribute for each vertex?
For some reason this code doesn't work:

import bpy

mh = bpy.data.meshes.new("Mesh")
mh.vertices.add(2)

att = mh.attributes.new(name="a", type='INT', domain='POINT')
att.data.foreach_set('a', [1, 2]) #mh.vertices.foreach_set('a', [1,2])

#AttributeError: foreach_set(..) 'IntAttribute.          data[...]' elements have no attribute 'a'

#>>> bpy.data.meshes['Mesh'].attributes[:]
#[bpy.data.meshes['Mesh'].attributes["a"]]

What am I doing wrong?

$\endgroup$

2 Answers 2

3
$\begingroup$

You add a attribute named "a", But there is no "a" attribute in the data collection.

import bpy

mh = bpy.context.object.data

att = mh.attributes.new(name="a", type='INT', domain='POINT')
att.data.foreach_set('value', range(len(att.data)))

print(att.name)

for v in att.data:
    print(v.value)
$\endgroup$
1
$\begingroup$

foreach_set is much faster, though, method is effective only for a small number of vertices.

Object mode

In object mode. There is a way to specify directly.

import bpy

# Get the mesh data of the Cube object
mesh = bpy.context.collection.objects["Cube"].data

# Add a new attribute (ignore if it already exists)
if "new attribute" not in mesh.attributes:
    attribute = mesh.attributes.new(name="new attribute", type="INT", domain="POINT")
else:
    attribute = mesh.attributes["new attribute"]

# Check all vertices and set attribute values based on conditions
for i, vert in enumerate(mesh.vertices):
    if vert.index in [1, 2]:
        attribute.data[i].value = 5
    else:
        attribute.data[i].value = i

# Verify the attribute values
for i, attr in enumerate(attribute.data):
    print(f"Vertex {i} attribute value: {attr.value}")

# Note: This script can only be used in Object Mode

Console

Vertex 0 attribute value: 0
Vertex 1 attribute value: 5
Vertex 2 attribute value: 5
Vertex 3 attribute value: 3
Vertex 4 attribute value: 4
Vertex 5 attribute value: 5
Vertex 6 attribute value: 6
Vertex 7 attribute value: 7

Edit mode

By the way, here is the script in edit mode. Bmesh is used. This may be smarter. Booleans cannot be used, so please specify booleans in object mode.

import bpy
import bmesh

# This script adds a new integer attribute to the vertices of a mesh object named "Cube".
# It then sets the attribute values for each vertex, with specific values for vertices
# with index 1 and 2, and prints the attribute values.

# Get the target mesh object
mesh = bpy.data.objects["Cube"].data

# Add a new attribute
attribute_name = "new_attribute"
attribute = mesh.attributes.new(name=attribute_name, type="INT", domain="POINT")

# Get the BMesh in edit mode
bm = bmesh.from_edit_mesh(mesh)

# Get the attribute layer
layer = bm.verts.layers.int.get(attribute.name)
if layer is None:
    layer = bm.verts.layers.int.new(attribute.name)

# Set the attribute value for all vertices
for vert in bm.verts:
    if vert.index in [1, 2]:
        vert[layer] = 5
    else:
        vert[layer] = int(vert.index)

# Display the set attribute values
for vert in bm.verts:
    print(f"Vertex {vert.index} attribute value: {vert[layer]}")

# Update the mesh
bmesh.update_edit_mesh(mesh)

enter image description here

Manually setting custom attributes per edge / vertex / etc

$\endgroup$
2
  • 1
    $\begingroup$ Hello, this is a great answer, but I feel like it does not really answer the actual question. The advantage of using foreach_get and foreach_set is that it's magnitudes faster than direct attribution with a for loop. You won't notice the difference with 8 vertices, but with 8 million vertices you'll see it instantly. Cheers $\endgroup$
    – Gorgious
    Commented May 20 at 7:41
  • $\begingroup$ @Gorgious Thanks again for your comments. I certainly didn't know what such a useful function was. Looks like I need to learn how to manage larger numbers!😂 $\endgroup$
    – mml
    Commented May 20 at 10:54

You must log in to answer this question.

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