I use the same framework as in course CS562, which I developed during summer based on C++ and Vulkan for graphics. This framework is much easier to extend and modify compared with pure Vulkan and I decided to use it for my GAM550 game project as well. For the mesh loader, I followed professor’s suggestion and adopt Assimp as basic reader. The render pipeline I used for this project is almost the same as CS562, which is a deferred, multi local light render pipeline. The difference is I added a new Vulkan pipeline (or a shader program under OpenGL definition) for skeletal mesh rendering and a new no depth-test pass for drawing joints.
Key Frames & Updating:
After loading the aiScene and loading all the meshes, I follow the instructions from OGL Dev:
(http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html) and traverse all the meshes to get bones and weights and store then in a map which uses bone name as keys. Then, for each animation node, I traverse the hierarchy tree from root node to extract all the nodes that belongs to the animation and store those nodes(with their key data, parent id and ref-pos matrix) in a linear buffer in a breadth first order with node number of each tree height recorded. When updating the animation, I can traverse this buffer and update each node transforms linearly. Lastly in the shaders, I pass both per-vertex bone weights and bone transforms as SSBOs and use glVertexIndex to index them.
Quaternion and S-Lerp Functions:
For the quaternion spherical interpolation functions used in this project, I refer to build-in functions of Assimp (which is almost the same as professors) and write my own functions which takes GLM vec4 as a quaternion. This brings me a problem: The Assimp quaternion structure uses w as its first value(same as GLM built-in quaternion). At first I directly use memory-based construct function(glm::make_Mat4) to convert Assimp quaternion into vec4, which leads to weird results, later I change the construction method into assign values one by one.
Draw Joints:
At first I tried to use cylinders to indicate directions of joints but later it seems like different meshes has different joint directions, so I made a compromise and draw sphere to show positions of joints.
Formats and Files:
Since Assimp supports quite a lot kinds of mesh formats, I tried to load skeletal meshes of different formats. The result shows that it goes well with FBX format but shows weird results when loading glb format meshes.
Bee meshes loaded in glb format, shows weird results.
Same bee meshes converted into FBX format.
In the videos that I submitted shows two different meshes with three different animations in each. The first set of animations is what professor provided on Moodle and the other one is a bee mesh with three animations. In order to realize animation instantiation I write a class named animation instance and instantiate three of it for each set of animations. In rendering loop, each animation instance will update its own bone transforms based on its own frame time and animation key data and store them along a linear SSBO buffer with offsets. Those transforms will then be indexed in vertex shader using glInstanceIndex and glVertexIndex.