Unreal Engine 5 mannequin with CAT (Character Animation Tools)

Stragalet
17 min readJul 13, 2023

--

Introduction

I struggle with programing and I can anticipate that I will struggle a lot when doing a game, so I was thinking I want to maintain UE5 mannequin bone structure so everything goes smooth as possible later on, at least on the animation side.

However, there wasn’t a lot of clear and complete information available. Fortunately, I found some great scripts, templates, and tutorials from talented people, including:

While this is great material, I was missing some clear reasoning and information. So, I tried to find my way as a developer (even though I’m not one) and came up with a solution that draws from both Miloš Černý and bond1’s approaches.

Solid Solution for later.

Less work and fewer headaches later on.
I wanted a solution that allowed for customization, was robust, and had custom animation and mocap capabilities with ease.
I needed a solution that was ready to add extra bones, as the UE5 mannequin has lots of bones, especially in the hands. The “bond1” solution had a simplification there that I didn’t need, so I couldn’t use his template exactly.
Additionally, I wanted to respect the naming convention and bone orientation of the bones like bond1, so I wouldn’t have to worry later on in UE. Miloš Černý’s method did not take care of that part, and I guess he was relying on a retargeting solution later on in the pipeline. That would have introduced more variables that I just don’t want to deal with.

Why all the hassle?

First, if this were for an interactive movie or animation, I wouldn’t have done all of this. I would have exported the CAT rig or Biped rig as is, and UE would have loaded it without any trouble (I tried). I wouln’t have cared about naming conventions or bone orientation, it just works.
However, the objective this time was to have something that we can use very easily in games as well so respecting the UE5 skeleton layout seems the way to go.

CAT and Biped solutions have their custom bone orientations and limbs links, they can be somewhat customized but fixing the orientation is tricky.

This solution will provide the UE5 skeleton rig, but you can use it freely with CAT, so good for loading motion capture, but also good to hand animate.

Pros

  • can animate the CAT rig as you will.
  • can recycle this setup to every character with minor tweakings.
  • UE5 will understand the exported rig perfectly.
  • No retargeting needed for most animations.

Cons

  • You will end up with 2 hierarchies so you need to update them both when there is a change.
  • the setup takes some time.

Would be awesome if in the future 3DsMax can export the ideal UE5 skeleton without this methot of course.

Process overview.

  1. I will extract the Manequin from UE5.
  2. Convertit to helpers so we can use it with ease in 3dsMax.
  3. Build a very similar CAT humanoid rig on top.
  4. “link” (Position and rotation constraint) the UE5 helper hierarchy to the newly created CAT rig.
  5. You will end up with 2 separate hierarchies, one for animating with its own bones and orientations, and another one with UE5 skeleton hiearchy intact so you don’t need re-targeting.

Disclosure.

This is my own version of the process. I cannot confirm it is the best way, but it makes sense.
Other people have tried similar things, but it could be wrong in some ways or overcomplicated.
Anyways, if I get more information about this, I will update this documentation with a better method.

I think it’s a fun read, and you can learn lots of things, including some easy scripts and other stuff. I tried to be detailed, and I don’t think I skipped any important parts, but I’m sorry if I skipped something by mistake.
Just let me know in the comments, and I can update it.

I strongly believe that it’s better to learn how to do this by yourself so you can make a more customized version of it. Also, if you want a more polished or just another version of this, I recommend “bond1” version. It has a very neat root feature that I’m totally missing at the moment.

The process!

Export an FBX from UE5 mannequin.

Just open a UE5 3rdPerson project, and with the humanoid selected export as FBX.

Convert the Bones to Dummy

Open the FBX in 3DsMax and select the chain of bones and from the root, and export it as FBX.

Import it once more to 3DsMax.

All the bones have been converted to dummy and mantaining the hierarchy intact.

I tried to check convert Dummy to Bones, but It won’t import it as bone no matter what, so well, Dummies will do.

Convert Dummy to Point helpers

