To avoid as much confusion as possible let me begin by clarifying exactly what this project was set up to become. For the duration of 5 weeks at 50% part-time I was asked to specialize in anything game related that interested me. Something I wanted to explore and learn more from with no apparent restrictions except time. This led me to really sit down and think about what part of games interested me the most and what area I believed myself to be able to excel in.
Since I’m a huge fan of third person games that allow you to see your character or vehicle and all the positive gameplay elements that enables I chose to explore the challenges of AAA games such as Assassin’s Creed or Mass Effect by specializing in the 3 C’s (Camera, Character, Controls).
My goal was to be able to recreate something similar to a Assassin’s Creed loading screen scenario in our own built engine. Furthermore I wanted to implement “root motion” support, making the animations control the movement of the character, to take it even closer to AAA standard today.
I knew from the getgo that in order to make a believable case of this I needed motion captured material. Not only that, I specifically needed a rig with a root node (for root motion) and multiple motion captured animations, preferably separated in binary exported fbx:es since our engine use assimp for loading fbx files. You don’t need to be a rocket scientist to tell you it’s going to cost some money to get a hold of this and luckily I’m no rocket scientist, so off to the Unity Asset Store I went!
I found a mobility pack made for Unity but with separate fbx files for all animations and the rig that was all available post purchase. With little to no hesitation I parted with my money and began my journey.
Tackling Root Motion
Since no one had tried root motion at The Game Assembly before I was extra intrigued to make this work for my specialization and so I began to study the animations I bought immediately. I was happy to find a root node (a “third leg” if you will) moving just as planned on the rig which meant that any movement done in the animation would be directly translatable to my character’s in game transform. At this point I knew that the animations would be able to control all the movement I’d choose to let it.
Next step was to load this animation into the game. As I mentioned before our engine uses assimp as fbx loader which up to this particular minute had been a rather nice solution with triangulation, optimizations and verifications all there as flags we could use to make fbx loading effortless. Well now I had a problem. My root node I just saw in Maya isn’t showing up in game, but the rest of the model is (and it is looking great). Debugging showed me that the model loaded from assimp in to our engine didn’t contain any root node and without it there would be no feasible way to keep track of the characters’s movement.
With some support from our great programming teachers I was able to download the source code for assimp and attach it to our engine while debugging giving me insight in precisely how the fbx was prepared before loading in to our engine. I soon realized that there was no way of solving my problem using assimp’s flags without sacrificing the optimizations made for every model loaded into the game and so I came to the conclusion I had to enable support for my root node in assimp, and compile it as a new version for use in our engine. Although I had to make multiple changes due to assimp’s nature of discarding anything it doesn’t consider important this particular for-loop (taken from assimp) was the root of all evil.
I needed for the boolean “ok” to be true, even if the root node’s “count” (skinweights) was 0. And so started a heavy chapter of following assimp’s endless sanity checks which began to feel more and more like insanity until it finally happened. Assimp let the root node through and our engine embraced it with open arms as a bone and that sure was the pinnacle of the entire root motion implementation looking back on it all. The pride of accomplishment was mine to taste!
Moving the character
The table was set and dinner was about to get served in Visual Studio. With a multitude of animations to choose from I started with the basics. Idle, Run, Sprint and all transitions in between that I had at my disposal. First things first though, I set up a run animation on a straight with a freecam allowing me to test the animation based movement (root motion). I used a green cube to represent the transform that the character would use as it’s parent transform, meaning the animations would be played from this transform at all times. And I chose a red smaller cube to represent the root that would tell me where the character actually is which I could then use whenever an animation looped or changed. So before implementing any actual root motion code this is what I was looking at.
In essence all I needed to do now to turn this into root motion was to grab the root bone’s matrix before restarting the animation and apply it to the parent transform (green cube). And the result was a pleasure.
Coming this far I reckoned I wanted even smoother animations and so I extended the animation pipeline from using baked transforms created at compile time at 24 keyframes/s to using them as keyframes to interpolate between. This gave a much smoother result and was great to have when adding blending between root motion animations. I won’t go into detail about all the edge cases of blending with root motion but feel free to drop me a question or two if you’re intrigued.
Camera and Controls
Up ’til now I’d spent a substantial amount of my planned time on the character, but as my heading says there is two equally important factors I haven’t given any love yet, yes you’re absolutely right, it’s the camera and controls. As I had already implemented an input system and a freecamera I had in fact laid the ground work for both of these and so starting further research and implementations for the camera was quite comfortable. For starters I pulled up a video of Assassin’s Creed Syndicate and set it on fullscreen. On my other screen I lined up my camera to match the perspective as close as I could while still feeling right. Some things just need the touch of ones feeling to work, and the camera to some extent needs that kind of love. I came to the conclusion that an FOV (Field of View) of 70 was just about right and after some more close comparing I came up with this.
Now I pinned the camera at this offset for now and began translating the inputs from the controller to actual directions which ended up being much easier than I expected as I could just use the directions of the camera, skipping the up-direction. At this time I then added the only movement based feature that isn’t entirely driven by animations – rotation. I set up a function for rotating the animation at the center of the root node (red cube) which in turn rotated it’s parent transform (green cube). This would give away the immersion of root motion when turning either very fast or turning in place. Since I wanted to focus the remainder of the specialization on the actual 3 C’s I was fine with this compromise.
However, what I just realized after this was that not only should the camera and controls be developed together, they are absolutely doomed to depend on eachother until the end of games as we know it. You’re probably nodding or thinking I’ve lived under a rock but to be honest I can’t really say that as a gamer I’ve ever given a second thought about the camera unless it stops showing me what I want, and in turn making it harder to control my character. Thus if the camera is made to maximize control the best results should always be achieved. I can humbly say that this specialization has already opened my eyes wider than I thought and I’ve only just begun.
The actual reason for this insight was in fact when I tried to turn with a camera pinned to the rotating transform. Without a proper turnrate and some way of understanding that you’re turning things quickly feel off or even broken. I made sure to implement a maximum turnrate for the character and then started on camera controls (rotating the camera via input).
Quaternions had been a constant pain in my Euler loving rear up until recently, when I decided to make love and not war when translating my input axis to pitch and yaw around the character. One thing I learned the hard way was exactly why Quaternions aren’t commutative even though you multiply them and that is of course because doing separate rotations in different order will yield different results.
I also came to the conclusion that by doing my pitch before my yaw made sure the yaw didn’t “screw” up the orientation. Good times!
Once the camera controls was in place I looked closer on how other games used their camera dynamically and found that most pull away from the player when sprinting and if you’re moving the camera always try to make it’s way behind the character giving you clear sight ahead. This is something I replicated by setting up different camera offsets depending on your current movement state. When an offset changed I set up a curve interpolation between the offsets.
The moving to the back I solved by setting up a timer that counted down at different speeds depending on which movement state. So if you sprint I wanted the timer to count down quickly so you won’t miss anything in front of you but should you just jog or stand still I want you to be able to look more freely without having to rotate the camera constantly. Feedback from people trying out the project were also a wish for being able to turn towards the camera without it rotating with you. I agreed once I tried changing it and so the camera and controls we’re changed and later concluded.
Making it presentable
With a few days left it was time to appeal the eyes, making the presentation look a bit more final. Earlier I had sat down with one of our school’s best artists at being ginger, luckily for me he is also good at texturing so in one evening we we’re able to come up with some decent textures for my character. As you can see the result was something we both could live with.
I had also come up with an idea for the environment that kind of sticked throughout the project and so after a few different cube textures I could release him into the wild and continue with my idea. For it I chose to make a grid of cubes that would dynamically come down to act as your floor when within a certain distance. I imagined it could be quite the sight to have hundreds of them soaring through the air while you’re running around and for me details like this are what makes a good game great. I regrettably didn’t have time to implement any form of instancing in our rendering which meant a specified grid size had to suffice. Nevertheless my project felt like a success and even though there are things I’d like to improve or redo if the time was given I’m still at peace at what I’ve accomplished in the 5 weeks that I had.
For your convenience I made two versions with different grid sizes. A larger grid will demand higher performance.
-Xbox One/360 controller
Left Stick: Move
Right Stick: Rotate camera
F: Toggle free/character camera
WASD: Move free camera
C: Toggle mouse cursor on/off
Thank you for reading!