As I have been developing the player editor for Elemental, I have come across a number of unexpected difficulties that were not initially obvious. I had a challenging time figuring out some of these bugs in my code so that I could get it just right. I really wanted the weapons to look like they are being held properly and armour pieces to deformed with the player without clippings like you would expect it to.
There are two main types of mounting that I'm going to cover and one takes much more care and effort than the other. These two types are as follows:
1. Mounting boneless static meshes (such as weapons)
2. Mounting skinned deforming meshes (such as armour and clothing)
Mounting Boneless Static Meshes
This one is a bit of a cake walk but there were some difficulties that I came across when doing this.
My method basically involves including bones in the player character mesh in the positions where the weapons would be placed. Figure 1 below shows these bones as they are in my current rig. I have created 1 bone in each hand and 2 bones on the characters back. The idea is that 'in game' the weapons will be parent to these pseudo bones so that the weapons simply follow in the characters hands or on their backback.
Here is some sample code showing the general idea:
TModel wepL; TModel char; TEntity wepLBone; //Assuming the weapon bone is called wep_L //Find the bone wepLBone = FindChild(char, "wep_L"); //Set the matrix of the weapon to be same as bone SetEntityMatrix(wepL, GetEntityMatrix(wepLBone)); //Parent weapon to bone EntityParent(wepL, wepLBone);
This method is very simple, however, if the bones are not initially set up properly, there will be complications. My mistakes were two fold. Firstly the scale of my bones was not 1,1,1 in Blender and I realised much too late. Secondly the orientation of x,y,z axis of the bones in Blender did not match the default orientation in LE. These two small mistakes made a world of trouble for a few reasons as I'll outline below.
1. Wrong Scale:
When you call SetEntityMatrix() it sets the scale as well as a number of other things. So because the scale of my bones was about (0.327,0.327,0.327) instead of (1,1,1), when I set the matrix of the weapon to the bone, it would scale the weapon down to 0.327.
As an alternate to spending many hours re-doing the rig I decided to cut my losses and make a work around. For this problem it was simple. I just had to scale them up again immediately after with ScaleEntity();
This was not ideal but I think going back and fixing the rig and redoing all the animations would have been a 'Bear Trap' as Josh has recently coined the term.
One may think you could just use PositionEntity() and RotateEntity() to get the orientation right instead of SetEntityMatrix(). However, both of those functions do not work on entities that are children of another entity. They seem to return the position and rotation of the parent instead of the specific bone. This isn't entirely useful in this situation.
The idea to go into blender and simply use ctrl+a to '0' the scale of the rig without actually effecting its size did occur to me. However, it badly affected the rig's orientation and was not a viable solution.
The key learning here is: Always make sure your scale is (1,1,1) prior to doing any rigging, skinning and animations.
2. Incorrect Bone Axis Orientation
Simply put this problem occurred because the orientation of the bone axis in Blender were not matching that of LE. This was not Blender's fault but mine. I should have edited them correctly before skinning. The effect was that if you set the matrix of the weapon to the bone it would not line up. The model would always be moved to a relative position and rotation to the bone origin. See Figure 2
This meant that once I had set the matrix I had to tweak the position and rotation of the weapon model before parenting it to the bone. The coding of this was not all that hard but it was difficult figuring out which axis's did what and how much I had to tweak it. Imagine if Josh programmed Vec3(x,y,z) to read the x,y,z part in random orders and you'll have an understanding of how annoying this problem is.
Once again I could have just redone the rig. However, that would have taken a very long time. Instead, I cut my losses and went for the work around. After all, the repositioning only has to be done once when the weapon is either taken out, sheathed or loaded and not every frame. Therefore, the performance impact is negligible.
The Key Learning here is: Always ensure you have oriented the axis of your rig bones correctly before doing any skinning or animations.
Mounting Skin Deforming Meshes
Mounting armour and clothing is a bit of a different story as you can't simply parent the model to a bone as the mesh has to deform with a number of bones. This makes things a little more difficult. The way I did this was to skin the armour to the relevant bones and delete all the extra bones (eg. for the boots I only took the foot, toe and shin bones). Then my plan was to parent each of the individual bones in the boots to the corresponding bone on the character model. Figure 3 shows this.
Luckily, problem 2 from the static mounting was not a problem because, in this method we are parenting bones to bones instead of meshes to bones. As the bones on the boots and the bones on the character had the same messed up axis, they kind of cancelled each other out as they were in the same orientation relative to each other.
Now there was only one major problem with this method and it involved the nature of parenting and animation recursion in Leadwerks. Simply put, when you animate a model in LE you set the recursion to 1 so that all children of the model are animated appropriately. Of course, this means that if I parent the boots bones to the character and animate the character, the recursion tells the boots to animate as well. Figure 4 shows how this looks. The right picture is with the boots parented and the left is without parenting.
The problem with this is that the boots only have a single animation frame which is the pose that it was exported with (or modelled in). So when the bones are parented they are moved into position but the animation causes the bones to move to their 'frame 1' positions again except relative to their parenting position.
This may be a bit difficult to follow so I will demonstrate in the following video.
Turn your sound up!
As you could see my solution was to simply not parent the bones, but to just re-position them every frame. Although this probably takes a bit more processing poser I can't see any way of parenting the entity without the animation recursion stuffing it up.
The key learning here is: Never parent bones to animated bones or else animation recursion will have your balls
Thank you for reading. I hope you learned something useful. Feel free to comment or ask questions.