Take Control Effector takes control over selected clone. Select clone ID and then clone is linked to the Effector. When you move the Effector, clone moves with it in Effector’s coordinate space.

Besides changing PSR, you can also modify clone (works only with Cloner object), set custom clone weight, or change clone color. Take Control Effector works properly with Cloner object when ‘Fix Clone’ checkbox is ticked. There is also checkboxes to activate/deactivate position, scale and rotation linking in ‘Matrix’ group.

There is handy ‘Go To Origin’ button that moves effector to clone’s original position (before this effector is calculated).

Warning! There is a bug in C4D (at least in R20.059) with Fracture Object. You can fix this putting Plain Effector before Take Control Effector to Fracture Object and then adjusting ‘Weight Transform’ parameter (just drag it around). After that you can delete Plain Effector.

Updated 26/04/2019
> Complete rebuild

Updated 30/05/2019
> Changed ‘Visible’ option

take_control_effector.c4d

Cinema 4D, Effector, MoGraph, Python

I’m currently working with one project where I mess with OBJ sequences (recorded with Brekel Pro PointCloud), so I created a script that loads OBJ files from a folder and a Python Tag that plays through objects making them visible and invisible depending the current frame.

Import obj folder

import c4d, os
from c4d import storage as s
def main():
    extensions = ["obj"] # File extensions that will be imported
    folder = s.LoadDialog(c4d.FILESELECTTYPE_ANYTHING,'Select folder to import',c4d.FILESELECT_DIRECTORY,'') # Load folder
    if not folder: return # If there is no folder, stop the script
    files = os.listdir(folder) # Get files
    for f in files: # Loop through files
        ext = f.rsplit(".",1) # Get file extension
        if ext[1] in extensions: # If extension matches
            c4d.documents.MergeDocument(doc, folder+'\\'+f, 1) # Merge file to current project
    c4d.EventAdd() # Update Cinema 4D
if __name__=='__main__':
    main()

OBJ Sequence Player

This is Python Tag with some custom constrols on it. You can change starting frame, reverse sequence and animate manually with custom mode. Controls are in Python Tag.

import c4d

