2
$\begingroup$

This question is within the context of Geometry Node and drivers.

Using the Python API, we can retrieve the drivers associated to Geometry Nodes of a given node tree this way:

fcurves = tree.animation_data.drivers.values()
for fc in fcurves:
    print("fc data_path: " + fc.data_path + "   array_index=" + str(fc.array_index))

For a node with compound components (vector) such as this one: enter image description here

we will have the following result:

fc data_path: nodes["Switch.001"].inputs[2].default_value   array_index=0
fc data_path: nodes["Switch.001"].inputs[2].default_value   array_index=1

To get the path of the property, we need to append the array index to the data path, for example: nodes["Switch.001"].inputs[2].default_value[0]

For a node with non-compound component such as this one: enter image description here

we will have the following result:

fc data_path: nodes["Switch"].inputs[1].default_value   array_index=0

The problem is that the FCurve's array_index mentions 0 even though the property is not compound. So based on this information alone, we cannot determine the right path of the property: it may be either

nodes["Switch"].inputs[1].default_value[0]

or

nodes["Switch"].inputs[1].default_value

If array_index was set to -1 in the case of non-compound property, that would be unambiguous, but as it is 0 we cannot know with this information alone. Hence my question: how can we determine the right data_path of the property in such a case?

Note: a workaround is to access the node property input given the FCurve data_path and check its type dynamically. However this is cumbersome so I was looking for a cleaner way.

$\endgroup$
2
  • $\begingroup$ Why do you think there is any way other than accessing the input and checking the type? Actually it seem clear there is no other way, since the exact same fcurve in the same action applied to two different graphs may be addressing a scalar in one graph and the first element of an array in the other. $\endgroup$
    – scurest
    Commented Jun 15 at 16:33
  • $\begingroup$ I do not understand why this is not possible to differenciate the two cases at the FCurve level. As I mentioned, having array_index to -1 in case of scalar would have done the trick. Also I am not sure why the FCurve.data_path is not pointing to the exact field of the property it is operating on. But maybe I didn't understand well how FCurve can be used, as you seem to mention a same FCurve can be used within the context of two properties. If so this is not clear to me how this is represented in Blender. $\endgroup$
    – Alio
    Commented Jun 15 at 19:35

1 Answer 1

1
$\begingroup$

A function to check driver fcurve allows array_index > 0

import bpy

def is_array_fcurve(datablock, fc):
    try:
        v = eval(f"datablock.{fc.data_path}")
    except:
        return None # invalid datapath
    return hasattr(v, "__len__") # skip the str case since str can't add driver


# Exmaple:
ob = bpy.context.object

ob.driver_add("location")

fc = ob.animation_data.drivers.find("location")

is_array = is_array_fcurve(ob, fc)
if is_array is True:
    print("array")
elif is_array is False:
    print("not array")
$\endgroup$
2
  • 1
    $\begingroup$ You can use datablock.path_resolve(fc.data_path) instead of eval. $\endgroup$
    – scurest
    Commented Jun 16 at 3:00
  • $\begingroup$ Thanks, the whole point though was to use the FCuve alone, not the object (datablock). As I mentioned in the ending note, a workaround is to get to the object and check the type, which can be done as you did or using the node socket type. When having only the FCurve, getting the corresponding node is the cumbersome part, I did it by deconstructing the FCurve's data path, and this is what I wanted to avoid. Unfortunately I think there is no other way. $\endgroup$
    – Alio
    Commented Jun 16 at 9:38

You must log in to answer this question.

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