Search Unity

Cinema 4D R11 exports joints!

Discussion in 'Asset Importing & Exporting' started by tolm, Apr 9, 2009.

  1. tolm

    tolm

    Joined:
    Feb 4, 2008
    Posts:
    61
    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. :)

    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!
     
  2. mia

    mia

    Joined:
    Dec 31, 2007
    Posts:
    83
    thank you very much.
     
  3. artzfx

    artzfx

    Joined:
    Apr 28, 2008
    Posts:
    572
    Thanks for the tip, now I just need to get R11...
     
  4. the_motionblur

    the_motionblur

    Joined:
    Mar 4, 2008
    Posts:
    1,774
    Seriously? :eek: 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)
     
  5. the_motionblur

    the_motionblur

    Joined:
    Mar 4, 2008
    Posts:
    1,774
    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 :(
     

    Attached Files:

  6. tolm

    tolm

    Joined:
    Feb 4, 2008
    Posts:
    61
    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?
     
  7. kwabbott

    kwabbott

    Joined:
    Jun 5, 2007
    Posts:
    151
    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
     
  8. tolm

    tolm

    Joined:
    Feb 4, 2008
    Posts:
    61
    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.
     
  9. kwabbott

    kwabbott

    Joined:
    Jun 5, 2007
    Posts:
    151
    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
     

    Attached Files:

  10. tolm

    tolm

    Joined:
    Feb 4, 2008
    Posts:
    61
    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.
     
  11. kwabbott

    kwabbott

    Joined:
    Jun 5, 2007
    Posts:
    151
    Fantastic - thanks for the advice and for the great script.

    Kevin
     
  12. kwabbott

    kwabbott

    Joined:
    Jun 5, 2007
    Posts:
    151
    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?
     
  13. tolm

    tolm

    Joined:
    Feb 4, 2008
    Posts:
    61
    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:

    Code (csharp):
    1. /* Export to Unity script.
    2.  *
    3.  * Bakes animation for all joints in the scene, deletes
    4.  * any controllers or other objects that you specify,
    5.  * and saves the result as a new file at a specified path,
    6.  * leaving the original untouched.
    7.  *
    8.  * Note: The script will only bake animation if the
    9.  * filename has an @ in it.
    10.  */
    11.  
    12. // Inputs. Change these to match your own setup.
    13. var bakePosition = 1;
    14. var bakeScale = 0;
    15. var bakeRotation = 1;
    16. var fps = 30;
    17. var savePath = "/Users/User/Documents/Project/Assets/";
    18. var deleteObjects;
    19. assignArray()
    20. {
    21.     deleteObjects = new(array,2);
    22.     deleteObjects[0] = "Controllers";
    23.     deleteObjects[1] = "High Poly";
    24. }
    25.  
    26. // Constants
    27. const var joint = 1019362;
    28. const var goto_start = 12501;
    29. const var goto_next_frame = 12414;
    30. const var record_active_objects = 12410;
    31. const var record_position = 12417;
    32. const var record_scale = 12418;
    33. const var record_rotation = 12419;
    34. const var delete_object = 12109;
    35. const var close = 12664;
    36. const var use_expressions = 13522;
    37.  
    38. // Bakes the current frame for all joints
    39. bakeJoints(doc, obj)
    40. {
    41.     while (obj != NULL)
    42.     {
    43.         // Only key joints
    44.         if (obj->GetType() == joint)
    45.         {
    46.             doc->SetActiveObject(obj);
    47.             CallCommand(record_active_objects);
    48.         }
    49.  
    50.         // Loop through all children and bake them as well
    51.         var child = obj->GetDown();
    52.         while (child != NULL)
    53.         {
    54.             bakeJoints(doc, child);
    55.             child = child->GetNext();
    56.         }
    57.  
    58.         obj = obj->GetNext();
    59.     }
    60. }
    61.  
    62. // Deletes the object hierarchy with the specified name
    63. deleteObject(doc, name)
    64. {
    65.     var obj = doc->GetFirstObject();
    66.     while (obj != NULL)
    67.     {
    68.         if (obj->GetName() == name)
    69.         {
    70.             doc->SetActiveObject(obj);
    71.             CallCommand(delete_object);
    72.         }
    73.         obj = obj->GetNext();
    74.     }
    75. }
    76.  
    77. main(doc, op)
    78. {
    79.     // Because you can't assign arrays outside functions - yeah stupid
    80.     assignArray();
    81.  
    82.     // Set what to parameters to bake
    83.     if (IsCommandChecked(record_position) != bakePosition)
    84.     {
    85.         CallCommand(record_position);
    86.     }
    87.     if (IsCommandChecked(record_scale) != bakeScale)
    88.     {
    89.         CallCommand(record_scale);
    90.     }
    91.     if (IsCommandChecked(record_rotation) != bakeRotation)
    92.     {
    93.         CallCommand(record_rotation);
    94.     }
    95.  
    96.     // Only bake keyframes if the filename contains "@"
    97.     var currFilename = doc->GetFilename();
    98.     var file = currFilename->GetLastString();
    99.     if(strstr(file, "@") != -1)
    100.     {
    101.         // Bake keyframes for all joints
    102.         CallCommand(goto_start);
    103.         var frame = doc->GetTime()->GetFrame(fps);
    104.         var maxFrame = doc->GetMaxTime()->GetFrame(fps);
    105.         for (; frame <= maxFrame; frame++)
    106.         {
    107.             var obj = doc->GetFirstObject();
    108.             bakeJoints(doc, obj);
    109.             CallCommand(goto_next_frame);
    110.             DrawViews(DA_NO_THREAD);
    111.         }
    112.     }
    113.  
    114.     // Delete objects
    115.     var i;
    116.   for(i = 0; i < sizeof(deleteObjects); i++)
    117.     {
    118.         deleteObject(doc, deleteObjects[i]);
    119.     }
    120.    
    121.     // Save as new file
    122.     var currFilename = doc->GetFilename();
    123.     var newFilename = new(Filename);
    124.     newFilename->SetFullString(savePath);
    125.     newFilename->AddLast(currFilename->GetLastString());
    126.     doc->Save(newFilename);
    127.     println(newFilename->GetFullString(), " exported");
    128.    
    129.     // Close the new file
    130.     CallCommand(close);
    131.  
    132.     // Reopen original file
    133.     LoadDocument(currFilename);
    134.     println(currFilename->GetFullString(), " reopened");
    135. }
     
  14. kwabbott

    kwabbott

    Joined:
    Jun 5, 2007
    Posts:
    151
    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
     
  15. tolm

    tolm

    Joined:
    Feb 4, 2008
    Posts:
    61
    No problem. It's great seeing it put to use. :)

    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:

    Code (csharp):
    1. deleteObjects = new(array,3);
    2. deleteObjects[0] = "Splines";
    3. deleteObjects[1] = "High Poly";
    4. deleteObjects[2] = "Delete On Export";
     
  16. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Hello in there :)

    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 :)
     
  17. jakkovanhunen

    jakkovanhunen

    Joined:
    Oct 20, 2008
    Posts:
    79
  18. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Hello ;)

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

    Thank you anyway.
     
  19. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    It's ok now, I've rewritten my own version of the export script :)
    (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.
     
  20. jakkovanhunen

    jakkovanhunen

    Joined:
    Oct 20, 2008
    Posts:
    79
    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
     
  21. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Thank you, I'll make sure to lend a hand if needed with what I learned so far.

    One thing though, I'm encountering a minor performance problem, iPhone wise, due to overbaking legs IK (every frame is baked on a total of 1010).
    I'm actually engineering a way to calculate the best keypoints to traduce those IKs (already done that for fingers sliders).
     
  22. fivearchers

    fivearchers

    Joined:
    Apr 17, 2009
    Posts:
    716
    Argh, now i'm trying my hand at baking - not working! I'm trying to bake an align to spline object - works fine before, but after baking the object spins around on its z axis as it moves...can't figure out what setting might be causing this.
     
  23. jakkovanhunen

    jakkovanhunen

    Joined:
    Oct 20, 2008
    Posts:
    79
    I keep having problems when I use joints for animations, no matter if I use the export script or if I manually bake the joint positions. Once in Unity the start position is always the neutral position, no matter how much I bake/pose/keyframe and the animations are messed up.

    In previous iterations of the rig there also was a lot of mesh distortion, but I managed to clean that op.

    After spending a couple of days on this I've converted all joints to bones and manually re-weighted the skin (the converter missed a couple of spots), baked positions and now all seems to be okay (keeping fingers crossed). I was hoping I could get the joints to work, because the workflow is a lot nicer that way.

    Still, I don't get it, for some people joints seem to work, but for others they don't.

    gr.jakko
     
  24. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Hello Jakko,

    I have encountered a similar problem until I discovered that Cinema 4D was allowing animations with non-aligned joints. But in Unity, they are all automatically re-aligned on import, which can lead to horrible mesh deformations.

    So make sure all of your bones are correctly auto-aligned in c4D :)

    _________________

    I got one other question regarding the script in this thread and Joint exporting :

    Baking all frames is way too heavy for ingame performance.
    Isn't there some plugin, or script, or whatever, that could bake "intelligently" IKs ? Like keeping the exact same trajectories, but with way less keyframes ?

    I think this would really be vital for every gamedev working under c4D, so I'm really surprised nobody on forums has already talked about it .. :roll:
     
  25. jakkovanhunen

    jakkovanhunen

    Joined:
    Oct 20, 2008
    Posts:
    79
    I think the best way is to manually add the keys for the most important positions. A bit laborious, but I don't see how a script could determine the positions automatically. I will be going that route at the end of the development cycle, hand optimizing all animations this way.

    (But if a brilliant person could devise a script that would do that automagically for me, I would be very happy to use it)

    You mentioned the alignment of the joints: I thought I had done that using the Align command in C4D, isn't that enough? The end result was still messed up in Unity. Is there a better way to align joints in C4D?

    Like I said, I ended up using bones because the end results were more predictable than when using joints. Still having skin weighting problems though, but I managed to hide that for problematic animations.

    Here example of some of the problems I encounterd:


    gr.jakko
     
  26. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Arg, manual adjustment is plainly impossible for my game, as there are 8 different chars, 1500+ frames each, with very precise joint rotations. That would take ages to adjust trajectory deformations :/
    I will continue to dig some sort of script to find the best matching reduced splines. Will share it here if I come with success.

    Let's see your pics (cute character, I like the color choice).

    Ok it looks like alignment problem to me :)

    Alignment should be done on the Z axis, with "to children" parameter on each Joint (that's how Unity understands FBX bones I guess).

    But be careful, if you already set keyframes for this joints, your alignment will be overwritten as soon as you play the animation.

    I personally had to write a custom script to re-record every keyframe of every re-aligned joint, using a clone of the main skeleton, with no keyframe, copying the original via a "parent" constraint tag . A pain in the ass at the beginning, but as soon as you find how to handle your script, it's a matter of one-click maneuver.

    Finally, if your joints are already aligned in c4D, I doubt it would be from a bad weighting, as it's a single numerical value for each vertex, in a non-destructive exporting method.

    Good luck anyway ;)
     
  27. jakkovanhunen

    jakkovanhunen

    Joined:
    Oct 20, 2008
    Posts:
    79
    Thanks, actually the character texturing isn't finished yet. Will post pics and movies when Rainbow Raid project is moving a bit more towards the final visuals.

    With a bit of hacking I resolved most of the animation issues. It looks alright now when exporting to Unity. I will take another look at the alignment for the other characters. Now that the main characters is alright, I dare not touch it :)

    gr.jakko
     
  28. TBoxman

    TBoxman

    Joined:
    Aug 2, 2008
    Posts:
    29
  29. TBoxman

    TBoxman

    Joined:
    Aug 2, 2008
    Posts:
    29
    Wow. I'm surprised this topic has had zero traffic in the past 9 months. Is moving joint rigged characters from C4D to Unity still problematic? did R11.5 help any? Have there been new tools released? Are there no new procedures that work universally for users?

    Or has everyone just given up and not taking advantage of the C4D and Unity combination?

    Terry
     
  30. Per

    Per

    Joined:
    Jun 25, 2009
    Posts:
    460
    Why not try it out for yourself?
     
  31. gamesurgeon

    gamesurgeon

    Joined:
    Oct 11, 2009
    Posts:
    427
    Last time I tried, joints still don't work properly with .fbx. I still use bones :/
     
  32. Per

    Per

    Joined:
    Jun 25, 2009
    Posts:
    460
    What doesn't work about them for you?