Cinema 4D R11 exports joints!

I just wanted to correct a very common misunderstanding that I see around here, even among people knowledgeable with Cinema 4D: that Cinema 4D doesn’t export joints to FBX, and that you have to convert your joints to bones before they can be imported into Unity. This is simply not true with R11. Just to make it really really clear:

Cinema 4D R11 exports joints to FBX!

Got it? Good. :slight_smile:

The only thing you have to do is manually bake any IK or Xpresso before putting the .c4d file in your assets folder, as baking isn’t done automatically when exporting to FBX. I’ve put up a script on the wiki that does this in a reliable way. It also does some other nifty stuff, like automatically saving the baked file to your assets folder and deleting your controllers so they don’t clutter up the hierarchy in Unity.

Now stop perpetuating the myth and start using them joints!

thank you very much.

Thanks for the tip, now I just need to get R11…

Seriously? :shock: The last time I tried it crashed Unity … without the use of IK. I need to check it out again.

That yould be more than awesome, though. That and multi-UV export and I’m happy. 8)

Has anyone here had the time to test this more extensively?

I got one first test to work without IK but with IK setup … I can see the animation playing but the deformation fails.

The result I get in Unity looks like the picture below. Sometimes the limbs don’t look that weird but even baked (with your script) the IK still won’t show inside Unity - the movement apparently is without any JointRotation.

[edit] Another thing I noticed: if you pose a model with a Bones/ClaubeBonet skeleton without setting a keyframe the pose is immediately visible in unity. With a Joint/Skin setup this doesn’t work - a posed model without IK (for me) only shows up on animation.

Something that would interest me from UT’s side of the development: The manual says that there is “no reliable way of exporting animated characters that use the Joint’s” system. Did some features of Joint based animation work in R10.1 already but were just too buggy to support officially?

tolm: how complex meshes/Characters did you manage to implement so far? Did you encounter any odd behaviours since your initial post?

I really want this to work :frowning:

I’ve been using joints for the past couple of months with a rig that’s got 24 joints, some constraints, regular IK, spline IK and some XPresso. It’s definitely not as complex as a standard human (it’s a cute robot) but it does use a lot of the features you would use for a standard human rig. Since I got it set up correctly I haven’t had any problems at all.

I remember messing around with different ways to organise the animations when I set it up, and what I found worked the best was to have the character in T-pose without animation in a file named character.c4d, and each animation in a separate file with the character@animation.c4d naming scheme.

I also remember having some trouble with rotation not being exported/imported for joints that had no keyframes at all, but all I did then was animate them slightly, and that solved it. Perhaps that’s the problem you’re having?

So far this script doesn’t seem to be working for me. It creates the copy but doesn’t do any baking, Am I missing a step?

Kevin

An @ in the name of the file perhaps? If that’s not the problem, maybe you could upload the file, and I can take a look at it.

I’ve tried the script on three different files (and no @ in the filesnames) so I figure I must be missing something.

The attached file is from Cinema R11 on a Mac. When running the script it saves out the new file into the right location but no baking has been applied.

Thanks for looking at it.

Kevin

154290–5601–$iktestc4d_158.zip (9.32 KB)

Sorry. It should be the other way around; the filename has to have an @ in it, or the script won’t bake. I tried renaming your file IkTest@whatever.c4d and it bakes just fine.

Fantastic - thanks for the advice and for the great script.

Kevin

I changed the file names to include the @ symbol and it still won’t bake for me.

When I run the script it runs through the animation and appears to open a new Cinema4D window momentarily, but when I check the newly created file it’s the same as the original.

I used the exact same file I sent you and renamed it just like you did and still no baking. Any ideas?

Ah! I found out what the problem is. My joint hierarchy isn’t parented to anything, so I wrote the script to skip anything at the top level that isn’t a joint. But your joint hierarchy is parented to a null, so the script skipped it. Stupid of me.

Here’s a new version that bakes keyframes for all joints in the scene, no matter where they are in the hierarchy:

/* Export to Unity script.
 *
 * Bakes animation for all joints in the scene, deletes
 * any controllers or other objects that you specify,
 * and saves the result as a new file at a specified path,
 * leaving the original untouched.
 *
 * Note: The script will only bake animation if the
 * filename has an @ in it.
 */

// Inputs. Change these to match your own setup.
var bakePosition = 1;
var bakeScale = 0;
var bakeRotation = 1;
var fps = 30;
var savePath = "/Users/User/Documents/Project/Assets/";
var deleteObjects;
assignArray()
{
    deleteObjects = new(array,2);
    deleteObjects[0] = "Controllers";
    deleteObjects[1] = "High Poly";
}

// Constants
const var joint = 1019362;
const var goto_start = 12501;
const var goto_next_frame = 12414;
const var record_active_objects = 12410;
const var record_position = 12417;
const var record_scale = 12418;
const var record_rotation = 12419;
const var delete_object = 12109;
const var close = 12664;
const var use_expressions = 13522;

