A new version of Cineversity has been launched. This legacy site and its tutorials will remain accessible for a limited transition period

Visit the New Cineversity


 ·   Wiki Home
 ·   Categories
 ·   Title List
 ·   Uncategorized Pages
 ·   Random Page
 ·   Recent Changes
 ·   RSS
 ·   Atom
 ·   What Links Here



Create or Find Page:


View Python: DescIDs and Animation


The trickiest part of dealing with animation tracks in Python is the concept of DescIDs.

DescIDs are actually used throughout CINEMA 4D, but they’re especially important when working with animation tracks. A DescID is a multi-level ID structure for individual description elements. The DescID can define multiple levels of data, like with UserData, where the first element of the DescID is always ID_USERDATA and the second element is the index for each userdata element. The multiple levels of a DescID are also used for subchannels, like the individual vector elements of a Position, Scale, Rotation or Color element.

Each element of a DescID is a DescLevel. The DescLevel also has three elements - in this case, they are the id itself, the data type and the creator.

Let’s look at some examples:

Creating tracks for simple description elements

If a description element doesn’t have sub-channels, the DescID is simply the ID of the description element.

# Track for Object Enabled Boolean
enabled = c4d.CTrack(op, c4d.DescID(c4d.ID_BASEOBJECT_GENERATOR_FLAG))
# Track for Light Brightness Real
track = c4d.CTrack(op,c4d.DescID(c4d.LIGHT_BRIGHTNESS))

Creating Position X, Y, Z tracks

Note that each vector element has its own track, just like in C4D’s timeline. The DescID for each contains two levels. Level 1 in each case is the Position track itself, which has a VECTOR type. This is the parent Position element you see in the timeline. Level 2 is the vector element for this specific track, and has a REAL type.


trackX = c4d.CTrack(op,
trackY = c4d.CTrack(op,
trackZ = c4d.CTrack(op,

Creating tracks for userdata

When you create userdata or iterate through the userdata container, the ID you get is the DescID. However, for elements with subchannels like vectors or color, you still have to add individual tracks for each subchannel. This code sample elaborates on DescIDs and DescLevels through some print statements and also contains a custom function that creates the appropriate tracks for certain userdata types. Not all possible types are considered - it’s just a start.


import c4d

def CreateUDTrack(op,id):
    tracks = []
    # element0 is always UD group
    # element1 is the UD itself
    ud = id[1]
    dtype = ud.dtype
    if dtype == c4d.DTYPE_VECTOR or dtype == c4d.DTYPE_COLOR:
        # get datatypes with subchannels and add multiple tracks
        for v in xrange(c4d.VECTOR_X, c4d.VECTOR_Z+1):
            descID = c4d.DescID(id[0],id[1],c4d.DescLevel(v,c4d.DTYPE_REAL))
        # just add the single track

    return tracks

def main():
    for id, bc in op.GetUserDataContainer():
        # id is the DescID, bc is the container
        print bc[c4d.DESC_NAME], id
        # look at each DescLevel
        # this isn't necessary, just instructive
        for level in xrange(id.GetDepth()):
            print "Level ", level, ": ", \
                  id[level].id, ",", \
                  id[level].dtype, ",", \
        # Create tracks using custom function
        tracks = CreateUDTrack(op,id)
        # Loop through returned tracks and insert
        for track in tracks:

if __name__=='__main__':


Finding a Track

In Release 13 and greater, you can use FindCTrack to find an existing animation track for a particular DescID. It’s a good idea to do this if you’re not sure if the track exists. Otherwise, C4D will just create additional tracks for the same parameter.


# Track for Light Brightness Real
dBrightness = c4d.DescID(c4d.LIGHT_BRIGHTNESS) #assign the DescID to a var for convenience
tBrightness = op.FindCTrack(dBrightness) #find the track
if not tBrightness:                      #if track isn't found, create it
    tBrightness = c4d.CTrack(op,dBrightness)


Adding Keys

Once you have the necessary tracks, adding keys is relatively simple. All the keys are applied to an F-Curve, which is a CCurve object in Python. So first you have to get the CCurve, and then you can use AddKey or InsertKey to add keys to the curve. Note that you can use the CTrack method FillKey to fill a key with the default values for the track, setting the appropriate interpolation. Also, you should use SetValue when setting a float value, and SetGeData when setting any other data type.


#Get the curve
curve = track.GetCurve()

#Add keys using AddKey
#Creates the key at the proper time
#Then you modify the key
keyDict = curve.AddKey(c4d.BaseTime(0))
#keyDict is a dict with key=CKey and int=index
myKey = keyDict["key"]
#Use FillKey to fill the key with default values (interpolation)
#Use SetValue or SetGeData to set the key value
#Add keys using InsertKey
#Define the key first
key = c4d.CKey()
#Use FillKey to fill the key with default values (interpolation)
#Then insert it


Setting the Keyframe Selection

A similar task also involving DescIDs is setting the Keyframe Selection for an Object. You can use this in conjunction with the record button to create tracks, but the direct method specified above is more robust. You might however wish to enable keyframe selection on specific description IDs if you’re generating a rig or other object in Python which the user will be animating.



# Put the "Position" desclevel in a variable for convenience
pos = c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION, c4d.DA_VECTOR)
# Set Keyframe selection on each vector X,Y,Z
op.SetKeyframeSelection(c4d.DescID(pos,c4d.DescLevel(c4d.VECTOR_X, c4d.DA_REAL, c4d.DA_VECTOR)), True)
op.SetKeyframeSelection(c4d.DescID(pos,c4d.DescLevel(c4d.VECTOR_Y, c4d.DA_REAL, c4d.DA_VECTOR)), True)
op.SetKeyframeSelection(c4d.DescID(pos,c4d.DescLevel(c4d.VECTOR_Z, c4d.DA_REAL, c4d.DA_VECTOR)), True)
# Update the C4D Interface