def main():
    frame = doc[c4d.DOCUMENT_TIME].GetFrame(doc[c4d.DOCUMENT_FPS]) # Get current frame
    obj = op.GetObject() # Get object
    children = obj.GetChildren() # Get children
    index = 0 # Initialize index variable
    run = 0 # Initialize run variable

    rev = op[c4d.ID_USERDATA,2] # User data: Reverse sequence
    start = op[c4d.ID_USERDATA,3] # User data: Starting frame
    holdf = op[c4d.ID_USERDATA,4] # User data: Hold first frame
    holdl = op[c4d.ID_USERDATA,5] # User data: Hold last frame
    manon = op[c4d.ID_USERDATA,7] # User data: Activate manual mode
    manfr = op[c4d.ID_USERDATA,8] # User data: Set manual frame

    if manon == False: # If manual mode is off
        if rev == False: # If reverse mode is off
            for child in children: # Loop through children
                if frame == index+start: # If index maches with current frame
                    child[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2 # Default
                    child[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2 # Default
                    run = 1 # Sequence is running
                else: # Otherwise
                    child[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1 # Off
                    child[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1 # Off
                index = index + 1 # Increase index
        else: # Otherwise
            for child in reversed(children): # Loop through reversed children
                if frame == index+start:
                    child[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2
                    child[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2
                    run = 1
                else: # Otherwise
                    child[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
                    child[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
                index = index + 1

        if holdf == True and run == 0: # If hold start frame is on
            if frame < len(children)+start: if rev == True: children[-1][c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2 children[-1][c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2 else: children[0][c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2 children[0][c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2 if holdl == True and run == 0: # If hold last frame is on if frame >= len(children)+start:
                if rev == True:
                    children[0][c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2
                    children[0][c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2
                else:
                    children[-1][c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2
                    children[-1][c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2
    else: # Manual mode is on
        for i, child in enumerate(children): # Loop through children
            if i == manfr: # If index is same as custom frame
                children[manfr][c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2
                children[manfr][c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2
            else: # Otherwise
                child[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
                child[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1

Updated 31/03/2019

obj_sequence_player.c4d

Asset, Cinema 4D, Python

I use a lot of custom assets in every single project. Those assets can be very big MoGraph setups, Xpresso rigs, Python Generators or whatever. That’s why I had an idea to make a little script that merges your asset from absolute file path to your existing project.

Instead searching your asset every time in folders or content browser, you can simply create custom asset with this script and place it to Cinema 4D’s layout.

import c4d

def main():
    doc.StartUndo() # Start recording undos
    path = "C:\\c4d-assets\\my-asset.c4d" # Your asset file path, change this
    flags = c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS | c4d.SCENEFILTER_MERGESCENE # Merge objects and materials
    c4d.documents.MergeDocument(doc, path, flags) # Merge asset to active project
    c4d.EventAdd() # Refresh Cinema 4D
    doc.EndUndo() # Stop recording undos
if __name__=='__main__':
    main()

You can also use this to load models (obj, abc, fbx) or different c4d projects into your active document.
If you use Mac, use “/” instead “\\” (line 5)

Updated 26/03/2019

Cinema 4D, Python

Nowadays many clients wants to burn subtitles straight into video so they can put video to social media etc. so I made two scripts that makes working with After Effects and subtitles a little bit easier.

With the first script you can import srt files and the script makes automatically text layers from that subtitle file. I wanted to make text layers instead of keyframed sourceText since individual layers gives better control and are sometimes also lighter to process.

  1. Make composition or use current one, but there needs to be a open composition.
  2. Run the script (File > Scripts > Run Script File…)
  3. Select the srt-file to import
  4. Text layers are generated

AR_ImportSRT.jsx

With second script you can export text layers to srt file. Your text layers should look something like in the image: use ascending layer stacking.

AR_ExportSRT.jsx

After Effects, JavaScript

FolderLink is asset made with Xpresso and Python that allows you to select folder which includes specific file types. You can decide which kind of file types you are looking for by typing file extensions (separated with comma). FolderLink will scan selected folder (top level) and collects approved files to dropdown menu.

Then you can link easily and quickly browse between different files with dropdown menu and link selected file’s file path to whatever you like, for example to textures or HDRIs.

import c4d, os # Import necessary libraries

def main():
    global path # Output file path
    string = search # Get extensions string
    string = search.replace(" ","") # Remove spaces
    extensions = string.split(",") # Split to list
    c = 0 # Initialize iteration variable
    names = [] # Initialize list for file names
    obj = doc.SearchObject("FolderLink")
    cycle = c4d.BaseContainer() # Initialize base container
    bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG) # Integer
    bc.SetString(c4d.DESC_NAME, "File") # Set user data name
    bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE) # Set user data gui
    try: # Try to execute following code
        if folder != "": # If there is folder
            files = os.listdir(folder) # Get files from folder
            for f in files: # Iterate through files
                ext = f.rsplit(".",1) # Get file extension
                if ext[1] in extensions: # If file extension matches
                    c += 1 # Increase iteration
                    cycle.SetString(c, f) # Add item to user data cycle
                    names.append(f) # Add file name to list
            bc.SetContainer(c4d.DESC_CYCLE, cycle) # Set container
            obj.SetUserDataContainer([c4d.ID_USERDATA, 5], bc) # Update user data
            path = folder+"\\"+names[select-1] # Return file path
        else: # Else
            path = "" # Return empty string
    except IndexError: # If something went wrong
        path = "" # Return empty string

If you use Mac OS X you might have to change line 26 “\\” to “/”.
I updated the file so now it’s possible to filter files by filename extension. Thanks to @lasse_lauch for this suggestion.

folderlink.c4d

Asset, Cinema 4D, Python, Xpresso

I made some experiments with Processing to send data to Cinema 4D with OSC (Open Sound Control) protocol.

Tools you need

  1. Maxon Cinema 4D
  2. fOSC v1.1.1 plug-in for Cinema 4D (https://github.com/fillmember/fOSC)
  3. Processing v3.5.3 (https://processing.org/download/)
  4. oscP5 v0.9.9 library for Processing (http://www.sojamo.de/libraries/oscP5/)
  5. Different Processing libraries depending what you want to do (e.g. Kinect, Leap Motion, The MidiBus)

Processing OSC template
Here is basic Processing example that sends OSC data. In this example sketch generates a window where mouse position is captured and then remapped to more nice values for Cinema 4D (y-axis is flipped and sketch middle point is the origin) and then data is send with OSC.

import oscP5.*; // Import oscP5 library
import netP5.*; // Import oscP5's net library

OscP5 osc; // Declare oscP5 object
NetAddress net; // Declare net address object

void setup() { // Sketch basic settings
  size(640, 640); // Set sketch window size (width, height)
  osc = new OscP5(this, 6449); // Set new OscP5 object
  net = new NetAddress("127.0.0.1", 32000); // Set new net address
}

void draw() { // Processing will run this function constantly
  clear(); // Clear window every frame
  float posX = mouseX; // Get mouse x-position
  float posY = mouseY; // Get mouse y-position
  circle(posX, posY, 25); // Draw circle to mouse position
  float x = map(posX, 0, width, (width/2.0)*-1, width/2.0); // Remap x value
  float y = map(posY, 0, height, height/2.0, (height/2.0)*-1); // Remap y value
  send(x, y); // Run send function
}

void send(float value_a, float value_b) {
    OscMessage message_1 = new OscMessage("Mouse Position"); // Initialize new OSC message
    message_1.add(value_a); // 1st x-position
    message_1.add(value_b); // 2nd y-position
    osc.send(message_1, net); // Send OSC message
}

With fOSC plug-in you want to listen to port 32000.

fOSC makes null object for every individual OSC message and you can assign position and rotation parameters to message using add() method. Then you can use Xpresso to remap those values to whatever you want to.

Cheat sheet

  1. value controls X-position.
  2. value controls Y-position.
  3. value controls Z-position.
  4. value controls H-rotation.
  5. value controls P-rotation.
  6. value controls B-rotation.

Example sketch:
Track brightest pixel from webcam and send that via OSC

Updated 14/04/2019

Cinema 4D, Experimental, Processing

Super simple setup to count beats per minute in Xpresso with Python node. Counting starts immediately when time is running. You can easily modify code  for your needs e.g. starting time.

import c4d

def main():
    global out # Output port: 'Out'

    bpm = 128 # Beats per minute
    spb = 60.0 / int(bpm) # Seconds per beat

    if time != 0: # If current frame is not first frame
        out = int(time/spb) # Hits count
    else: # Otherwise
        out = 0 # Hits count is 0

bpm_in_xpresso.c4d

Cinema 4D, Python, Xpresso

I had some fun trying to recreate @Sholmedal‘s Python Tag Vertex Map tools which he showed at his presentation at IBC 2014. I ended up with some different Python Tags.

N.B. This post is kind of obsolete now since you can do all kind of crazy stuff with fields in R20. I’ll keep this here anyway for learning purposes.

Falloff setup
This setup creates weight values to the Vertex Map. Control position with a Null.

import c4d
from c4d import utils as u

def main():
    vertexMap = op[c4d.ID_USERDATA,1] # Get Vertex Map tag
    mind = op[c4d.ID_USERDATA,2] # User Data: Minumum distance
    maxd = op[c4d.ID_USERDATA,3] # User Data: Maximum distance
    spline = op[c4d.ID_USERDATA,4] # User Data: Remap spline
    
    obj = vertexMap.GetObject() # Get object that Vertex Map uses
    pts = obj.GetAllPoints() # Get object's all points
    null = op.GetObject() # Get null object that Python Tag uses
    null[c4d.NULLOBJECT_RADIUS] = maxd # Set null's radius
    nullPosition = null.GetMg().off # Get null's position vector
    array = [0.0] # Initialize list
    if len(array) != len(pts): # If array is not same size as object's point count
        diff = len(pts) - len(array) # Get difference
        array.extend([0.0]*diff) # Extend array
    for i in xrange(len(pts)): # Iterate through points
        point = pts[i] # Get point
        distance = (nullPosition - point).GetLength() # Calculate distance
        value = u.RangeMap(distance,mind,maxd,1,0,False,spline) # Remap value
        array[i] = u.Boxstep(0,1,value) # Clamp value between zero and one
    vertexMap.SetAllHighlevelData(array) # Set the data for the Vertex Map

vertex_map_python_tag_falloff.c4d

Math
Combine two Vertex Maps together with different math operations, like add, substract and intersect.

import c4d
import operator as o

def main():
    # User data
    tagA = op[c4d.ID_USERDATA,1] # Get Vertex Map tag A
    tagB = op[c4d.ID_USERDATA,2] # Get Vertex Map tag B
    tagC = op[c4d.ID_USERDATA,3] # Get Output Vertex Map tag
    func = op[c4d.ID_USERDATA,4] # Math operation selection
    invert = op[c4d.ID_USERDATA,5] # Invert checkbox
    
    dataA = tagA.GetAllHighlevelData() # Get Vertex Map A's data
    dataB = tagB.GetAllHighlevelData() # Get Vertex Map B's data
    if func == 0: # If add
        dataC = map(o.add, dataA, dataB) # Add A and B
    elif func == 1: # If substract B from A
        dataC = map(o.sub, dataA, dataB) # Subtract B from A
    elif func == 2: # If substract A from B
        dataC = map(o.sub, dataB, dataA) # Subtract A from B
    elif func == 3: # If intersection
        dataC = map(o.mul, dataB, dataA) # Intersection
    if invert == True: # If invert checkbox is ticked
        for i in range(0, len(dataA)): # Loop through array
            dataC[i] = 1-dataC[i] # Invert value
    tagC.SetAllHighlevelData(dataC) # Set the data for the Vertex Map

vertex_map_python_tag_math.c4d

Remap
With this you can remap source data with a spline to something different.

import c4d
from c4d import utils as u

def main():
    source = op[c4d.ID_USERDATA,1] # User Data: Source Vertex Map tag
    target = op[c4d.ID_USERDATA,3] # User Data: Output Vertex Map tag
    spline = op[c4d.ID_USERDATA,4] # User Data: Remap spline
    sourceData = source.GetAllHighlevelData() # Get Vertex Map data
    array = [0.0] # Initialize list
    if len(array) != len(sourceData): # If array is not same size as sourceData list
        diff = len(sourceData) - len(array) # Get difference
        array.extend([0.0]*diff) # Extend array
    for i in xrange(0, len(sourceData)): # Iterate through data
        value = u.RangeMap(sourceData[i],0,1,0,1,False,spline) # Remap data
        array[i] = u.Boxstep(0,1,value) # Clamp value between zero and one
    target.SetAllHighlevelData(array) # Set the data for the output Vertex Map

vertex_map_python_tag_remap.c4d

Decay
With this you can decay source Vertex Map.

import c4d

array = [0.0] # Initialize global list
def main():
    global array # Get access to global list
    source = op[c4d.ID_USERDATA,1] # User Data: Source Vertex Map tag
    target = op[c4d.ID_USERDATA,3] # Data Data: Output Vertex Map tag
    decay = op[c4d.ID_USERDATA,2] # User Data: Amount of decay in percentage
    sourceData = source.GetAllHighlevelData() # Get source Vertex Map data

    if len(array) != len(sourceData): # If array is not same size as sourceData list
        diff = len(sourceData) - len(array) # Get difference
        array.extend([0.0]*diff) # Extend array
    for i in xrange(0, len(sourceData)): # Iterate through data
        array[i] = array[i]+sourceData[i] # Value is prev value + source value
        if array[i] > 1: # If value is over '1'
            array[i] = 1.0 # Clamp value to '1'
        if array[i] > 0: # If value is over '0'
            array[i] = array[i]-decay # Decay value
        if array[i] < 0: # If value is below '0'
            array[i] = 0.0 # Clamp value to '0'
    target.SetAllHighlevelData(array) # Set the data for the output Vertex Map

vertex_map_python_tag_decay.c4d

Cinema 4D, Python, Tag

Here is easy Xpresso setup that drives X-Particles with MoGraph data. In this setup the cloner sets the amount of the XpEmitter’s particles. Emitter’s emission mode is set to “shot”. Then Xpresso iterates through the clones and sets position, rotation and color data from every single clone to X-Particle particles.

Now you can use for example XpTrail with your MoGraph setup instead using just old MoGraph Tracer object.

data_from_mograph_to_xpraticles.c4d

Cinema 4D, MoGraph, X-Particles