instancing a deformer / copy all params

On 30/04/2017 at 09:13, xxxxxxxx wrote:


I am trying to figure out the best way to link all parameters of one object to another.

More fundamentally, I would like to understand the syntax behind object parameters, more specifically, the base objects, like the deformers, hypernurbs etc.

For any object, to address a parameter, you use square brackets.
To me, this suggests the object is a list/array.

Yet if I try to loop through it like this:

link = op[c4d.ID_USERDATA,1] # this is a link to another object
def main() :
    for a in link:
        print a

I get TypeError: 'c4d.BaseObject' object is not iterable

so whats the deal with this useage of square brackets?
And what is a good approach to get/set all object parameters? 
Maybe when I say "all" is a bit too vague, I assume they are categorised based on the tabs you see in the attribute manager, I don't know how/where this info is stored / accessed..

On 02/05/2017 at 10:13, xxxxxxxx wrote:

I guess you should read this relevant pdf from pgrooff User Data using Python.pdf

Basicly link is currently egal to an object. Not a link.
For testing it just do print link. YOu will se it's egal to the object linked and not directly to the link ui.

About object parameter I really encourage you to read and re-read to be sure to really understand what this mean about BaseContainer.
Basicly BaseContainer is like a list (more precisly a non ordered list).
So for exemple if we take a cube (create one yoo too, you will understand me way more by doing it yourself also than jsut by reading myself)

Now open the console and drag the parameter Size .X into the console.
You will saw Cube[c4d.PRIM_CUBE_LEN].
If you press Enter you get the current value of the cube.
Again in the console hit the top arrow key (like that you get your previous line executed).
This time remove [c4d.PRIM_CUBE_LEN] and press enter. You will have something like
<c4d.BaseObject object called 'Cube/Cube' with ID 5159 at adress in memory>
So Cube is our object.

Now again press the top arrow key and remove Cube and [] so we got c4d.PRIM_CUBE_LEN,c4d.VECTOR_X Press Enter.
And you will see two number. (1100, 1000)

Thoses two number are actually ID to acces parameter into the basecontainer(you remember the list?) of your object.

Then I think you will understand my following code

import c4d
def main() :
    #Get current selected obj
    obj = op
    #abord if is not a cube. c4d.Ocube = 5159 as we saw before in the console
    if not obj.CheckType(c4d.Ocube) :
    #Get the cube container instance.
    #it's an instance that mean any change we made into this container 
    # are automaticly replicated into the container of the object
    bc_cube = obj.GetDataInstance()
    #before we get 2 ID c4d.PRIM_CUBE_LEN which was egal to 1100 and c4d.VECTOR_X = 1000
    #In our case Since its Vector c4d divide his into multiple data like that we can retrieve only X parameter if we want.
    #But internally size Is an Vector(3 floats)
    #So for retrieve data we can do
    size = bc_cube.GetVector(1100) #or c4d.PRIM_CUBE_LEN is exactly the same just more visual than a number.
    size.x = 10 #we change the value of the vector, this is a variable, now we should update the container if we want to change obj properties
    bc_cube.SetVector(c4d.PRIM_CUBE_LEN, size)
    #Since we use GetDataInstance, and it's an instance we don't have to update the container of the object with'
    #trigger change
if __name__=='__main__':

Hope it's help you

On 02/05/2017 at 13:36, xxxxxxxx wrote:

Hi NNenov, thanks for writing us.

In addition to the extended explanation that gr4ph0s has gently provided I warmly suggest to have a look at the BaseObject Manual and to the BaseContainer Manual because, even though they both belong the C++ API, could help understanding the foundations of these two relevant Cinema classes.

Last but not least, the Python examples available on GitHub might be of valuable support to ease the learning curve of the concepts above.

Best, Riccardo

On 12/05/2017 at 13:09, xxxxxxxx wrote:

Hey! Sorry for the delay.
I think I understand, so GetDataInstance() will get an instance of all the settings stored for the object? like, position, generator parameters, etc. And to get their unique IDs, just put the id value in console, e.g. c4d.ID_MG_SHADER_SHADER returns 5000

So is it possible if the source and target are of same O type, that you can take one object's DataInstance and set it "to" the other?

I am trying to create a python generator with user data type link, so you can link to a deformer, and the python generator will "become" an "instance" of that deformer. Instance is perhaps the wrong word, I mean it would be generating a unique deformer, but that deformer will have all of it's parameters linked, and, actively updated, to those of the target in the user data field.

So far I have created a python generator, with user data, and linked it to the deformer I would like to "instance".

In the python code, I started by creating a base object using the type what has been linked

    oType = obj.GetType()
    clone = c4d.BaseObject(oType)

where obj is the user data link to deformer I want to mimic

now that I have this new generated deformer, I do:

    oDat = obj.GetDataInstance()

then return clone.
I was hoping this would set the new base object to all the same parameter, including local coordinates, but this doesn't work, there is no deformation on the sphere and the coordinates are unchanged.

Also if I make the python generator editable, it returns a Null object rather than the displace deformer base object. 
I don't get an error message either..

check screenshot: instance.jpg?dl=0


On 15/05/2017 at 01:26, xxxxxxxx wrote:

Not really you can copy it only if it's really the same type.

Understand Basecontainer just like a way for storing data. Is not because you store all the data from an object that he will act like another one. It have to be same.

But in your case it should work but I guess it's a limitation from the python generator (maybe if you register you own deformer you can do it). But I'm not sure wait a, official reply.

Anyway if you jsut want to get a clone why not make source.GetClone()

On 15/05/2017 at 10:27, xxxxxxxx wrote:

Hmm yeah I thought it would have to at least be the same type..
when you say .GetClone(), do you mean something like this in the python generator?

import c4d
obj = op[c4d.ID_USERDATA,1]
def main() :
    return obj.GetClone()

this doesn't seem to work either.
Maybe the reason this doesn't work is the same why an instance object referencing a deformer doesn't work either.. could it be something to do with the deformed point caches not being generated? Very curious about this.

On 16/05/2017 at 06:29, xxxxxxxx wrote:

Hi NNenov,

with reference to your request, consider that being the Python Generator (as properly pointed out by gr4ph0s) registered as OBJECT_GENERATOR, it impedes the generator to behave as a modifier since the  BaseObject::GetVirtualObjects() is actually implemented in the Python Generator itself. This goes beyond the fact that the data in your cloned object matches the one used in the source modifier object.

Last but not least, the Instance Object, as you have properly reported, doesn't work either since it's again registered as an OBJECT_GENERATOR as well. The official documentation on the generator states explicitly mention this behaviour.

Best, Riccardo

On 28/05/2017 at 13:42, xxxxxxxx wrote:

Hi KnickKnack,

Thanks for following up on this, I ended up making a python tag instead, with a link field user data.
It works with any object I've tried so far, instances all target parameters to whatever object the tag is applied to:

import c4d
source = op[c4d.ID_USERDATA,1]
target = op.GetObject()
def main() :
    oDat = source.GetDataInstance()