Now that we have Dummies, we can convert them to PointHelpers that is its nicer because we can change color and size. ( if you try to do the same from bones directly to point helpers won’t work, so we need the dummies first)
I have a script of my own for this in my toolbar, but I’ll share the code here as it is very simple. It works this way.

Select everything you want to convert, and then select as a last object, the object you want it to be the new shape. It is very important that the last object is the “target” object.

just a screenshot from my toolbar for understanding what it does.
if selection.count >=2 then
(
oldObjs = for obj in (selection as array) collect obj
temp = oldOBJs[oldObjs.count] -- store last object from the array.
deleteitem oldObjs oldObjs.count -- delete the last object from the array.
if queryBox "Replace as INSTANCE ? " beep:true then
(
displayTempPrompt "---- Replaced with instance ----" 0
for i in oldObjs do (
i.baseObject = temp.BaseObject
)
)else(
displayTempPrompt "---- Replaced with copy ----" 0
for i in oldObjs do (
i.baseObject = copy temp.BaseObject
)
)
)else(messageBox "Select 2 or more objects.")
),

Very simple script but very useful. Lets say you have 3 objects 2 boxes and 1 teapot, but you would like to have 3 teapots.
Select first the 2 boxes and at last the teapot and execute this script. (control + e)

here is where you add the script code. New Script ► and just copy paste there the text. (control+e) to execute.

It will ask you if you want instance, if not, will do a copy. Do instance.
Now all become teapots and editing one will change the other.

We will do the same but with the dummy and selecting a newly created point helper the last. ( you can delete that one later )

You can update the size of the helpers and adjust them.

⚠ CAREFULL NOTE ⚠

I noticed after using it for a while that the mannequin bones are not perfectly symmetrical, this was creating an issue while skinning where sometimes It wouldn’t pick it correctly.

this is the missalignment I’m talking about… small but can be bad for symmetry.
in some places the difference was larger

This only happens because I matched the CAT rig to the Mannequin UE one… if I was doing the other way around then no problem as CAT was pefectly symmetrical.
Annyways, to make sure that the mannequin has all the helpers symmetrical I made a script that finds the “ _l “ parts and mirrors whatever there is in the “_r” parts.

Make sure you select ALL helpers from the mannequin first, also make sure that the object is not locked in anyway, and that there are no any other objects on the scene with the same name!
Also make sure the objects end with “_l” “_r” and that you didn’t duplicate it and becomed “_l001” or something…
With all that it should work flawlessly.

      
fn SelectAtLeasttwo =
(
if selection.count >=2 then
(
displayTempPrompt "there at least 2 object selected continue" 8000
SelectionOk = 1
return SelectionOk
)
else
(
displayTempPrompt "⚠ select at least 2 object ⚠" 8000
messageBox "⚠ select at least 2 object ⚠" title:"Alert"
SelectionOk = 0
return SelectionOk
)
)

fn FMirrorPosRot180 =
(
with undo "copy rotation and such" on
(
oldObjs = #()
temp = #()
SelectionStuff = SelectAtLeastTwo () -- gets the result from the SelectAtLeastOne Funcion, 1 for yes 0 for no
If SelectionStuff == 1 then -- checks the function result and if it is possitives continues, otherwise shows a popup warning
--if selection.count >=2 then
(
oldObjs = for obj in (selection as array) collect obj
temp = oldOBJs[oldObjs.count] -- store last object from the array.
deleteitem oldObjs oldObjs.count -- delete the last object from the array.

displayTempPrompt "---- Replaced with instance ----" 0
for i in oldObjs do
(
OldPos = i.position
print temp.rotation
i.rotation = temp.rotation * (matrix3 [1,0,0] [0,-1,0] [0,0,-1] [0,0,0]) --raruno pero funciona
i.position = temp.position * [-1,1,1]--(matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0])
in coordsys local rotate i (eulerAngles 180 0 0)
print i.rotation
)

)
)
)

