6

I have read the answers to this question, so see you can access Geometry Nodes-generated attributes on an evaluated object using Python.

I'm attempting to access a mesh-wide vector-attribute in a driver. For testing purposes, a fixed vector value is plugged straight into the output node of a Geometry Nodes tree.

However, if I attempt to run v_attr(), a driver-namespace function, as defined below..

import bpy

def v_attr(obj_name, attr_name):

C = bpy.context
ob = bpy.data.objects [obj_name]
ev_dg = C.evaluated_depsgraph_get()
ev_me = ob.evaluated_get(ev_dg).data

return ev_me.attributes[attr_name].data[0].vector

bpy.app.driver_namespace['v_attr'] = v_attr

#print(v_attr('Plane', 'v_test').y)

.. inside a driver, Blender 3.0b freezes.

Run from the Python console, v_attr() returns correct values, as a vector, or its components. Permission to auto-run scripts has been granted in Preferences.

I apologise if this is a premature question on a beta-bug, but I doubt that it is.. it's much more likely to be me, maybe misunderstanding the depsgraph altogether? Or permissions?

If there are better ways to store a mesh-wide attribute than duplicated on every point, that would be good...

Robin Betts
  • 76,260
  • 8
  • 77
  • 190
  • may i ask where you added your driver to ? – Chris Nov 03 '21 at 03:55
  • All the mesh attributes store the same value ? Because then you can use a custom property instead like you would on a regular object – Gorgious Nov 03 '21 at 07:19
  • @chris I tried using v_attr('Plane', 'v_test').y in a scripted expression, to drive the Z location of an Empty. The result, for me, was a hang of (Linux) Blender 3.0b, requiring a kill of the Blender process. – Robin Betts Nov 03 '21 at 08:02
  • @Gorgious I was just wondering if there was such a thing as a declared 'Whole Object' domain for an attribute, from within GN, which would save duplicating a value as a layer across all elements of a geometry domain. If I use, say, an Attribute Statistic result as an output, that may have to be stored only once, for the mesh. – Robin Betts Nov 03 '21 at 08:10
  • @Gorgious sorry, that should be a 'Geometry' level domain: 1 attribute per hunk of geometry. – Robin Betts Nov 03 '21 at 08:25
  • Testing shows the function hangs on ev_dg = C.evaluated_depsgraph_get() : As most of the time in python scripting for Blender, the main culprit of hair pulling is incorrect context. I gather bpy.context is not good right there. Not the same tool but you may have better luck with this kind of implementation (handlers instead of drivers) https://blender.stackexchange.com/a/183440/86891 – Gorgious Nov 03 '21 at 10:37
  • @Gorgious Thanks for your work on this! (If only I had hair :D ) How did you locate the hang? A debugger? – Robin Betts Nov 03 '21 at 11:07
  • Nope nothing fancy I just added return after the first line then tried to run it, then moved it one line further until it hung :p – Gorgious Nov 03 '21 at 11:08
  • @Gorgious doooooooH ! – Robin Betts Nov 03 '21 at 11:12
  • @Gorgious: that’s how developer are doing…. – Chris Nov 03 '21 at 11:17

1 Answers1

2

Not a full solution, but since Blender 2.90 you can use the depsgraph variable in drivers to retrieve the current dependency graph, which helps you avoid using bpy.context:

import bpy

def v_attr(ev_dg, obj_name, attr_name):

ob = bpy.data.objects[obj_name]
ev_me = ob.evaluated_get(ev_dg).data

return ev_me.attributes[attr_name].data[0].vector

bpy.app.driver_namespace['v_attr'] = v_attr

Then in your driver function call, just add an argument depsgraph at the start.

However, even then, there is no depsgraph relation built between the mesh, which is why there is no automatic update (you must click on "Update Dependencies" on the driver to see changes).

Alternative implementation, without extending the driver namespace: bpy.data.objects["Plane"].evaluated_get(depsgraph).data.attributes["v_test"].data[0].vector.y. This warns about use of bpy.data, but there sadly is no way to retrieve an evaluated mesh through the driver variables.

RedMser
  • 21
  • 3