// Bakes the current frame for all joints
bakeJoints(doc, obj)
{
    while (obj != NULL)
    {
        // Only key joints
        if (obj->GetType() == joint)
        {
            doc->SetActiveObject(obj);
            CallCommand(record_active_objects);
        }

        // Loop through all children and bake them as well
        var child = obj->GetDown();
        while (child != NULL)
        {
            bakeJoints(doc, child);
            child = child->GetNext();
        }

        obj = obj->GetNext();
    }
}

// Deletes the object hierarchy with the specified name
deleteObject(doc, name)
{
    var obj = doc->GetFirstObject();
    while (obj != NULL)
    {
        if (obj->GetName() == name)
        {
            doc->SetActiveObject(obj);
            CallCommand(delete_object);
        }
        obj = obj->GetNext();
    }
}

main(doc, op)
{
    // Because you can't assign arrays outside functions - yeah stupid
    assignArray();

    // Set what to parameters to bake
    if (IsCommandChecked(record_position) != bakePosition)
    {
        CallCommand(record_position);
    }
    if (IsCommandChecked(record_scale) != bakeScale)
    {
        CallCommand(record_scale);
    }
    if (IsCommandChecked(record_rotation) != bakeRotation)
    {
        CallCommand(record_rotation);
    }

    // Only bake keyframes if the filename contains "@"
    var currFilename = doc->GetFilename();
    var file = currFilename->GetLastString();
    if(strstr(file, "@") != -1)
    {
        // Bake keyframes for all joints
        CallCommand(goto_start);
        var frame = doc->GetTime()->GetFrame(fps);
        var maxFrame = doc->GetMaxTime()->GetFrame(fps);
        for (; frame <= maxFrame; frame++)
        {
            var obj = doc->GetFirstObject();
            bakeJoints(doc, obj);
            CallCommand(goto_next_frame);
            DrawViews(DA_NO_THREAD);
        }
    }

    // Delete objects
    var i;
  for(i = 0; i < sizeof(deleteObjects); i++)
    {
        deleteObject(doc, deleteObjects[i]);
    }
    
    // Save as new file
    var currFilename = doc->GetFilename();
    var newFilename = new(Filename);
    newFilename->SetFullString(savePath);
    newFilename->AddLast(currFilename->GetLastString());
    doc->Save(newFilename);
    println(newFilename->GetFullString(), " exported");
    
    // Close the new file
    CallCommand(close);

    // Reopen original file
    LoadDocument(currFilename);
    println(currFilename->GetFullString(), " reopened");
}

It works! Thanks so much for taking the time to fix it for me.

BTW, can you tell me how to “tag” an object as a Controller or as a high poly object?

thanks again,

Kevin

No problem. It’s great seeing it put to use. :slight_smile:

Unfortunately you can’t tag individual objects to be deleted. What the script does is look at the root hierarchies in the scene, and delete those whose names match the names in the deleteObjects array of the script.

So put all your controllers in a root null that you name “Controllers”, and all your high poly stuff in a root null named “High Poly”. Or name the nulls whatever you want and change the names in the script. If you have three nulls named “Splines”, “High Poly” and “Delete On Export”, the deleteObjects part would look like this:

deleteObjects = new(array,3); 
deleteObjects[0] = "Splines"; 
deleteObjects[1] = "High Poly";
deleteObjects[2] = "Delete On Export";

Hello in there :slight_smile:

I’m join the train to talk about a little problem with Bake Object function :

As said, it doesn’t write all frames, leaving some little holes in the timeline.
This is creating unwanted interpolations for my chars …

Isn’t there a solution to force all frames to be written ?

Thank you for your attention :slight_smile:

Hey nomad,

Did you try out the script mentioned in the first post of this thread?
http://www.unifycommunity.com/wiki/index.php?title=Cinema_4D#Exporting_to_Unity

In the description it mentions it gets around the gaps in the timeline when baking the object. Curious to see if it solves your problem, haven’t tested it out myself yet.

gr.jakko

Hello :wink:

Yes I’ve already tried it, but it takes forever to process (45 min for 1010 frames) and at the end, some body members act weirdly. I have to admit my rigging is somehow complex, mixing expresso, constraints, clamps, IKs … So it should be difficult to just have it done without a problem :slight_smile:

Thank you anyway.

It’s ok now, I’ve rewritten my own version of the export script :slight_smile:
(typed manually the bones names in an array to avoid recursivity)

Indeed, thank you very much for the original script. It helped me a lot for C4D scripting initiation.

Good to hear you’ve managed to fix it by modifying that script. I will probably start exporting rigs to Unity in a couple of weeks, now I’m not so worried anymore that I will run into unfixable problems.

gr.jakko