3
$\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
    Mar 16 '21 at 11:49
  • 1
    $\begingroup$ (btw I think using a float64 array is pointless cause Blender only stores float32s) $\endgroup$
    – scurest
    Mar 16 '21 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
    Mar 16 '21 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
    Mar 16 '21 at 11:59
  • $\begingroup$ Thank you a lot! All works fine! $\endgroup$
    – mifth
    Mar 16 '21 at 13:13
3
$\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$
5
  • 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
    Mar 16 '21 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
    Mar 16 '21 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
    Mar 16 '21 at 22:36
  • $\begingroup$ Thank you for clarification. Is it possible to replace 0.0 values with zeros of np.array? $\endgroup$
    – mifth
    Mar 16 '21 at 23:11
  • 1
    $\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
    Oct 29 '21 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.