Механизм Geometry Nodes в Blender позволяет легко создавать для объектов дополнительные кастомные атрибуты и помещать в них нужные данные. Однако прямого доступа к таким атрибутам нет.
Если попробовать обратиться к созданному в Geometry Nodes атрибуту объекта по имени:
1 |
bpy.context.object.data.attributes['_attribute_name_'] |
Blender выдаст ошибку:
KeyError: ‘bpy_prop_collection[key]: key “_attribute_name_” not found’
Это происходит потому, что Geometry Nodes работают по принципу модификатора, наложенного на объект. Они не затрагивают его изначальное состояние, накладывая изменения “поверх”.
Так же, как и со всеми остальными модификаторами, все результаты работы Geomertry Nodes, в том числе и создаваемые в них атрибуты, могут быть получены с “рассчитанного” (evaluated) объекта.
Для примера добавим в сцену куб и назначим на него модификатор Geometry Nodes.
В нодовое дерево Geometry Nodes добавим нод Attribute Convert (shift+a – Attributes – Attribute Comvert). Во поле Attribute укажем “position” а в поле Result – любое имя для нового атрибута, например, “my_pos”. В результате Geometry Nodes создаст новый атрибут с этим именем и будет транслировать в него текущее положение объекта.
Если прямо сейчас попробовать обратиться к этому атрибуту:
1 |
bpy.context.object.data.attributes['my_pos'] |
Blender выдаст ту же самую ошибку, информируя, что указанный атрибут у данного объекта отсутствует.
Можно еще раз убедиться, что атрибутов у объекта нет, проверив список его атрибутов.
1 2 3 |
print(object_.data.attributes[:]) # [] |
Для того, чтобы получить доступ к атрибутам Geometry Nodes, нужно сначала “рассчитать” объект – получить его финальную копию.
1 2 3 |
obj = bpy.context.object.evaluated_get(bpy.context.evaluated_depsgraph_get()).data # <bpy_struct, Mesh("Cube") at 0x0000024E8E0F0108> |
В объекте obj теперь содержится полностью просчитанная копия активного объекта со всеми изменениями, произведёнными модификаторами и Geometry Nodes.
В рассчитанном объекте нужный атрибут уже присутствует:
1 2 3 |
print(obj.attributes[:]) # [bpy.data.meshes['Cube'].attributes['my_pos']] |
Теперь мы можем получить все нужные данные с атрибута по его имени.
Например, положение первой точки меша:
1 2 3 |
obj.attributes['my_pos'].data[0].vector # Vector((-1.0, -1.0, -1.0)) |
или список координат всех точек меша:
1 2 3 4 5 |
print([pos.vector for pos in obj.attributes['my_pos'].data]) # [Vector((-1.0, -1.0, -1.0)), Vector((-1.0, -1.0, 1.0)), Vector((-1.0, 1.0, -1.0)), Vector((-1.0, 1.0, 1.0)), Vector((1.0, -1.0, -1.0)), Vector((1.0, -1.0, 1.0)), Vector((1.0, 1.0, -1.0)), Vector((1.0, 1.0, 1.0))] |
Самое интересное что как только вы “отстегиваете” входную геометрию и пытаетесь сделать что то свое из примитивов то у вас практически пропадают все атрибуты у объекта
Это в принципе выглядит логичным, атрибуты это по сути свойства, присвоенные каждой точке меша. Если вы отключаете входную геометрию, вам не нужны и атрибуты отключенных точек.