Master Slider Python Tag

This is simple Python Tag example that daisy chains children’s specific parameter and then you can control sequentially linked parameters. In this example there is a couple Sweep Objects and their ‘End Growth’ parameter is linked to the Master Slider.

Master Slider

If you have for example 20 children and want that 6 first are 100%, you should use following formula in theMaster Slider’s input field:

(100 / [childrencount]) * [nth child]

So in this case we would input: (100 / 20) * 6. It is recommended that linked parameter uses float values. If parameter uses different value than percentage, change “maxValue” variable accordingly.

import c4d
from c4d import utils as u

def main():
    slider = op[c4d.ID_USERDATA,1] # User Data: 'Slider'
    obj = op.GetObject() # Get object
    children = obj.GetChildren() # Get children list
    count = len(children) # Count of children
    maxValue = 1 # Parameter's maximum value (In this example it's 100%)
    step = (1 / float(count)) # Step size
    for i, child in enumerate(children): # Iterate through children
        if i == 0: # If first item
            r = u.RangeMap(slider, 0, step, 0, maxValue, True) # Map range
        else: # If anything else but first item
            r = u.RangeMap(slider, step*i, step*(i+1), 0, maxValue, True) # Map range
        child[c4d.SWEEPOBJECT_GROWTH] = r # Manipulate child's parameter

Originally I builded this setup for “Connect Spheres” Python Generator. It uses same algorithm in “Sequence” mode.

master_slider_python_tag.c4d

Master Slider 2

Thanks to @cristobalvila for requesting a delay function, I made Master Slider 2. There is options to offset slaves with ‘delay’ slider and remap output values with spline data.

import c4d
from c4d import utils as u

def main():
    try: # Try to execute following code
        slider = op[c4d.ID_USERDATA,1] # User Data: 'Slider'
        delay = op[c4d.ID_USERDATA,3] # User Data: 'Delay'
        spline = op[c4d.ID_USERDATA,4] # User Fata: 'Spline'
        obj = op.GetObject() # Get object
        children = obj.GetChildren() # Get children list
        count = len(children) # Count of children
        maxValue = 400 # Parameter's maximum value (In this example it's 100%)
        step = (1 / float(count)) # Step size
        for i, child in enumerate(children): # Iterate through children
            z = (delay*count) + (slider-delay)
            step = u.RangeMap(slider, 0, 1, 0, z, False)
            step = step-(delay*i)
            r = u.RangeMap(step, 0, 1, 0, maxValue, True, spline)
            child[c4d.PRIM_RECTANGLE_WIDTH] = r # Manipulate child's parameter
    except: # If comething went wrong
        pass # Do nothing

I’ll keep these files separated, since they operate a bit differently.

Updated 30/05/2019
> Added Master Slider 2 setup

master_slider_2_python_tag.c4d

Cinema 4D, Python, Tag

Custom Color Effector

This effector allows you to change clones’ color. I actually built this effector just to practise creating and deleting User Data with Python. There is nice documentation in Cineversity’s Wiki how to handle this kind of stuff.

You can add as many custom colors as you want. Remove button will delete always the latest group.

I don’t know if it is a bug or what, but I coudn’t hide the group titles. But if you go to “Manage User Data …” and just press OK, group titles will be removed. I have to investigate that issue and update solution when I get this solved.

custom_color_effector.c4d

Cinema 4D, Effector, Experimental, MoGraph, Python

Fade Clones Effector

This effector fades clone’s colors gradually over time. I made it originally for one commercial project and it was pretty handy in some cases.

You can choose start frame, when fading should start. You can change fading duration and step duration. Both changes overall animation time. You can also weight clones (it is a bit legacy option). You can also randomize fading order and set different random seed. There is also option to pick start and end colors and you can also remap fading with spline.

Updated 31/07/2019
> Now you can manually input indexes how you want them to appear
Updated 22/08/2019
> Added ‘Swap’ button for swapping colors quickly
> Added ‘Use Custom’ checkbox

fade_clones_effector.c4d

Cinema 4D, Effector, MoGraph, Python

Inheritance Python Tag

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 single Python Tag. This was super fun practice and here is my results.

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.

inheritance_python_tag.c4d

Asset, Cinema 4D, Python, Tag

Zero Scale Fix Effector

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

zero_scale_fix_effector.c4d

Cinema 4D, Effector, MoGraph, Python

Blog Update

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

Mix Gradients

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 count of knots with both gradients, otherwise rig won’t work. 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
        MixGrad.InsertKnot(resultList[i]['col'],
        resultList[i]['brightness'],
        resultList[i]['pos'],
        resultList[i]['bias'],
        resultList[i]['index'])
    GradOut = MixGrad # Output mixed gradient

mix_gradients.c4d

Asset, Cinema 4D, Python, Xpresso

Cinema 4D splines to After Effects masks

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)

AR_C4DSplinesToAeMasksPart1.py
AR_C4DSplinesToAEMasksPart2(CC).jsx

After Effects, Cinema 4D, JavaScript, Python

Connect X-Particles emitters

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

connect_xpemitters.c4d

Asset, Cinema 4D, Python, X-Particles

TurbulenceFD direction tool

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

tfd_direction_tool.c4d

Asset, Cinema 4D, Python, TurbulenceFD, Xpresso