exporting animation data



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/01/2007 at 09:54, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   10 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    I´m looking for a way to get animation data out of C4D.
    What I need is:

    - keyframes for bones
    - vertex weights

    Some C++-snippet would be nice to start.

    Thanks,
    C.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 03:51, xxxxxxxx wrote:

    Hi,

    look into the SDK docs. You need to get the object you need (bones for example), then get the track with GetBaseTrack() and then get the BaseSequence with the appropriate call and this one holds the keyframes of the bones, which you can also easily get with the corresponding function. See the clear docs on this issue.

    Vertex weights, I don´t know. Which weights do you mean? From a weightmap (vertexmap) or from a hypernurbs weightmap?

    The former can be retrieved with CalcVertexMap(op) or directly getting the vertexmap tag, which would also be the case for the Hypernurbs weights. Retrieval is described in the docs too.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 08:25, xxxxxxxx wrote:

    which Cinema version? If R10, do you use joints and the new weight tag?

    cheers,
    Matthias



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 08:28, xxxxxxxx wrote:

    oops, yes, that I don´t know about. :-)



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 11:38, xxxxxxxx wrote:

    Perhaps I didn´t describe clearly what I need.
    I need a way to export informations about characteranimation to display characters in a computergame ;-).

    Characters should be able to run, walk, shoot etc.
    To do this, grafics designer models his character and bones it, defines animations through rotations of bones and defines in which way a specific vertex is influenced by a specific bone.

    To display character in the game, the programmer (that´s me), needs the previously described info, this is:

    - a table of matrices (bones) for each animation.
    - a relation between theses matrices and the vertices (eg. Vertex 1234 is influenced 10% by matrix 5, 20% by matrix 6, 50% by matrix 7, 20% by matrix 0)

    That´s it.

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    You need to get the object you need (bones for example)
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    Searching for bones, keyframes, animations ... in CINEMA 4D R9.6 SDK brings no useful info for me.

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    See the clear docs on this issue.
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    Where?

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    Vertex weights, I don´t know. Which weights do you mean? From a weightmap (vertexmap) or from a hypernurbs weightmap?
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    Grafic artists say, hypernurbs weightmap is some step in between, so I think I need weightmap.

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    which Cinema version? If R10, do you use joints and the new weight tag?
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    Grafic artists want to use joints. Should it matter to me? At last, I just need what comes out ;-).

    Thanks,
    C.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 12:02, xxxxxxxx wrote:

    I'll tell you right off that Cinema 4d does not store animation in matrices. The only matrices are static ones. All animation is described with keys on animation tracks (no matrices). You'll either need to construct your matrices using the key values or not export as matrices (but instead as key frames).

    Weightmaps shouldn't be a big problem, but there are several ways to setup skin deformations in Cinema 4D:

    Functions (on bones)
    Point Selection tags
    Polygon Selection tags
    Vertex Map tags
    Claude Bonet weightmaps (hidden tags)
    New stuff for Joints

    Vertex Map tags are probably the easiest to deal with and are closer to most other weight mapping systems (afaik). Each tag stores an array of Real values for every point on the Polygon object. These values determine the weighting (0.0-1.0) of the point under deformation. The Vertex Map tags are then set in their respective Bone objects as a Restriction (for what points the Bone deforms).

    Objects in Cinema 4D are a general class (BaseObject). To get the type, such as 'bone', you need to check using something like:

    BaseObject* obj = doc->GetFirstObject();
    if (obj && obj->IsInstanceOf(Obone)) GePrint("Hey, this is a bone object!");

    There is no 'BoneObject', though there are some special cases like PolygonObject or CameraObject as they are extensions of the general class containing information specific to the derivation. Extra information on other types is stored in "Description Resources" - you'll learn them, love them, hate them, and learn to live with them. They are the backbone of Cinema 4D.

    Additionally for Keyframes and Animation: see BaseTrack, BaseSequence, BaseKey in the documentation.

    Most of the more specific information that you'll need is either available in the documentation, the sdk example code (plugins/cinema4dsdk), or by searching here (select Show Topics -> All to get the best coverage).

    HTH,
    Robert



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 12:37, xxxxxxxx wrote:

    <<<<<<<<<<<<<<<<<<<<<<<<<<<
    You'll either need to construct your matrices using the key values or not export as matrices (but instead as key frames).
    >>>>>>>>>>>>>>>>>>>>>>>>>>>

    Do you mean tweening?
    Exporting a mesh in different poses and interpolating all vertices in between?
    This is not what I need.

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<
    You'll either need to construct your matrices using the key values...
    <<<<<<<<<<<<<<<<<<<<<<<<<<<

    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).

    Could it be better to switch to fbx and write an an fbx- converter instead of trying to export something inexportable out of C4D?
    Grafic artist would have to export two files in this case, that must be put together again in the engine, not so elegant...

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    Extra information on other types is stored in "Description Resources" - you'll learn them, love them, hate them, and learn to live with them. They are the backbone of Cinema 4D.
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    Uaahh, I just wanna get some data out of C4D, you know.
    Only want to gain a basic understanding of their system.

    Thanks,
    C.



  • 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;  
    }
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 13:14, xxxxxxxx wrote:

    I should like to add that information on what 'tracks', 'sequences', and 'keys' are is pretty much thoroughly explained in the Cinema 4D manual (PDF). Gonna be tough to write an animation export plugin where you don't understand how animation works with the plugin's application.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 05/01/2007 at 13:50, xxxxxxxx wrote:

    Thanks anyway, time for weekend ;-)

    Cu
    C.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 07/01/2007 at 17:00, xxxxxxxx wrote:

    You can retrieve the current matrices of the desired objects while animation is running. You can run the animation with

      
    Real               fps = doc->GetFps();  
    BaseTime          t0 = BaseTime(startTime);  
    BaseTime          td = BaseTime(1.0/fps);  
    BaseTime               tEnd = BaseTime(stopTime);  
    do  
    {  
            doc->SetTime(t0);  
         doc->AnimateDocument(NULL, TRUE, TRUE);  
         GeSyncMessage(EVMSG_TIMECHANGED, 0, 0, 0);  
         EventAdd(EVENT_ANIMATE);  
         t0 = t0 + td;  
           
    }while(t0 <= tEnd);  
    

    Inside your plugin execute function you may ask for the current matrices of your objects and store them in the format you prefer.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 08/01/2007 at 05:39, xxxxxxxx wrote:

    @Klaus Heyne:

    Thanks, that seems to be pretty useful!


Log in to reply