5

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

Gorgious
  • 30,723
  • 2
  • 44
  • 101
mifth
  • 2,341
  • 28
  • 36
  • 1
    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). – scurest Mar 16 '21 at 11:49
  • 1
    (btw I think using a float64 array is pointless cause Blender only stores float32s) – scurest Mar 16 '21 at 11:50
  • Oh! You are right! I can create the attribute. But I cannot parse it with foreach_get/foreach_set I modified my question – mifth Mar 16 '21 at 11:58
  • are you sure about float32? What if Blender Team will change it in future. May be I should leave float64? – mifth Mar 16 '21 at 11:59
  • Thank you a lot! All works fine! – mifth Mar 16 '21 at 13:13
  • Perfect candidate re https://blender.meta.stackexchange.com/questions/2790/proposing-the-numpy-tag – batFINGER Mar 16 '21 at 13:27

1 Answers1

5

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

mifth
  • 2,341
  • 28
  • 36
  • 1
    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.?? – batFINGER Mar 16 '21 at 13:37
  • Thanks, I'll take into account. I tried np.zeros and np.empty with 12 million array of floats. No big difference. – mifth Mar 16 '21 at 21:45
  • 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. – batFINGER Mar 16 '21 at 22:36
  • Thank you for clarification. Is it possible to replace 0.0 values with zeros of np.array? – mifth Mar 16 '21 at 23:11
  • 2
    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? – Phann Oct 29 '21 at 10:43
  • @Phann You ever figure this out? – TheJeran Feb 02 '22 at 15:03
  • @TheJeran: No, unfortunately not, my workaround is numpy.array(myFloatValues * 3) with FLOAT_VECTOR and vector. See my full script based on the answer given here: https://blender.stackexchange.com/questions/241500/import-data-x-y-z-attributes-from-file-into-geometry-nodes/241870#241870 – Phann Feb 03 '22 at 19:26
  • @Phann Oh shit, sorry I thought I edited my comment. I figured out the answer is 'value' – TheJeran Feb 04 '22 at 08:45
  • @TheJeran: Awesome. Thank you for that information! I'll improve my answer with a reference to your comment. – Phann Feb 06 '22 at 20:41