I saw @SamplisticMedia‘s NAB (2019) presentation where he talked about his neat Xpresso setup: SimpleMoves. I wanted to try to create similar setup, but using just a single Python Tag. This was a super fun practice project and hopefully this asset will be useful for someone.

Put Inheritance Tag to the object you want to control, then put target obejcts to ‘Targets’ list, then changing ‘Mix’ value you can move object from one target object to another one, also inheriting target’s position, scale and rotation.

‘Mix’ value works similarly how it works in SimpleMoves rig. 0% is first target, 100% is second target, 200% is third target and so on.


Asset, Cinema 4D, Python, Tag

This effector helps, when you are scaling clones and default MoGraph operations gives a weird results.

import c4d
from c4d.modules import mograph as mo

def main():
    method = op[c4d.ID_USERDATA,2] # User Data: Method
    negative = op[c4d.ID_USERDATA,3] # User Data: Negative Values
    md = mo.GeGetMoData(op) # Get MoData
    if md is None: return False # If there is no MoData, stop processing
    cnt = md.GetCount() # Get clone count
    marr = md.GetArray(c4d.MODATA_MATRIX) # Get MoData matrix
    farr = md.GetArray(c4d.MODATA_FLAGS) # Get MoData flags
    for i in xrange(0, cnt): # Iterate through clones
        sx = marr[i].v1.GetNormalized()[0] # Get scale x
        sy = marr[i].v2.GetNormalized()[1] # Get scale y
        sz = marr[i].v3.GetNormalized()[2] # Get scale z
        if negative == 1: # If 'Negative Values' checkbox is ticked
            if sx < 0: # If x is smaller than zero
                sx = 0 # Set x to zero
            if sy < 0: # If y is smaller than zero
                sy = 0 # Set y to zero
            if sz < 0: # If z is smaller than zero
                sz = 0 # Set z to zero
        if sx == 0: # If x-scale is zero
            marr[i].v1 = c4d.Vector(0.0000001,0,0) # Set x-scale to extreme small
        if sy == 0: # If y-scale is zero
            marr[i].v2 = c4d.Vector(0,0.0000001,0) # Set y-scale to extreme small
        if sz == 0: # If z-scale is zero
            marr[i].v3 = c4d.Vector(0,0,0.0000001) # Set z-scale to extreme small
        if method == 1: # If method is set to 'Hide'
            if sx == 0 or sy == 0 or sz == 0: # If some of the axis are zero
                farr[i] &= ~(c4d.MOGENFLAG_CLONE_ON) # Hide the clone
    md.SetArray(c4d.MODATA_FLAGS, farr, True) # Set MoData flags
    md.SetArray(c4d.MODATA_MATRIX, marr, True) # Set MoData matrix
    return True # Everything is fine


Cinema 4D, Effector, MoGraph, Python

It has been a bit quiet around here. Reason for that is because I have so many things going on. First of all I’m creating new websites for myself and this blog is going to get a completely new look.

I’m also rewriting all of my Cinema 4D scripts with comments and maybe with better code. After that I’m planning to do same for my After Effects scripts. So, I’ll organize my github better with nice readme-markup page. I’m also building a new computer for myself.

Many things to do that takes time but everything is progressing nicely.

General Talk

I made this gradient rig for a work project that I’m currently working with. With this Xpresso rig you can blend between two different gradients. You have to use same amount of knots with both gradients, otherwise the script won’t calculate correctly. There is options to restrict mixing to work only with knot position or color. I also added spline user data to remap gradient.

import c4d
from c4d import utils as u