fn UEAutoFixer =
(
SelectionStuff = SelectAtLeasttwo () -- gets the result from the SelectAtLeastOne Funcion, 1 for yes 0 for no
If SelectionStuff == 1 then -- checks the function result and if it is possitives continues, otherwise shows a popup warning
(
TotalSele2 = Selection as Array
TotalSeleCount = TotalSele2.count as integer
print "hellyeah"
print TotalSele2
print TotalSeleCount
o = 1 as integer
EnableSceneRedraw = false

for o = 1 to TotalSeleCount do -- much nicer :D
(
workingObjName = totalsele2[o].name
workingObjName += "."
MirrorObjName = substituteString workingObjName "_l." "_r."
-- check if mirror object exist in the array
mirrorObjectExist = false


for t = 1 to TotalSeleCount do
(
checkthis = totalsele2[t].name + "."
if checkthis == MirrorObjName do (mirrorObjectExist = true exit)
)


if mirrorObjectExist == true then
(
select totalsele2 [o]
if workingObjName != MirrorObjName then --if they are different
(
-- check if they are L and R
workingObjNametemp = substituteString workingObjName "_l." "_r."
if MirrorObjName == workingObjNametemp then
(
print"mirror this two"
print workingObjName
print MirrorObjName
MirrorObjName = substituteString MirrorObjName "_r." "_r"
workingObjName = substituteString workingObjName "_l." "_l"
print workingObjName
print MirrorObjName

select (getnodebyname workingObjName)
selectmore (getnodebyname MirrorObjName)
print $
print"---------------"
FMirrorPosRot180 ()
)
)
else
(
-- they are the same! so don't do anything.
print"they are R with R so I don't do anything here"
)
)
else
(
print workingObjName
print MirrorObjName
print "didn't find match for this"
)

EnableSceneRedraw = true
redrawViews ()
)
)
)


UEAutoFixer()

now we continue…

Do a little bit of cleaning inside 3DsMax.

The mannequin has some bones that are not beeing used, I’m not really sure why but I think it is because it serves as a more complete skeleton structure just in case someone want to add more of the bones to the skinning. Why I came to this conclusion? well there are bones that are not skinned in any way nor move in that character.

So I will create some selection sets, just for ease of use, with the main structure I want to use and the other extra bones just in case I need them later.

Here I separated Blue — Main bones (now point helpers), Yellow — extra.

Can be a bit hard to know what are the important ones, so I recommend:

  • You can check what affects the skinning mesh in the original FBX. if it moves the mesh, might be important.
  • You can visualize, in the original FBX export, the bones as bones since once we convert them to point helpers can be more tricky to know what is what.
example on how to I separated them.

Just be aware that you cannot break the hierarchy. I mean, you can “ignore” the links that are finals, but no the ones that are trunk or base to the other bones.

you can’t skipp the red cross one. but you can skipp the green circle one.

Example: you can ignore the “thigh_correctiveRoot_r” because that chain ends there and doesn’t have anything after, but you cannot skip “pelvis” otherwise the legs would be floating without a parent and UE won’t like that.

Color Code

I change the colors similar to what CAT does to diferenciate a bit more the helpers. this is not needed but it is fancy.

I just do because I can.

Reason I don’t delete the Extra (red) point helpers, I might use this in some characters and I rather have the name ready there for now.

Create a CATrig

I will create a cat rig that matches that structure.
It could be a simplified version too, like for the legs you don’t need to do the divisions, but in this case I would like to have those division so I’ll go with almost a perfect match with the UE5 skeleton here.

start with the CAT rig parent object. you can find this in Helpers ►CAT Parent.

Start with the basic human and modify it to match the Unreal Engine skeleton.

Pay attention to the bones you need.

Some parts of the CAT rig needs to be splitted into more pieces if you want to match that aswell, it is not mandatory though, you might want to use a simplified version, but this time I will be using it like this.

So you go align pivot to pivot and do your best job in the feet and hands.
It can be tricky, sometimes only position alignment is neede some times rotation in some axis is also needed.
I recommend opening another Max instance side by side so you can check the original bone CAT orientations in case that they become messed up in the process… For instance, Y axis should be pointing up from the palm in my case… so If it’s pointing anywhere else it is messed, and you should twist it back.

