View Python: Creating objects and modifying parameters
First of all, in this article, I will distinguish between objects in Cinema 4D’s
Object-manager, and instances that are objects in a programming-languages context.
Objects in the Object-Manager of Cinema 4D are represented by instances of the
c4d.BaseObject class. It is a
subclass of c4d.BaseList2D
class which basically implements the hierarchial arranged structure you can find
very often in Cinema 4D. (Object-Manager, Layer-Channel, Renderoptions,
etc.) Subclassing allows us to use methods implemented in a parent-class
in it’s subclass. Any method that c4d.BaseList2D
implements can be used from an instance of
c4d.BaseObject.
Modifying an object’s parameters
Every instance of c4d.BaseList2D
owns a reference to an object of the c4d.BaseContainer
class. It is basically is an associative array
containg all the values of the parameters an object has in the Attribute-Manager.
1. Accessing the BaseContainer and using it’s methods
Modifieng an object’s parameter is simple in that case. First, we get the
c4d.BaseContainer instance. Next,
we take the ID of the parameter we want to change and change the value in the
container. That’s all.
Make sure that a cube-object is selected in the Object-manager before running
the script in the Script-manager.
import c4d bc = op.GetDataInstance() bc.SetVector(c4d.PRIM_CUBE_LEN, c4d.Vector(500, 100, 20))
Note, c4d.BaseContainer.GetDataInstance()
returns the original container, NOT A COPY. Modifieng this container will
directly modify the object’s parameters. If you want to get a copy, use
c4d.BaseObject.GetData()
2. Accessing the BaseContainer and using subscripting
There is a more convenient way, an alternative of using methods like SetVector, SetReal, etc. The trick is called subscripting using the bracket [] syntax.
import c4d bc = op.GetDataInstance() bc[c4d.PRIM_CUBE_LEN] = c4d.Vector(500, 100, 20)
3. Using subscripting directly on the object
The third and last way to modify an object’s parameters is to use the subscripting syntax directly on the object itself, which you will most likely see in most of the Py4D codes available.
import c4d op[c4d.PRIM_CUBE_LEN] = c4d.Vector(500, 100, 20)
But what’s better?
Basically, you can say: “The more inconvenient, the more efficient.” which
is normal in computer-programming. Adding more and more easy-of-use
to anything requires something being wrapped that will produce overhead in doing
what it is supposed to do.
We can say that, method #1 is the fastest way,
method #2 in between and
method #3 the slowest. But why is this?
Imagine you are an automated glass-container that seperates different types of
glass from each other. Method #1 wouldn’t you require to think about anything,
you are being told where to put the incoming glass, and that’s fine. Method #2,
in contrast, doesn’t tell you what type of glass is incoming, you have to check
where to put it, which requires a little more time. Finally, method #3 would be
like giving the glass to the attendant of the dump because someone’s in a hurry,
who then gives the glass to you, and you are executing method #2.
Creating new objects in Python
Fine, now that we’ve discussed about how to modify and object’s parameters, we
can go on on how to create an object from Python.
There are several way of doing so.
1. Create an all new object from scratch
As already said in the first section, every object in the Object-manager is an instance of the c4d.BaseObject<7span> class. Why not creating an instance of this class directly? It’s simple. The constructor takes a single argument that defines the type of object that should be constructed.
import c4d op = c4d.BaseObject(c4d.Ocube)
Hm, got an object now. But what to do with it? There are different ways of inserting an object into a document. You can either use the current document or another object to do so.
import c4d op = c4d.BaseObject(c4d.Ocube) doc.InsertObject(op) # .. or .. op.InsertBefore(doc.GetFirstObject())
Both ways end in the same result, but using the first one has a big advantage. If doc.GetFirstObject() results in None, that is when no object is in the document, the call will boil down to op.InsertBefore(None) which will cause an exception.
2. Cloning an existing object
Test the following script only if you can accept Cinema 4D to crash!
op = doc.GetFirstObject() op.InsertUnder(op)
Here you got one of the simplest examples of how to crash Cinema 4D. But can you
imagine of why this would cause a crash?
It is simple, actually. With op you have the reference to the
real internal instance of the first object in the OM. Inserting an object
under it’s exactly same instance will cause an infinite loop.
- MyUniqueCube
- MyUniqueCube
- MyUniqueCube
- [and so on ... ]
- MyUniqueCube
- MyUniqueCube
What do we learn from this? DO NEVER INSERT AN OBJECT THAT IS ALREADY STORED
SOMEWHERE ELSE.
You can avoid this by creating a copy of the object.
op = doc.GetFirstObject() op.InsertUnder(op.GetClone())