Obtaining Properties from other objects with the Python Effector


#1

I just started learning how to use the Python effector, and I’m wondering if it’s possible for it to access other objects in the code the way Xpresso can. For example, I currently have the following setup:

As you can see, a value that I’m using in the Python effector depends on a value from a completely separate cloner that it is NOT affecting.

My question is this; is it possible to, from within the Python code, obtain those same values? Can a Python Effector object which is effecting object A access properties from object B? If so, how? Can you give an example?


#2

You simply need to pass the object in question into the Python node as a link.
Like so:
image

Then it’s just a matter of reading whatever you want from that object, e.g. like so:

import c4d

def main():
    global Cube_Size
    Cube_Size = An_Object.GetAbsPos().__abs__()
    # You can read(!) any parameter here, e.g. An_Object[c4d.PRIM_SPHERE_RAD]

And here’s the example scene, containing the above:
test_xpresso_param_access.c4d (222.4 KB)

One word of warning though:
You should not modify an object (including the host object of the Xpresso tag) from within the Python node. Instead pass your results to output ports and link these to the parameters of respective object nodes. I know, modifying objects from within the Python node may seem to work. But it’s a risky game, especially for other objects. Rather use the object node, internally it’s made in a way such changes happen safely and as expected.

Cheers


#3

this is really very useful and knowledgable blog!!


#4

very interesting and useful information i just found here keep it up@!!


#5

Thanks, but I’m not sure how to pass in the object as a paramter; I’m using a Python effector in my xpresso while you’re using a Python node. Is it possible to pass objects to a Python Effector? Right clicking on the blue section does not present the same options that a regular Python node presents.


#6

Sorry, my bad, my brain completely ignored the “Effector” part.

In Python effector there are global variables predefined, like in other parts of C4D’s Python scripting.
Mainly interesting probably:
op - In Python effector this is the effector itself
doc - The scene/document

With these you basically have two ways of accessing other objects.

Via doc (BaseDocument) you have functions like GetFirstObject(), GetObjects() or also SearchObject() and probably some more. In case of SearchObject() be aware, though, that in C4D object names are not necessarily unique.

Via op (or maybe also from an object found by above means) you can iterate the hierarchy with the standard GeListNode (a BaseObject is derived from GeListNode) methods: GetDown(), GetUp(), GetNext(), GetPred() plus a bunch of others.

Another option could be to add a User Data to the Python effector with a Link datatype. And then link the object in question there for easier access. Not only could this spare you the iteration/search part, but it would also make it more robust against scene hierarchy or naming changes.

In theory this should as long as the data read from another object is “static”. Like you want to read the radius of a sphere, which is not influenced by anything else (like Xpresso, …). Otherwise you will sooner or later run into priority issues, which may get difficult to solve (if at all).

@Cairyn has a nice series of Python tutorials. The hierarchy iteration got discussed here: https://www.patreon.com/posts/python-spoonfed-30982663

Cheers


#7

Which by the way is again evidence, I’m way more susceptible to visual input than text… :frowning:


#8

Thanks, this was helpful. You mentioned “adding a user data to the python effector with a link datatype.” How exactly do you do this? You can do this in xpresso with a regular python node:
image
But seemingly not with a python effector:
image


#9

User Data is a general concept, not related (but usable in) Xpresso.
In the Attribute Manager of an object (in this case the Python effector) there’s a User Data menu, where you can add and manage all User Data. In order to access User Data parameters via Python, you will unfortunately need to open the User Data Manger twice. First to add a new parameter and then second time to get the User Data ID, which only shows as <> when a new parameter gets added.
In Python you can access User Data (almost) the same as any other parameter, like so (assuming the object in need is referenced by variable obj):

obj[c4d.ID_USERDATA, <User Data ID>]

In Xpresso User Data ports can be added just like all other ports.

Cheers


#10

Thank you, this was helpful, and I figured out how to do it. However, just to make sure I’m understanding properly, you’re saying that this is the most efficient way to get access to those parameters in a Python effector:


Or is there a better way still?


#11

Ooopsy, I missed your reply. Sorry.

Well, I’m not sure, if this is the most efficient way. Neither have I done any benchmarks or comparison, nor would I claim to know everything. Another way could be the above described User Data of type Link (User Data on the Python Effector, dragging the Cloner to the parameter) and then read the parameters from the linked object directly in Python. Could avoid the need for Xpresso completely. If that’s leas or more efficient, I don’t know. You’d have to measure yourself.

Cheers