This effector randomizes position, scale and rotation with given values (fixed). You can change seed separately for position, scale and rotation. There are also global seed that changes all seeds. There is additive mode (‘Add’-checkbox) that adds random values to current state, otherwise values are overwrited.
Scale group has also ‘Uniform’-checkbox that scales clones uniformly, there is own input field for this. If this checkbox is ticked, you cant use X, Y or Z checkboxes.
Here are two old Python Tags of mine, that toggles object’s visibility based on different rules. I have find them very useful when you want maximise clarity in your viewport.
Show Only If Active
First tag shows the object only if object is selected (i.e. active). Sometimes this is very helpful, if you have for example bunch of deformers under one object and you want to focus to tweak just one. Just apply this tag to every deformers and then deformer is only visible when it is selected.
import c4d
def main():
obj = op.GetObject() # Get object
if obj == doc.GetActiveObject(): # If object is active
obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 0 # Set 'Visible in Editor' to 'On'
else: # Otherwise
obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1 # Set 'Visible in Editor' to 'Off'
Show Only If Correct Camera
Second tag shows the object only if correct camera is active. There are also different options to modify how the tag operates.
import c4d
def main():
bd = doc.GetActiveBaseDraw() # Get active base draw
activeCam = bd.GetSceneCamera(doc) # Get active camera
targetCam = op[c4d.ID_USERDATA,2] # UD: Assigned camera
activeMode = op[c4d.ID_USERDATA,6] # UD: Active mode
deactiveMode = op[c4d.ID_USERDATA,7] # UD:
render = op[c4d.ID_USERDATA,3] # UD: Affect Render Visibility
obj = op.GetObject() # Get object
if invert == False: # If invert is not ticked
if activeCam == targetCam: # If active camera is same as target camera
obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = mode # Set 'Visible in Editor' to mode
if render: # If render is ticked
obj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = mode # Set 'Visible in Renderer' to mode
else:
obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1 # Set 'Visible in Editor' to 'Off'
if render: # If render is ticked
obj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1 # Set 'Visible in Renderer' to 'Off'
else: # Otherwise (inverted)
if activeCam == targetCam: # If active camera is same as target camera
obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = mode # Set 'Visible in Editor' to mode
if render: # If render is ticked
obj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = mode # Set 'Visible in Renderer' to mode
else:
obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2 # Set 'Visible in Editor' to 'Off'
if render: # If render is ticked
obj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2 # Set 'Visible in Renderer' to 'Off'
This effector quantizes clone’s position, scale and rotation with user given steps. For example, if clone moves from pos.x 0 to pos.x 500 and quantize step is set to 50, the clone moves only when it’s pos.x value reaches value 50, 100, 150, 200 and so on.
The quantization formula looks like this:
step * math.floor(value / step)
When you are quantizing scale your should modify clone only with uniform scaling, otherwise you’ll get funky results with this version of effector.
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.
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.
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.
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
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.
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 range(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
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.
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
MixGrad.InsertKnot(resultList[i]['col'],
resultList[i]['brightness'],
resultList[i]['pos'],
resultList[i]['bias'],
resultList[i]['index'])
GradOut = MixGrad # Output mixed gradient