Herer is a pseudo code
doc = LoadDocument("file.c4d");
doc->CreateSceneFromC4D();
takeData = doc->GetTakeData();
prevTake = takeData ? takeData->GetCurrentTake() : null;
prevTime = doc->GetTime();
takes = collectAllTakesRecursively(takeData->GetMainTake());
for each take in takes:
takeData->SetCurrentTake(take);
isMain = (take == takeData->GetMainTake());
useEvaluatedValues = !isMain;
for each object in doc:
overrideKeys = {};
if (override = take->FindOverride(takeData, object)):
// override tracks (animated overrides)
for each ctrack in override->GetFirstCTrack():
addTrack(ctrack, isOverride=true);
overrideKeys.insert(trackKey(ctrack));
// override params (constant overrides)
for each descId in override->GetNodeData()->GetAllOverrideDescID():
overrideKeys.insert(trackKey(descId));
markPropertyAsAnimated(descId); // create channel even if no curve
// main tracks (skip those overridden)
if (!overrideOnly):
for each ctrack in object->GetFirstCTrack():
if (!overrideKeys.contains(trackKey(ctrack))):
addTrack(ctrack, isOverride=false);
// Build one animation for this take
// For non-main takes, sample evaluated values to capture final override result
for each animated property (pos/rot/scale, joints too):
times = keyTimesFromCurves();
if (useEvaluatedValues) times = [docMinTime..docMaxTime] @ fps;
for t in times:
doc->SetTime(t); doc->Execute();
value = object->GetParameter(propertyId);
writeKey(t, value);
takeData->SetCurrentTake(prevTake);
doc->SetTime(prevTime); doc->Execute();
We import each C4D take as a separate animation by iterating TakeData (main + child takes). For each take we call SetCurrentTake(take) and then collect animation data from:
- override tracks (BaseOverride::GetFirstCTrack()), and
- override parameters (BaseOverrideData::GetAllOverrideDescID()), so constant overrides are not missed.
We also read the base tracks (BaseObject::GetFirstCTrack()) but skip any channel that is overridden in the current take.
For non‑main takes we sample evaluated values (doc->SetTime(t); doc->Execute(); GetParameter()) over the document time range, because takes can change the final evaluated state even without explicit tracks.
This gives one animation per take (e.g., Idle/Walk/Run). Joint objects (Ojoint/Obone) are handled the same way as regular objects, so skinning animation is captured via joint transforms.