diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ed2c86..6ed0d07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ add_shaders(shaders ) add_executable(demo + animation.c gpu.c linear_alg.c main.c diff --git a/animation.c b/animation.c new file mode 100644 index 0000000..bac7383 --- /dev/null +++ b/animation.c @@ -0,0 +1,50 @@ +#include "animation.h" + +#include +#include + +static mat4_t bone_transform(bone_t bone) +{ + return mat4_mul( + mat4_translate_vec3(bone.translation), + mat4_mul( + mat4_rotate_quaternion(bone.rotation), + mat4_scale_vec3(bone.scale))); +} + +static void compute_bone_matrices( + size_t bone_count, const bone_t *bones, + const mat4_t *inverse_bind_matrices, mat4_t *matrices) +{ + matrices[0] = bone_transform(bones[0]); + for (unsigned i = 1; i < bone_count; ++i) { + const mat4_t transform = bone_transform(bones[i]); + assert(bones[i].parent < bone_count); + matrices[i] = mat4_mul(matrices[bones[i].parent], transform); + } + + for (unsigned i = 0; i < bone_count; ++i) + matrices[i] = mat4_mul(matrices[i], inverse_bind_matrices[i]); +} + +animation_state_t animation_init(const model_t *model) +{ + mat4_t *bone_matrices = calloc(model->bone_count, sizeof(mat4_t)); + assert(bone_matrices != nullptr); + return (animation_state_t) { .bone_matrices = bone_matrices }; +} + +void animation_cleanup(animation_state_t *state) +{ + if (state->bone_matrices != nullptr) { + free(state->bone_matrices); + state->bone_matrices = nullptr; + } +} + +void animation_update(animation_state_t state, const model_t *model) +{ + compute_bone_matrices( + model->bone_count, model->bones, model->inverse_bind_matrices, + state.bone_matrices); +} diff --git a/animation.h b/animation.h new file mode 100644 index 0000000..20cde1e --- /dev/null +++ b/animation.h @@ -0,0 +1,15 @@ +#ifndef ANIMATION_H +#define ANIMATION_H + +#include "model.h" + +typedef struct { + mat4_t *bone_matrices; +} animation_state_t; + +animation_state_t animation_init(const model_t *model); +void animation_cleanup(animation_state_t *state); + +void animation_update(animation_state_t state, const model_t *model); + +#endif diff --git a/linear_alg.c b/linear_alg.c index 2aa141f..6cbbaee 100644 --- a/linear_alg.c +++ b/linear_alg.c @@ -74,3 +74,60 @@ mat4_t mat4_perspective(float aspect, float fov, float near, float far) { 0, 0, -far * near / (far - near), 0 }, }; } + +mat4_t mat4_translate_vec3(vec3_t v) +{ + return (mat4_t) { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { v.x, v.y, v.z, 1 }, + }; +} + +mat4_t mat4_scale_vec3(vec3_t v) +{ + return (mat4_t) { + { v.x, 0, 0, 0 }, + { 0, v.y, 0, 0 }, + { 0, 0, v.z, 0 }, + { 0, 0, 0, 1 }, + }; +} + +mat4_t mat4_rotate_quaternion(vec4_t q) +{ + const float xx = q.x * q.x; + const float xy = q.x * q.y; + const float xz = q.x * q.z; + const float xw = q.x * q.w; + + const float yy = q.y * q.y; + const float yz = q.y * q.z; + const float yw = q.y * q.w; + + const float zz = q.z * q.z; + const float zw = q.z * q.w; + + return (mat4_t) { + { + 1 - 2 * (yy + zz), + 2 * (xy + zw), + 2 * (xz - yw), + 0, + }, + { + 2 * (xy - zw), + 1 - 2 * (xx + zz), + 2 * (yz + xw), + 0, + }, + { + 2 * (xz + yw), + 2 * (yz - xw), + 1 - 2 * (xx + yy), + 0, + }, + { 0, 0, 0, 1 }, + }; +} diff --git a/linear_alg.h b/linear_alg.h index 09fcaa6..8eb5d52 100644 --- a/linear_alg.h +++ b/linear_alg.h @@ -80,5 +80,8 @@ vec3_t vec3_cross(vec3_t v, vec3_t u); mat4_t mat4_mul(mat4_t m, mat4_t n); mat4_t mat4_lookat(vec3_t camera, vec3_t target, vec3_t up); mat4_t mat4_perspective(float aspect, float fov, float near, float far); +mat4_t mat4_translate_vec3(vec3_t v); +mat4_t mat4_scale_vec3(vec3_t v); +mat4_t mat4_rotate_quaternion(vec4_t q); #endif diff --git a/main.c b/main.c index a0b9dd8..cc8e9c0 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,4 @@ +#include "animation.h" #include "gpu.h" #include "model_format_glb.h" @@ -71,6 +72,10 @@ int main(int argc, char *argv[]) gpu_ctx_t gpu; gpu_init(&gpu, &gpu_config, model); + // Initialise animation + animation_state_t anim = animation_init(&model); + animation_update(anim, &model); + const vec3_t cam = { 0, 4, -4 }; const vec3_t tgt = { 0, 0.5, 0 }; mvp_t mvp = { @@ -107,6 +112,7 @@ int main(int argc, char *argv[]) } // Clean up + animation_cleanup(&anim); gpu_cleanup(&gpu); model_cleanup(&model); glfwDestroyWindow(window);