6
$\begingroup$

I want to store custom Vector attribute for each vertex (custom vertex positions). I want to get it through numpy as I have millions of vertices:

import bpy
import numpy

active_obj = bpy.context.active_object

active_obj.data.attributes.new(name='myAttribute', type='FLOAT_VECTOR', domain='POINT')

# set MAKES ERROR
test = numpy.empty(len(active_obj.data.vertices) * 3, dtype=numpy.float64)
active_obj.data.vertices.foreach_set('myAttribute', test)

# get MAKES ERROR
test2 = numpy.empty(len(active_obj.data.vertices) * 3, dtype=numpy.float64)
active_obj.data.vertices.foreach_get('myAttribute', test2)

I also found AttributeGroup. https://docs.blender.org/api/current/bpy.types.AttributeGroup.html#bpy.types.AttributeGroup

$\endgroup$
6
  • 1
    $\begingroup$ The attributes.new is the "right" way, what errors did you get? You use it like attributes['name'].data.foreach_get('vector', array). Other ways could be repurposing shape keys (if its a custom position). $\endgroup$
    – scurest
    Commented Mar 16, 2021 at 11:49
  • 1
    $\begingroup$ (btw I think using a float64 array is pointless cause Blender only stores float32s) $\endgroup$
    – scurest
    Commented Mar 16, 2021 at 11:50
  • $\begingroup$ Oh! You are right! I can create the attribute. But I cannot parse it with foreach_get/foreach_set I modified my question $\endgroup$
    – mifth
    Commented Mar 16, 2021 at 11:58
  • $\begingroup$ are you sure about float32? What if Blender Team will change it in future. May be I should leave float64? $\endgroup$
    – mifth
    Commented Mar 16, 2021 at 11:59
  • $\begingroup$ Thank you a lot! All works fine! $\endgroup$
    – mifth
    Commented Mar 16, 2021 at 13:13

1 Answer 1

6
$\begingroup$

Thanks to @scurest for answers in comments. Here is my working code now:

import bpy
import numpy

active_obj = bpy.context.active_object

active_obj.data.attributes.new(name='myAttribute', type='FLOAT_VECTOR', domain='POINT')

# set (you could also use numpy.empty)
test = numpy.zeros(len(active_obj.data.vertices) * 3, dtype=numpy.float32)
active_obj.data.attributes['myAttribute'].data.foreach_set('vector', test)

# get (you could also use numpy.empty)
test2 = numpy.zeros(len(active_obj.data.vertices) * 3, dtype=numpy.float32)
active_obj.data.attributes['myAttribute'].data.foreach_get('vector', test2)

Tested in Blender 2.92

$\endgroup$
9
  • 1
    $\begingroup$ One small thing, IMO would never set with np.empty could use np.zeros here, but one assumes that is the default anyhow. Perhaps for example sake get vert coords, manipulate and set to attribute.?? $\endgroup$
    – batFINGER
    Commented Mar 16, 2021 at 13:37
  • $\begingroup$ Thanks, I'll take into account. I tried np.zeros and np.empty with 12 million array of floats. No big difference. $\endgroup$
    – mifth
    Commented Mar 16, 2021 at 21:45
  • $\begingroup$ Not a speed issue. (empty is quicker since it allocates space not value) hence np.empty is likely full of rubbish values. No need to set with either since the default is already zero, and wouldn't bother to set with rubbish. $\endgroup$
    – batFINGER
    Commented Mar 16, 2021 at 22:36
  • $\begingroup$ Thank you for clarification. Is it possible to replace 0.0 values with zeros of np.array? $\endgroup$
    – mifth
    Commented Mar 16, 2021 at 23:11
  • 2
    $\begingroup$ How can I set a float array attribute instead of a float-vector array? I set FLOAT_VECTOR to FLOAT but what to but into vector in foreach_set? $\endgroup$
    – Phann
    Commented Oct 29, 2021 at 10:43

You must log in to answer this question.

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