like this all the bones.

Remember that spine will be missing some bones that you will need to add and the fingers too require more bones, and also the arms and legs.

very imporant to work here the orientations and positions.

Again, check that the CAT bone orientation didn’t go crazy when doing align, by default Y should point up and X front towards the end of the finger.

You can mirror left and right so you just need to do one arm and copy to the other.

Well there it is, we are getting closer. By the way I changed the colors to match the CAT. Not relevant at all.

Check it

Not joking, triple check what you did otherwise any miss from now on… could be very time consuming.
Save incremental often.
Go on every bone and helper, check the orientation and the position alignment.
Sometimes readjusting something in the spine can mess your hand so check that nothing moved.

Make “UE5 ready rig” follow CAT rig.

We have to select every “UE ready Point helper” and do a Position and a Rotation list controler where we will do a position/orientation constraints after the existing XYZ and Euler controllers respectively.
Ok this sounds like alien language but it is easier than it sounds let me explain further.

select one point helper go to the move pannel and check that out.

So every helper has its own “controller”, a controller is a thing that tells it where is it and what is the orientation (and also scale but we don’t use this time).

We want to keep the existing Orientation and Position, otherwise it would move to the 0,0,0 position, but we want to tell it that from now on it should move with the corresponding CAT bone.

How we do this? easy, we create a “list” inside position and rotation controllers respectively, this allows to add different types of controllers underneath… for instance another type of controller that follows another object called “constraint”.

But why we can’t use 3dsMax link function?
Well we can’t use link because that would change the hierarchy, and we want to keep the hierarchy intact so UE5 understands it perfectly.
That is why we use this other method to “link” the objects toguether.

I will explain step by step what is going on but hold it because there is a faster way at the end.

Click Position, go to the little icon, select Position List from the list and OK.

A Position List Controller will appear and will have the same Position XYZ as first option but now also will show a second option “Available” there we will add the Position Constraint, this will make our Point follow the bone once we select the target.

So now we have the Position Constraint ( It tells the Point to follow another object, without changing the hierarchy )

And then we can pick the object we want to follow.
The object shouldn’t move much because we aligned the CAT bones to it, but some of the minnor bones could have a slight shift, to solve that just click the “Keep Inital Offset button” and will fix it.

But this will update only the Position but not the orientation so we will repeat this also for the “Rotation” adding an “Rotation list” and in the aviable slot an “Orientation Constraint”

Also here we need to click also “Keep Initial Offset” or all the structure will turn. and we don’t need that.

The Faster way.

Oh! This is the faster way, but hold it… because maybe there is the Ultra Faster way! I’m hyping you, I know…

The faster way is, with the UE point helper you want to edit go to Animation menu on top, Position Controllers ►Position Constraint.
It will create the List for you automatically and same with Rotation Controllers ► Orientation Constraint.
Just remember to click “ Keep inital offset” in both.

By the way you can drag the Animation menus outside so you don’t need to click on int everytime.

If when doing the Constraint thingy something moves… check, because that means things weren’t aligned properly.

And we need to repeat this for every bone… yeah… every…. single… bone.

The Ultra Faster way.

So I put toguether this script… it has some very easy checks for list controllers, in case that you already linked it but I’m not checking much more so be aware not to apply it two times :)
It works like the other script I shared before, select first the “UE ready point helper”, and second the CAT bone as the target. It will do the list constraints all at once.
You still need go selecting stuff in pairs but I think that makes it less painfull.

By the way the “keep inital offset” gets activated too automatically.

--thanks Mambo4 from CGsociety forum for the few lines of code and comments :)
--modifier a bit the code so it can also handle position constraints and works with the "last is master" mode.
--ツンデレスクリプトやで。。。

