Import animation data using Melange lib

On 15/07/2014 at 11:33, xxxxxxxx wrote:

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

Hello all,

I'm trying to read the animation data from a C4D file using the melange lib, but I'm having all sorts of problems.
My first problem is related to the rotation axis. I have 2 different files, in both files I have a rotation around the Z axis. The problem starts when I create a keyframe. In one of the files, this rotation is applied as a "Rotation.B" whereas in the other file, I get "Rotation.P". Note that in both cases I rotated the model around the Z axis!

Then when I'm importing each of these files into my program, the conversion from HPB into XYZ results in different rotations, however, The Rotation.B is converted into a rotation around Z and  the Rotation.P is converted into a rotation around Y for the other, which seems that HPB is directly converted into XYZ.

Another problem I'm having is related to the point of rotation/scale. I'm getting 3 vectors from each keyframe (move, rotate, scale). I then create a transformation matrix with them, but applying this matrix directly will transform my model from within its center, independently of the point of rotation I used in Cinema4D. I'm almost definitely missing something here.

Here is a draft of my current code:

CTrack *track = op->GetFirstCTrack();
while (track)
        DescID testID = track->GetDescriptionID();
        DescLevel lv1 = testID[0];
        DescLevel lv2 = testID[1];
        CCurve *curve = track->GetCurve();
        if (curve)
                LONG keyCount = curve->GetKeyCount();
                CKey *key = NULL;
                BaseTime time;
                for (LONG i=0; i<keyCount; ++i)
                        key = curve->GetKey(i);
                        time = key->GetTime();
                        if (track->GetTrackCategory() == PSEUDO_VALUE)
                                const LONG keyId = time.GetFrame(animProps.fps);
                                if (animData.keyframes.find(keyId) == animData.keyframes.end())
                                        animData.keyframes[keyId] = MelangeStoreKeyframe(keyId);
                                MelangeStoreKeyframe &keyframe = animData.keyframes[keyId];
                                switch (
                                        case ID_BASEOBJECT_REL_POSITION:
                                                switch (
                                                        case VECTOR_X: keyframe.position[0] = key->GetValue(); break;
                                                        case VECTOR_Y: keyframe.position[1] = key->GetValue(); break;
                                                        case VECTOR_Z: keyframe.position[2] = key->GetValue(); break;
                                        case ID_BASEOBJECT_REL_ROTATION:
                                                switch (
                                                        case VECTOR_X: keyframe.rotation[0] = key->GetValue(); break;
                                                        case VECTOR_Y: keyframe.rotation[1] = key->GetValue(); break;
                                                        case VECTOR_Z: keyframe.rotation[2] = key->GetValue(); break;
                                        case ID_BASEOBJECT_REL_SCALE:
                                                switch (
                                                        case VECTOR_X: keyframe.scale[0] = key->GetValue(); break;
                                                        case VECTOR_Y: keyframe.scale[1] = key->GetValue(); break;
                                                        case VECTOR_Z: keyframe.scale[2] = key->GetValue(); break;
        track = track->GetNext();

On a final note, I'm not considering the global matrix of the model, which for my understanding, represents the model matrix at the current frame when exported.

        PolygonObject *op = (PolygonObject* )GetNode();
        Matrix mg	= op->GetMg();

I'm not applying this matrix (mg) to the model's vertexes nor the animation transforms (position, scale, rotation).

Also, it would be great is someone pointed me out some examples about this matter, I'm a little bit lost here.

Thanks in advance!

On 17/07/2014 at 07:05, xxxxxxxx wrote:

Well... I think I'm getting somewhere.

I cannot discard the model global matrix, but I don't know exactly what to do with it. Also, I don't understand the relation of this matrix with the values read from each keyframe.

Currently, if my model has no animation data, I simply multiply the global matrix by each vertex, and get exactly the same thing as in Cinema4D. However if my model do has animation data, I can't seem to get the same result.

Should I multiply each keyframe position, scale and rotation values (read as the previous post) by the global matrix, and also multiply each vertex by the same matrix?

I tried this, no luck yet!

On 27/01/2015 at 19:05, xxxxxxxx wrote:

Once again, I'll answer my own question, so others with the same problem could understand what's going on with C4D animations in melange.

So this is how it works:
the Matrix Global op->GetMg(), is nothing more than the matrix containing the transformation for a specific object when the C4D file was saved. This means that if we have an animation with 2 keyframes 0 to 10, and we save the file with the cursor in frame 10, we get the transformation the object has  in the keyframe 10.

Now, the data read from each keyframe: What we have to do here, is collect all the data we can for each keyframe, like my initial code does. But, because most of the time, a keyframe only has 1 or 2 transforms, like position_x and rotation_h or scale_z, we need to figure out all the missing data, and for that, we should use op->GetRelPos(), op->GetRelScale() and op->GetRelRot(), then simply set all the missing data with the values read from these calls. Example:

keyframe 0:
we got from the my code above:
position_x, position_y, scale_x, rotation_h, rotation_b for example

so we still need:
position_z, scale_y, scale_z and rotation_p

we get these like so:
position_z = op->GetRelPos().z
scale_y = op->GetRelScale().y
... and so on...

NOTE: you can do this the other way around, set all transforms to their "base" values using those functions, and then read the animation data, and replace the corresponding values.

Just do this for all the keyframes and we're done. (I mean... we still need to deal with interpolation, but that's another story)