← Back to mograph
Keyframe Cloner Offset Based on the Number of Clones in Cinema4D
29 Apr 26 (5mo ago)
With a the cloner set to Objec Type, filled with a spline, I want to have an even rudimentary cycle of the clones as it cycles through the spline.
To automate that, here is the script that does that:
import c4d
def main():
# 1. Get the active selected Object
obj = doc.GetActiveObject()
# Check if an object is selected and if it's a Cloner (Type ID 1018544)
if obj is None or obj.GetType() != 1018544:
c4d.gui.MessageDialog("Please select a Cloner object in your Object Manager.")
return
# 2. Extract the Cloner count data
try:
clone_count = obj[c4d.MG_SPLINE_COUNT]
except AttributeError:
c4d.gui.MessageDialog("Could not read MG_SPLINE_COUNT. Make sure the Cloner is set up correctly.")
return
if clone_count is None or clone_count < 2:
c4d.gui.MessageDialog("You need a Count of at least 2 to animate the offset intervals.")
return
# 3. Time and Frame Calculations
fps = doc.GetFps()
min_time = doc.GetMinTime().GetFrame(fps)
intervals = clone_count - 1
# --- NEW LOGIC: Hardcoded Hold and Transition Frames ---
hold_frames = 20
transition_frames = 8
# Start an undo block
doc.StartUndo()
# 4. Track Creation for Offset
offset_desc_id = c4d.DescID(c4d.DescLevel(c4d.MG_SPLINE_OFFSET, c4d.DTYPE_REAL, 0))
track = obj.FindCTrack(offset_desc_id)
if track:
doc.AddUndo(c4d.UNDOTYPE_DELETE, track)
track.Remove()
track = c4d.CTrack(obj, offset_desc_id)
obj.InsertTrackSorted(track)
doc.AddUndo(c4d.UNDOTYPE_NEW, track)
curve = track.GetCurve()
# 5. Loop and Insert Double Keyframes (Start and End of Hold)
for idx in range(clone_count):
# Maps step index to a 0.0 -> 1.0 float (0% -> 100% in the UI)
offset_value = float(idx) / float(intervals)
# Calculate exactly when this position's hold period starts and ends
hold_start_frame = min_time + (idx * (hold_frames + transition_frames))
hold_end_frame = hold_start_frame + hold_frames
# --- KEY 1: Start of the hold ---
start_time = c4d.BaseTime(hold_start_frame / float(fps))
key_dict_start = curve.AddKey(start_time)
if key_dict_start:
k_start = key_dict_start["key"]
k_start.SetValue(curve, offset_value)
k_start.SetInterpolation(curve, c4d.CINTERPOLATION_LINEAR)
# --- KEY 2: End of the hold ---
end_time = c4d.BaseTime(hold_end_frame / float(fps))
key_dict_end = curve.AddKey(end_time)
if key_dict_end:
k_end = key_dict_end["key"]
k_end.SetValue(curve, offset_value)
k_end.SetInterpolation(curve, c4d.CINTERPOLATION_LINEAR)
# 6. Auto-expand timeline if the keys go past the current max time
current_max_frame = doc.GetMaxTime().GetFrame(fps)
if hold_end_frame > current_max_frame:
new_max_time = c4d.BaseTime(hold_end_frame / float(fps))
doc.SetMaxTime(new_max_time)
# Close Undo block, refresh the view manager UI
doc.EndUndo()
c4d.EventAdd()
print(f"Successfully generated step-animation with {hold_frames}-frame holds and {transition_frames}-frame transitions!")
if __name__ == '__main__':
main()