if selection.count >=2 then
(
oldObjs = for obj in (selection as array) collect obj
temp = oldOBJs[oldObjs.count] -- store last object from the array, in reality stores the count number.. but is the same as the last one of course...
deleteitem oldObjs oldObjs.count -- delete the last object from the array.
for i in oldObjs do
(
if classof i.rotation.controller != Rotation_list then --simple check if the object wasn't Rotation listed before.
(

if classof i.position.controller != Position_list then--simplecheck if the object wasn't Rotation listed before.
(

i.rotation.controller = Rotation_list() --converts rotation controller form Euler XYZ to list, adds EulerXYZ to that list
i.rotation.controller.available.controller=orientation_constraint() --adds orient constraint to the list
i.rotation.controller.setactive 2 --otherwise, EulerXYZ was active
i.rotation.controller[#Orientation_constraint].appendTarget temp 50 --($.rotation.controller[2] would also work, but I like to keep things clearer)
i.rotation.controller[#Orientation_constraint].relative = on

i.position.controller = Position_list() --converts Position controller form Position XYZ to list, adds Position XYZ to that list
i.position.controller.available.controller=position_constraint() --adds position constraint to the list
i.position.controller.setactive 2 --otherwise, EulerXYZ was active
i.position.controller[#Position_constraint].appendTarget temp 50 --($.position.controller[2] would also work, but I like to keep things clearer)
i.position.controller[#Position_constraint].relative = on

displayTempPrompt "LETS GOOOO!!!!!! ♥♥♥♥♥♥ one less!! DON'T GIVE UP ♥♥♥♥♥♥ がんばるんだ!!!!" 4000

)else(messageBox "the position.constraint already contain something あらまー、ちゃんとなにやってる見てくれないですか!")
)else(messageBox "the rotation.constraint already contain something あらまー、ちゃんとなにやってる見てくれないですか!")
)
)else(messageBox "Select 2 objects one helper and a bone あらまー!オブジェクト二つせtなtくしてくれないでしょうか。。。")

Check on how to use scripts a little bit up if you don’t know how to.

If you mistake you can always delete the position constrain and re-align something that you missed.

Select all the code, drag it to a new toolbar or a custom toolbar you might have already out and It will become a button! super useful instead of pressing Control+E all the time…

It took me around 6 minutes to connect everything, even with a little error in one of the links where I had to do manually.

There are the UE5 skeleton has IK controllers that should be constrained to the hand, feet, or the root controller respectively. Also the center of mass, and interaction point helpers.

Lock everything that shoudn’t move.

Like the UE helpers, you shouldn’t be able to manipulate them directly so just Lock them up.

The Root Issue.

Well, there is different ways with the root bone, I will just parent the root to another object for now and that’s it. This object will be outside the hierarchy of CAT, will be independent for now.
At the moment I don’t really need this in UE so I will come back to this and try to make it better.

Or even better, maybe you already know how to do something fancy and can explain to me in the coments! :)

Root Control object.

Create an object in the base to control the Root independently. Get the root point helper and like we did many times already, constrain it to that newly created object.

Later I hope I can make something more fancy here but this should do for now.

the sape is not relevant, you can use 3dsMax Teapot too.

So in the end we get 1 control rig made in CAT.

skematic view in 3dsmax.

And we also have the “export” rig.

It is super large because it also includes all that “extra” helpers that we might not need, so If you really don’t need them you can delete them, but I would suggest you save this version somewhere.

Also you shouldn’t export the “UE_RIG” helper, just from “root” one… delete everything over “root”.

this is the UE main bone structure without the extras, more compact.
89 bones vs 161 in the full version.

Now you can adapt that CAT to any character, and add the extra bones if needed.

So far I did a fast test and it worked flawlesly in the first try.
Now time to Animate in CAT and see if it also works nice!

skining was super tempory… just for the sake of testing the rig. This character is a bit over the floor because it is supoused to wear shoes…

The end ( for now )

That is all for now…
Thankyou for reading :D

Remember you can follow me on twitter, instagram, Cara, Threads, Medium, Facebook, under I will apreciate your comments :)
Here is my lit.link to all that.

Maybe I should do a Video tutorial with this if it helps anyone… hummm I’ll think about it.

https://lit.link/en/stragalet

--

--

Stragalet

ストラガレットです! I like making 3DCG stuff OC. Indie Game dev