THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/01/2007 at 12:57, xxxxxxxx wrote:
Originally posted by chris4711 on 05 January 2007
<<<<<<<<<<<<<<<<<<<<<<<<<<<
Do you mean tweening?
Exporting a mesh in different poses and interpolating all vertices in between?
This is not what I need.
>>>>>>>>>>>>>>>>>>>>>>>>>>>
No!!! Keys (KEYS!!!!). The key data is NOT stored as matrices but as VALUES (Rotation X at Frame 10 = 2.69 (radians)). There are no 'this animation frame sets the bone and you can get the matrix for the animated bone here'. You do BaseObject->GetMg() and you will ALWAYS get the static matrix (ALWAYS and FOREVER). There is no animation matrix.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Any info available about "animation tracks" somewhere?
What do they do, and how? On which data do they operate?
CINEMA 4D R9.6 SDK doesn´t make this clear to me (at least at first sight).
<<<<<<<<<<<<<<<<<<<<<<<<<<<
In the SDK documentation under BaseTrack, BaseSequence, and BaseKey. The process to get these is through the BaseObject and by track type and Description (ID_VECTOR, VECTOR_X). There are threads here that elucidate this information.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Uaahh, I just wanna get some data out of C4D, you know.
Only want to gain a basic understanding of their system.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
And most of the data on things is stored in Description Resources - this is the basics, baby. As I said, learn 'em, love 'em, hate 'em, live with 'em.
Noone here is going to provide you with the full source required with details of how it works. What you need to get your understanding is basically the entire plugin spelled out. Nuh-uh. My fee is... ;)
You need to write an export plugin and build your code to do the file writing. You then need to get to the data and write it in some predetermined format. I can only provide these parts of my animation import/export plugin as the plugin is specific to the client's needs. So you'll have to wade through it and try to understand it in relation to your goals.
// AnimatSAVE.WriteObject - Recursive
// Write all BaseDocument Object Animation information to file
//*---------------------------------------------------------------------------*
BOOL AnimatSAVE::WriteObjects(BaseObject* obj, UWORD level)
//*---------------------------------------------------------------------------*
{
String lvl = String("");
for (UWORD i = 0; i < level; i++) lvl += String(" ");
UWORD nextLevel = level+1;
#ifdef C4D_R10
CTrack* track;
#else
BaseTrack* track;
#endif
for (obj; obj; obj = obj->GetNext())
{
// Write Object: OBJECT "<name>"
if (!WriteLine(lvl+"OBJECT \""+obj->GetName()+"\"")) return FALSE;
// Write Start: {
if (!WriteLine(lvl+"{")) return FALSE;
// Write Tracks
#ifdef C4D_R10
for (track = obj->GetFirstCTrack(); track; track = track->GetNext())
#else
for (track = obj->GetFirstTrack(); track; track = track->GetNext())
#endif
if (!WriteTrack(track, nextLevel)) return FALSE;
// Write Sub-objects
if (obj->GetDown())
{
if (!WriteObjects(obj->GetDown(), nextLevel)) return FALSE;
}
// Write End: }
if (!WriteLine(lvl+"}")) return FALSE;
}
return TRUE;
}
// AnimatSAVE::GetTrackParamStr
//*---------------------------------------------------------------------------*
String AnimatSAVE::GetTrackParamStr(BaseTrack* track)
//*---------------------------------------------------------------------------*
{
if (track->GetType() != Svalue) return String("");
String pstr;
DescID descID = track->GetDescriptionID();
LONG id = descID[0].id;
LONG dtype = descID[0].dtype;
/*
// Output
pstr = "";
for (LONG n = 0; n < descID.GetDepth(); n++)
{
pstr += " DescLevel("+LongToString(i)+", id["+LongToString(descID[n].id)+"] dtype["+GetDType(descID[n].dtype)+"]) .";
}
GePrint("TRACK value"+pstr);
*/
if (id == ID_BASEOBJECT_POSITION)
{
pstr = " position.";
id = descID[1].id;
if (id == VECTOR_X) pstr += "x";
else if (id == VECTOR_Y) pstr += "y";
else if (id == VECTOR_Z) pstr += "z";
}
else if (id == ID_BASEOBJECT_ROTATION)
{
pstr = " rotation.";
id = descID[1].id;
if (id == VECTOR_X) pstr += "h";
else if (id == VECTOR_Y) pstr += "p";
else if (id == VECTOR_Z) pstr += "b";
}
else if (id == ID_BASEOBJECT_SCALE)
{
pstr = " scale.";
id = descID[1].id;
if (id == VECTOR_X) pstr += "x";
else if (id == VECTOR_Y) pstr += "y";
else if (id == VECTOR_Z) pstr += "z";
}
else if ((id == ID_DYNAMIC_PARAMETER) || (dtype == DTYPE_SUBCONTAINER))
{
// Second value references XPresso control
pstr = " dynamic."+LongToString(descID[1].id);
}
else if (id == -1) pstr = " time";
else pstr = " unsupported";
return pstr;
}
// AnimatSAVE::WriteTrack
//*---------------------------------------------------------------------------*
BOOL AnimatSAVE::WriteTrack(BaseTrack* track, UWORD level)
//*---------------------------------------------------------------------------*
{
String lvl = String("");
UWORD nextLevel = level+1;
for (UWORD i = 0; i < level; i++) lvl += String(" ");
// Write Track: TRACK <String:type> [<String:parameter>] "<String:name>"
if (!WriteLine(lvl+"TRACK "+GetTrackTypeStr(track->GetType())+GetTrackParamStr(track)+" \""+track->GetName()+"\"")) return FALSE;
// Write Start: {
if (!WriteLine(lvl+"{")) return FALSE;
// Write Sequences
BOOL sndTrack = track->IsInstanceOf(Ssound);
for (BaseSequence* seq = track->GetFirstSequence(); seq; seq = seq->GetNext())
if (!WriteSequence(seq, nextLevel, sndTrack)) return FALSE;
// Write End: }
if (!WriteLine(lvl+"}")) return FALSE;
return TRUE;
}
// AnimatSAVE::WriteSequence
//*---------------------------------------------------------------------------*
BOOL AnimatSAVE::WriteSequence(BaseSequence* seq, UWORD level, BOOL soundTrack)
//*---------------------------------------------------------------------------*
{
GeData gdata;
BaseContainer* data = seq->GetDataInstance();
String lvl = String("");
UWORD nextLevel = level+1;
for (UWORD i = 0; i < level; i++) lvl += String(" ");
// Write Sequence: SEQUENCE <LONG:LeftBorder> <LONG:RightBorder> "<name>"
if (!WriteLine(lvl+"SEQUENCE "+LongToString(seq->GetT1().GetFrame(fps))+" "+LongToString(seq->GetT2().GetFrame(fps))+" \""+seq->GetName()+"\"")) return FALSE;
// Write Start: {
if (!WriteLine(lvl+"{")) return FALSE;
// Write Parameters: PARAMS <LONG:LoopBorder> <Real:Loops> <Bool:Soft> <Bool:LeftInfluence> <Bool:RightInfluence> <Bool:ConstantXYZVelocity>
String str = lvl+" PARAMS "+LongToString(seq->GetT3().GetFrame(fps))+" "+RealToString(data->GetReal(ID_BASESEQ_LOOPS))+" ";
str += (seq->GetSoft())?"T ":"F ";
str += (seq->GetLeftInfluence())?"T ":"F ";
str += (seq->GetRightInfluence())?"T ":"F ";
str += (data->GetBool(ID_COMPENSATE))?"T":"F";
if (!WriteLine(str)) return FALSE;
// Write TimeTrack: TIMETRACK <Bool:Unlooped Area> "<TrackName>"
str = lvl+" TIMETRACK ";
seq->GetParameter(DescID(ID_BASESEQ_TIME_EXLOOP), gdata, NULL);
str += (gdata.GetLong())?"T \"":"F \"";
if (seq->GetParameter(DescID(ID_BASESEQ_TIME), gdata, NULL))
{
BaseTrack* ttrk;
if (ttrk = static_cast<BaseTrack*>(gdata.GetLink(doc))) str += ttrk->GetName();
}
str += "\"";
if (!WriteLine(str)) return FALSE;
// Write Sound Properties (if applicable)
if (soundTrack)
{
str = lvl+" SOUND ";
str += (data->GetBool(ID_SOUND_ONOFF))?"ON ":"OFF ";
seq->GetParameter(DescID(ID_SOUND_NAME), gdata, NULL);
str += "\""+gdata.GetString()+"\"";
if (!WriteLine(str)) return FALSE;
}
// Write KeyCount: KEYCOUNT <LONG>
if (!WriteLine(lvl+" KEYCOUNT "+LongToString(seq->GetKeyCount()))) return FALSE;
// Write Keys
for (BaseKey* key = seq->GetFirstKey(); key; key = key->GetNext())
if (!WriteKey(key, nextLevel, soundTrack)) return FALSE;
// Write End: }
if (!WriteLine(lvl+"}")) return FALSE;
return TRUE;
}
// AnimatSAVE::WriteKey
//*---------------------------------------------------------------------------*
BOOL AnimatSAVE::WriteKey(BaseKey* key, UWORD level, BOOL soundTrack)
//*---------------------------------------------------------------------------*
{
String lvl = String("");
for (UWORD i = 0; i < level; i++) lvl += String(" ");
// Write Key: KEY <LONG:Frame>
if (!WriteLine(lvl+"KEY "+LongToString(key->GetTime().GetFrame(fps)))) return FALSE;
// Write Start: {
if (!WriteLine(lvl+"{")) return FALSE;
// Write Sound Properties (if applicable)
BaseContainer* data = key->GetDataInstance();
if (soundTrack)
{
// Write Volume: VOLUME <Real:0.0,MAX_REAL>
if (!WriteLine(lvl+" VOLUME "+RealToString(data->GetReal(ID_SOUNDKEY_VOLUME)))) return FALSE;
// Write Balance: BALANCE <Real:-100.0,100.0>
if (!WriteLine(lvl+" BALANCE "+RealToString(data->GetReal(ID_SOUNDKEY_BALANCE)))) return FALSE;
}
else
{
GeData gdata;
AnimValue* animVal = GetKeyValue(key);
// Write Value: VALUE <Real>
if (!WriteLine(lvl+" VALUE "+RealToString(animVal->value))) return FALSE;
// Write LinkTangents: LINK <Bool>
if (!WriteLine(lvl+" LINK "+((animVal->link_leftright)?"T":"F"))) return FALSE;
// Write Left Interpolation: INTERPL <String:Type> <Bool:Clamp> <Real:Value> <Real:Time> <Real:Strength>
String str = lvl+" INTERPL "+InterpTypeStr[animVal->inter_left]+" ";
key->GetParameter(DescID(KE_CLAMP_LEFT), gdata, NULL);
str += (gdata.GetLong())?"T":"F";
str += " "+RealToString(animVal->value_left)+" "+RealToString(animVal->time_left)+" "+RealToString(animVal->str_left);
if (!WriteLine(str)) return FALSE;
// Write Right Interpolation: INTERPR <String:Type> <Bool:Clamp> <Real:Value> <Real:Time> <Real:Strength>
str = lvl+" INTERPR "+InterpTypeStr[animVal->inter_right]+" ";
key->GetParameter(DescID(KE_CLAMP_RIGHT), gdata, NULL);
str += (gdata.GetLong())?"T":"F";
str += " "+RealToString(animVal->value_right)+" "+RealToString(animVal->time_right)+" "+RealToString(animVal->str_right);
if (!WriteLine(str)) return FALSE;
}
// Write End: }
if (!WriteLine(lvl+"}")) return FALSE;
return TRUE;
}