def main():
    global GradOut # Output gradient
    GradCnt = Grad1.GetKnotCount() # Get start grad knot count
    knotListA = [] # List for storing knots
    knotListB = [] # List for storing knots
    resultList = [] # List for final grad
    for i in range(GradCnt): # Iterate through knots
        knotListA.append(Grad1.GetKnot(i)) # Store knot data
        knotListB.append(Grad2.GetKnot(i)) # Store knot data
    for i in range(GradCnt): # Loop
        if MPos: # If 'Mix Position' is enabled
            mixPos = u.MixNum(knotListA[i]['pos'],knotListB[i]['pos'], Mix) # Mix positions
        else: # Otherwise
            mixPos = knotListA[i]['pos'] # Take position from start gradient
        if MColor: # If 'Mix Color' is enabled
            mixCol = u.MixVec(knotListA[i]['col'],knotListB[i]['col'], Mix) # Mix colors
        else: # Otherwise
            mixCol = knotListA[i]['col'] # Take color from start gradient
        mixBias = u.MixNum(knotListA[i]['bias'],knotListB[i]['bias'], Mix) # Mix knots bias
        mixBrightness = u.MixNum(knotListA[i]['brightness'],knotListB[i]['brightness'], Mix)
        mixPos = u.RangeMap(mixPos, 0, 1, 0, 1, True, Spline) # Remap position with spline
        resultList.append({ # Collect mixed gradient data
        'brightness': mixBrightness,
        'index': i+1,
        'bias': mixBias,
        'pos': mixPos,
        'col': mixCol
    MixGrad = c4d.Gradient() # Initialize gradient
    for i in range(GradCnt): # Loop
    GradOut = MixGrad # Output mixed gradient


Asset, Cinema 4D, Python, Xpresso

Transfer animated splines from Cinema 4D to After Effects masks. There are two scripts: the first one is for exporting AI file sequence from Cinema 4D. The second script is for importing AI file sequence and converting it to single solid layer with mask paths in After Effects. Export script uses Cinema 4D’s ‘Sketch and Toon’ module so you need it to run export script. Cinema 4D script is tested with R19 and R20. After Effects script is tested with CC 2018.

Warning 1. The import script is super slow if you have many points. Try to use as minimum point count as you can! Tweak ‘Intermediate Points’ settings in Cinema 4D.

Warning 2. It is recommend that you export only one spline at a time since masks can easily get mixed up. But if that does not matter, then don’t care.

Exporting (C4D)

  1. Select spline objects you want to export
  2. Set the preview range to match what frames you want to export
  3. Run the script (c4d-splines-to-ae-masks-part1.py)
  4. Select folder where you want to save AI file sequence

Importing (After Effects)

  1. Run the script (c4d-splines-to-ae-masks-part2.jsx)
  2. Select folder to export AI file sequence
  3. Insert frame rate that you used in Cinema 4D
  4. Wait until the script is done (it may take a long time)

Special thanks to @lasse_lauch for testing.

Updated 04/10/2018
> Added script for After Effects CS6

Updated 06/04/2019
> Added progress status for import script (CC version)

Updated 24/08/2019
> Added export script that creates separated folders for each spline object
> Added import script that imports to shape layers instead of masks

Updated 04/10/2020
> Link updated

AR_Scripts / AR_ExportSplineSeq.py
(Navigate to the latest AR_Script folder and find that AR_ExportSplieSeq.py script)

ar_c4dsplinestoaemaskspart2(CC).jsx (Solid layer with masks)
ar_c4dsplinestoaeshapespart2(CC).jsx (Shape layer with shape paths)

After Effects, Cinema 4D, JavaScript, Python

Connect two X-Particles xpEmitters with splines with this Python Generator. You can also tweak amount of connections and spline interpolations.

You can also connect two xpEmitters using xpElektrix by setting Mode to ‘Particle to Particle’.

import c4d, xparticles
from c4d import utils as u

def main():
    connect = c4d.BaseObject(1011010) # Initializ connect object
    connect[c4d.CONNECTOBJECT_WELD] = False # Untick weld checkbox
    emittera = xparticles.ToEmitter(op[c4d.ID_USERDATA,1]) # Emitter A link
    emitterb = xparticles.ToEmitter(op[c4d.ID_USERDATA,4]) # Emitter B link
    connections = op[c4d.ID_USERDATA,2] # Amount of connections
    interp = op[c4d.ID_USERDATA,3] # Iterpolation for spline
    offset = op[c4d.ID_USERDATA,8] # Offset connections
    splines = [] # Initialize list for splines
    pca = emittera.GetParticleCount() # Get Emitter A's particle count
    pcb = emitterb.GetParticleCount() # Get Emitter B's particle count
    if pca > pcb: # If Emitter A's particle count is larger than Emitter B's
        op[c4d.ID_USERDATA,6] = str(pcb) # Maximum amount of connections
        tpc = pcb # Particle count to use
    else: # Otherwise
        op[c4d.ID_USERDATA,6] = str(pca) # Maximum amount of connections
        tpc = pca # Particle count to use
    try: # Try to execute following script
        for i in xrange(connections): # Loop through connections count
            points = [] # Initialize list for points
            if op[c4d.ID_USERDATA,10] == True: # If modulo checkbox is ticked
                offset = offset%tpc # Offset with modulo
            pa = emittera.GetParticle(i+offset) # Get Emitter A's particle index
            pap = pa.GetPosition() # Get Emitter A's particle's position
            pb = emitterb.GetParticle(i+offset) # Get Emitter B's particle index
            pbp = pb.GetPosition() # Get Emitter B's particle's position
            for k in xrange(interp): # Loop through interpolation count
                r = u.RangeMap(k, 0, interp, 0, 1, True) # Range map
                pp = u.MixVec(pap, pbp, r) # Get point's final position
                points.append(pp) # Add point to points list
            points.append(pbp) # Add last point
            spline = c4d.SplineObject(interp+1, c4d.SPLINETYPE_LINEAR) # Initialize spline object
            splines.append(spline) # Add spline to splines list
            splines[i].SetName("Spline"+str(i)) # Set name for spline object
            splines[i].SetAllPoints(points) # Set points to spline
            splines[i].InsertUnder(connect) # Insert spline under connect object
    except: # If something went wrong
        pass # Do nothing
    return connect # Return connect object that contains splines

Updated 16/10/2018
> Added offset option


Asset, Cinema 4D, Generator, Python, X-Particles

Controlling TurbulenceFD’s wind and buoyancy direction parameters with default vector input is not very intuitive. I made more artist friendly tool with Xpresso and Python so you can rotate spline object to aim direction for wind and buoyancy.

import c4d
from c4d.utils import SplineHelp

def main():
    global Vector # Output variable
    sh = SplineHelp() # Get a new spline help object
    sh.InitSpline(Spline) # Initialize spline help with object
    Vector = sh.GetNormal(0) # Get a normal vector


Asset, Cinema 4D, Python, TurbulenceFD, Xpresso

Here is three simple deletion effectors I made for fun. Perhaps they might be sometimes pretty useful. These effectors hides clones completely, they does not scale them to zero.

Delete by scale effector

Hides clones (visibility) based on clone’s scale parameter (not size). This helps to get rid off too tiny or too big clones when you are randomizing clones’ scale with e.g. random effector.


Delete random effector

Hides clones randomly. You can change seed to randomize which clones are deleted, change amount of deleted clones and invert the final output.


Delete by index effector

Hides clones by given index number or range. Indexes are separated with commas (,) and ranges are pointed with dashes (-). You can also invert the final output.


Updated 24/04/2019:
> Effectors now supports already hidden clones
> Fixed ‘Delete by scale Effector’ does not calculate only x scale but scale vector average

Cinema 4D, Effector, MoGraph, Python

This script is for Blackmagic Fusion. With this script you can easily view different versions. You can load newer version, older version, latest version or custom given version. You need to install Python 2.7 64-bit version to use this script with Fusion. The script scans folder so it can jump over versions that are missing (e.g. from v02 to v05).

Place the script to comp folder:
“C:\Users\[USER]\AppData\Roaming\Blackmagic Design\Fusion\Scripts\Comp”

Script uses “_v” as a version delimiter.

Your filepath should be something like this:
So next version path looks like this:

Path structure is very important. It should not change.


Fusion, Python

This is my first Cinema 4D plug-in. Originally I made it for Xpresso heavy users. This plug-in makes changing node’s color easy. Just select nodes and click what color you want to use. You can also load and save custom color palettes. You can also colorise objects and add objects to layers. Plug-in works also with Redshift shader graph editor’s nodes.

When you are chaning Xpresso node colors, Xpresso tag has to be selected, otherwise plug-in wont colorise nodes. And when you are changing Redshift nodes, the Redshift material has to be selected. Also make sure that you have enabled these in the options (File > Options)!

Place Colorise plug-in to your appdata plug-in folder to make it work properly (avoid permission errors), since plug-in has to write and read presets and options files.

Win: “C:\Users\[USER]\AppData\Roaming\MAXON\Cinema 4D R[VERSION]\plugins\”
Mac: “/Users/[USER]/Library/Preferences/MAXON/CINEMA 4D R[VERSION]/plugins”

Commands: (Keymofidier, Button)
Alt + [Color]: Select items with this color
Alt + Shift + [Color]: Add to selection items with this color
Alt + Ctrl + [Color]: Remove from selection items with this color
Ctrl + [Color]: Group selected objects under null and assign layer for selected objects
Shift + [Color]: Set objects layer to this colored layer
Shift + [X]: Remove selected objects’ layer
Alt + [X]: Sequence colors to selected items
Ctrl + [X]: Random colors to selected items

Thanks to @BachtellDesign and @_james_owen_ for new feature ideas.

N.B. In R20 Maxon added color picker next to the color field. It is not possible to get rid of. That’s why horizontal mode is disabled.

Updated 08/09/2019 (v0.5)
> R21 version – completely rewritten plug-in with new features and bug fixes

Updated 11/09/2019 (v0.5.1)
> Added option to colorise lights
> Improved Redshift node handling

Updated 12/10/2019 (v0.5.2)
> Added support to make polygon selections
> Fixed Redshift node-editor bug

Updated 14/03/2021 (v0.5.3)
> Cinema 4D R23 support

colorise_v0.4.6_r20.zip (Depricated)
colorise_v0.5.3.zip (works with R23)

Cinema 4D, Plug-in, Python, Redshift, Xpresso