Updating/Rewriting .c3d importer

Heyo, just wanted to inform of me ‘attempting’ to update the old .c3d importer as i need it, but as it seems to not import certain files properly i also wanted to update it to better handle certain (my) .c3d files.

In particular i intend to replace the old parser with this one as it has MIT license and will probably be easier to maintain and better at managing the format. The license should be compatible but since licenses is beyond me there might be an issue that i missed.

In case there are any issues with this or if there are any suggestion feel free to post them here. I wouldn’t mind take pointers for how the format should be managed in Blender or parsing options for example. I’m also interested to know if there are any available test cases that needs to be supported, if there are, it would be helpful if i could obtain the files in some way.

Hopefully i’ll be able to provide a patch for it, otherwise i’ll make it publicly available at least.

Stay safe.

I’m pretty sure the Blender download has some MIT-licensed code in the libraries. Cycles is Apache licensed.

1 Like

The old importer utilized a second modal operator to generate an action sequence by running over the number of frames (in real-time) and keyframing the animated trackers. Since I doubt this is an intended behavior for an importer I decided to re-implement the importer rather then utilize the remaining old code.

Hopefully this is not an issue.


Have you done any communication with the GSOC student who is writing a fast mesh importer? I believe this is for .ply format.

I think if you’re gonna re-implement it, anyways, you should consider doing it in a fast compiled language like C. There’s a lot of people complaining about slow data I/O with common 3D art formats (.obj, .fbx…) and the C++ code that imports and exports Alembic and USD are much faster.

1 Like

I agree that it would be preferable to implement these kind of functions in C/C++ but I don’t see .c3d qualifying as a ‘common’ format in the context of Blender. To my knowledge there aren’t that many use cases for directly importing the files in Blender. The probable case is more so that the format is refined/converted in a separate application and the result is imported in another form.

Furthermore, I think there is benefit in the flexibility of implementing it in Python since even though the data format is straight forward, there are non-standard variations that will be hard to support without knowing specific variations.

But yeah, the reason why i created the thread was to see what other developers thoughts was, but i’m not technically writing a new importer, the idea is to replace the current one that isn’t working properly to another one that might actually get supported. The new problem i found was just that the old function passing the data to Blender structures did so in a way I don’t see being worth maintaining because it will probably just stop working at some point (and is inheritely slow and buggy).

1 Like

tl;dr warning, mostly documenting inconvenient behaviors :stuck_out_tongue:

Seems like calling insert to insert a keyframe in a F-Curve is very slow for having a ‘Fast’ flag. By doing some investigation it seemed like the flag only ignores updating the curve but there are still other updates triggered.

Slow method for adding keyframes to a F-Curve (fc) in Python:

for index in range(kf_count):
    fc.keyframe_points.insert(x_value, y_value, options={'FAST'}).interpolation = ENUM

Fast way of inserting F-Curve keyframes (~25-40 times faster):

for index in range(kf_count):
    kf = fc.keyframe_points[index]
    kf.co = (x_value, y_value)
    kf.interpolation = ENUM

Investigating the source it seemed to me like the insert function called some animation update function (rna_tag_animation_update) on every insertion:

static BezTriple *rna_FKeyframe_points_insert(
ID *id, FCurve *fcu, Main *bmain, float frame, float value, int keyframe_type, int flag)
    int index = insert_vert_fcurve(
         fcu, frame, value, (char)keyframe_type, flag | INSERTKEY_NO_USERPREF);

    if ((fcu->bezt) && (index >= 0)) {
        rna_tag_animation_update(bmain, id, true);

        return fcu->bezt + index;

    return NULL;

Namely the method:

static void rna_tag_animation_update(Main *bmain, ID *id, bool flush)
   /* Actually recalculate object properties, or just update COW. */

   AnimData *adt = BKE_animdata_from_id(id);

   if (adt && adt->action) {
       /* action is separate datablock, needs separate tag */
      DEG_id_tag_update_ex(bmain, &adt->action->id, tags);

   DEG_id_tag_update_ex(bmain, id, tags);

Seems like a odd behavior especially if the F-Curve is not updated. But yeah, need further investigation and proof, just documenting it if someone (I) ever feel like investigating further at some other time.

Alpha version

Completed the first stage and can now generate animated point clouds by importing .c3d files. Project source code is available on git. There is a quite a bit of work left to do, most of which is associated with ensuring more files are supported and which I will be able to start working on at a later date (in 1+ month). Below is a rough summary of what’s left.

  • Improve the python parser:
    • Ensure DEC/SGI to IEEE floating point conversion is correct.
    • Support extended standards such as ‘POINT2’/‘LABEL2’ for large files.
    • Ensure a selection of the available tests work correctly (only interested in supporting POINT data, not other/custom ANALOG data such as forceplates).
  • Improve importer script:
    • Support any parse changes
    • Tests
    • Probably more of #2 then I want to :cold_sweat:
    • At some point try to get the addon accepted…
  • Maybe? API function to add keyframe data from numpy arrays!? :slight_smile:

Stay safe

1 Like