diff options
author | omniscient <17525998+omnisci3nce@users.noreply.github.com> | 2024-08-13 22:13:29 +1000 |
---|---|---|
committer | omniscient <17525998+omnisci3nce@users.noreply.github.com> | 2024-08-13 22:13:29 +1000 |
commit | d4df846c97a7fd216748806abdb729a11a0ce2ec (patch) | |
tree | c466b49a356904842f7fb5b7df7c43adfa1b91d7 /src | |
parent | 567d384b698151e287e31140709c93f1b92e6db4 (diff) |
go
Diffstat (limited to 'src')
-rw-r--r-- | src/animation.c | 101 | ||||
-rw-r--r-- | src/animation.h | 21 | ||||
-rw-r--r-- | src/core/camera.c | 2 | ||||
-rw-r--r-- | src/render/pbr.c | 34 | ||||
-rw-r--r-- | src/render/render_types.h | 7 | ||||
-rw-r--r-- | src/resources/gltf.c | 26 |
6 files changed, 122 insertions, 69 deletions
diff --git a/src/animation.c b/src/animation.c index 1c5d893..48a5ff1 100644 --- a/src/animation.c +++ b/src/animation.c @@ -1,38 +1,71 @@ #include "animation.h" +#include "immdraw.h" #include "log.h" #include "maths.h" +#include "maths_types.h" +#include "ral_types.h" +#include "transform_hierarchy.h" -// keyframe animation_sample(animation_sampler *sampler, f32 t) { -// size_t previous_index = 0; -// f32 previous_time = 0.0; -// // look forwards -// // DEBUG("%d\n", sampler->animation.values.kind); -// TRACE("Total timestamps %d", sampler->animation.n_timestamps); -// for (u32 i = 0; i < sampler->animation.n_timestamps; i++) { -// f32 current_time = sampler->animation.timestamps[i]; -// if (current_time > t) { -// break; -// } -// previous_time = sampler->animation.timestamps[i]; -// previous_index = i; -// } - -// size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps; -// f32 next_time = sampler->animation.timestamps[next_index]; -// printf("%d %f %d %f\n", previous_index, previous_time, next_index, next_time); - -// keyframe prev_value = sampler->animation.values.values[previous_index]; -// keyframe next_value = sampler->animation.values.values[next_index]; - -// printf("%d %d\n", previous_index, next_index); - -// f32 time_diff = -// sampler->animation.timestamps[next_index] - sampler->animation.timestamps[previous_index]; -// f32 percent = (t - previous_time) / time_diff; - -// quat interpolated_rot = -// quat_slerp(sampler->animation.values.values[previous_index].rotation, -// sampler->animation.values.values[next_index].rotation, percent); - -// return (keyframe){ .rotation = interpolated_rot }; -// } +Keyframe Animation_Sample(AnimationSampler* sampler, f32 t) { + size_t previous_index = 0; + f32 previous_time = 0.0; + // look forwards + DEBUG("%d\n", keyframe_kind_strings[sampler->animation.values.kind]); + TRACE("Total timestamps %d", sampler->animation.n_timestamps); + for (u32 i = 0; i < sampler->animation.n_timestamps; i++) { + f32 current_time = sampler->animation.timestamps[i]; + if (current_time > t) { + break; + } + previous_time = sampler->animation.timestamps[i]; + previous_index = i; + } + + size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps; + f32 next_time = sampler->animation.timestamps[next_index]; + printf("%d %f %d %f\n", previous_index, previous_time, next_index, next_time); + + Keyframe prev_value = sampler->animation.values.values[previous_index]; + Keyframe next_value = sampler->animation.values.values[next_index]; + + printf("%d %d\n", previous_index, next_index); + + f32 time_diff = + sampler->animation.timestamps[next_index] - sampler->animation.timestamps[previous_index]; + f32 percent = (t - previous_time) / time_diff; + + switch (sampler->animation.values.kind) { + case KEYFRAME_ROTATION: + return (Keyframe){ .rotation = quat_slerp( + sampler->animation.values.values[previous_index].rotation, + sampler->animation.values.values[next_index].rotation, percent) }; + case KEYFRAME_TRANSLATION: + case KEYFRAME_SCALE: + case KEYFRAME_WEIGHTS: + WARN("TODO: other keyframe kind interpolation"); + return prev_value; + } +} + +void Animation_VisualiseJoints(Armature* armature) { + for (int j = 0; j < armature->joints->len; j++) { + Joint joint = armature->joints->data[j]; + Transform tf = joint.transform_components; + tf.scale = vec3(0.05, 0.05, 0.05); + Immdraw_Sphere(tf, vec4(0, 1, 1, 1), true); + } +} + +ShaderDataLayout AnimData_GetLayout(void* data) { + AnimDataUniform* d = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { .label = "AnimData", + .kind = BINDING_BYTES, + .data.bytes.size = sizeof(AnimDataUniform) }; + + if (has_data) { + b1.data.bytes.data = d; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} diff --git a/src/animation.h b/src/animation.h index 08ee92a..e0ad543 100644 --- a/src/animation.h +++ b/src/animation.h @@ -4,6 +4,7 @@ #include "defines.h" #include "maths_types.h" #include "mem.h" +#include "ral_types.h" typedef enum Interpolation { INTERPOLATION_STEP, @@ -19,6 +20,8 @@ typedef enum KeyframeKind { KEYFRAME_WEIGHTS, } KeyframeKind; +static const char* keyframe_kind_strings[4] = { "ROTATION", "TRANSLATION", "SCALE", "WEIGHTS"}; + typedef union Keyframe { Quat rotation; Vec3 translation; @@ -70,12 +73,13 @@ typedef struct AnimationSampler { } AnimationSampler; /** @brief Sample an animation at a given time `t` returning an interpolated keyframe */ -Keyframe Animation_Sample(AnimationSampler* sampler, f32 t); +PUB Keyframe Animation_Sample(AnimationSampler* sampler, f32 t); typedef struct AnimationClip { - // A clip contains one or more animation curves - // for now I think we can just enumerate all of the properties (assuming *only* one per type is in - // a clip) NULL = this property is not animated in this clip + // A clip contains one or more animation curves. + // For now I think we can just enumerate all of the properties (assuming *only* one per type is in + // a clip) and NULL = the property is not animated in this clip + // NOTE: when I call 'property' is typically referred to as a 'channel' by GLTF AnimationSampler* rotation; AnimationSampler* translation; AnimationSampler* scale; @@ -91,4 +95,11 @@ typedef struct SkinnedAnimation { size_t n_joints; } SkinnedAnimation; -void animation_play(AnimationClip* clip); +PUB void Animation_Play(AnimationClip* clip); + +void Animation_VisualiseJoints(Armature* armature); + +typedef struct AnimDataUniform { + Mat4 bone_matrices[4]; +} AnimDataUniform; +ShaderDataLayout AnimData_GetLayout(void* data); diff --git a/src/core/camera.c b/src/core/camera.c index c996d7d..77ddad6 100644 --- a/src/core/camera.c +++ b/src/core/camera.c @@ -87,4 +87,4 @@ void FlyCamera_Update(Camera* camera) { } // TODO: Right mouse => pan in screen space -}
\ No newline at end of file +} diff --git a/src/render/pbr.c b/src/render/pbr.c index 57ca1d8..cfa02fc 100644 --- a/src/render/pbr.c +++ b/src/render/pbr.c @@ -1,4 +1,5 @@ #include "pbr.h" +#include "animation.h" #include "camera.h" #include "core.h" #include "file.h" @@ -24,6 +25,12 @@ GPU_Renderpass* PBR_RPassCreate() { } void PBR_PipelinesCreate(PBR_Storage* storage, GPU_Renderpass* rpass) { + // Common shader bindings + ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); + ShaderDataLayout model_data = Binding_Model_GetLayout(NULL); + ShaderDataLayout material_data = PBRMaterial_GetLayout(NULL); + ShaderDataLayout lights_data = Binding_Lights_GetLayout(NULL); + // Static { const char* vert_path = "assets/shaders/static_geometry.vert"; @@ -31,11 +38,6 @@ void PBR_PipelinesCreate(PBR_Storage* storage, GPU_Renderpass* rpass) { char* vert_shader = string_from_file(vert_path); char* frag_shader = string_from_file(frag_path); - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - ShaderDataLayout model_data = Binding_Model_GetLayout(NULL); - ShaderDataLayout material_data = PBRMaterial_GetLayout(NULL); - ShaderDataLayout lights_data = Binding_Lights_GetLayout(NULL); - GraphicsPipelineDesc desc = { .debug_name = "PBR (Static) Pipeline", .vertex_desc = static_3d_vertex_description(), @@ -60,14 +62,11 @@ void PBR_PipelinesCreate(PBR_Storage* storage, GPU_Renderpass* rpass) { char* vert_shader = string_from_file(vert_path); char* frag_shader = string_from_file(frag_path); - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - ShaderDataLayout model_data = Binding_Model_GetLayout(NULL); - ShaderDataLayout material_data = PBRMaterial_GetLayout(NULL); - ShaderDataLayout lights_data = Binding_Lights_GetLayout(NULL); + ShaderDataLayout anim_uniform = AnimData_GetLayout(NULL); VertexDescription vertex_desc = { .debug_label = "Skinned vertices", .use_full_vertex_size = true }; - VertexDesc_AddAttr(&vertex_desc, "inPos", ATTR_F32x3); + VertexDesc_AddAttr(&vertex_desc, "inPosition", ATTR_F32x3); VertexDesc_AddAttr(&vertex_desc, "inNormal", ATTR_F32x3); VertexDesc_AddAttr(&vertex_desc, "inTexCoords", ATTR_F32x2); VertexDesc_AddAttr(&vertex_desc, "inBoneIndices", ATTR_I32x4); @@ -76,8 +75,8 @@ void PBR_PipelinesCreate(PBR_Storage* storage, GPU_Renderpass* rpass) { GraphicsPipelineDesc desc = { .debug_name = "PBR (Skinned) Pipeline", .vertex_desc = vertex_desc, - .data_layouts = { camera_data, model_data, material_data, lights_data }, - .data_layouts_count = 4, + .data_layouts = { camera_data, model_data, material_data, lights_data, anim_uniform }, + .data_layouts_count = 5, .vs = { .debug_name = "PBR (textured) Vertex Shader", .filepath = str8(vert_path), .code = vert_shader }, @@ -102,7 +101,9 @@ void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_te GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); GPU_CmdEncoder_BeginRender(enc, storage->pbr_pass); - GPU_EncodeBindPipeline(enc, storage->pbr_static_pipeline); + + // TEMP: only do skinned + GPU_EncodeBindPipeline(enc, storage->pbr_skinned_pipeline); // Feed shader data Mat4 view, proj; @@ -143,6 +144,13 @@ void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_te Binding_Model model_data = { .model = renderable.affine }; GPU_EncodeBindShaderData(enc, 1, Binding_Model_GetLayout(&model_data)); + AnimDataUniform anim_data = {0}; + for (int i =0; i < 4; i++) { + anim_data.bone_matrices[i] = mat4_ident(); + } + GPU_EncodeBindShaderData(enc, 3, AnimData_GetLayout(&anim_data)); + // Calculate matrices here + // set buffers GPU_EncodeSetVertexBuffer(enc, mesh->vertex_buffer); GPU_EncodeSetIndexBuffer(enc, mesh->index_buffer); diff --git a/src/render/render_types.h b/src/render/render_types.h index 5e2b282..dd09896 100644 --- a/src/render/render_types.h +++ b/src/render/render_types.h @@ -43,6 +43,7 @@ typedef struct Mesh { Geometry geometry; // NULL means it has been freed CPU-side MaterialHandle material; bool is_skinned; // false = its static + Armature armature; bool is_uploaded; // has the data been uploaded to the GPU } Mesh; #ifndef TYPED_MESH_CONTAINERS @@ -96,8 +97,7 @@ typedef struct Model { size_t mesh_count; MaterialHandle* materials; size_t material_count; - Armature armature; - bool has_joints; + arena anim_arena; AnimationClip_darray* animations; } Model; #ifndef TYPED_MODEL_ARRAY @@ -135,6 +135,9 @@ typedef u32 RenderEntityFlags; typedef struct RenderEnt { MeshHandle mesh; MaterialHandle material; + AnimationClip animation_clip; + bool is_playing; + f32 t; Mat4 affine; // In the future this should be updated by the transform graph Bbox_3D bounding_box; RenderEntityFlags flags; diff --git a/src/resources/gltf.c b/src/resources/gltf.c index f788043..c5f1fd1 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -119,11 +119,11 @@ void load_texcoord_components(Vec2_darray* texcoords, cgltf_accessor* accessor) } } -void load_joint_index_components(Vec4u_darray* joint_indices, cgltf_accessor* accessor) { +void load_joint_index_components(Vec4i_darray* joint_indices, cgltf_accessor* accessor) { TRACE("Load joint indices from accessor"); CASSERT(accessor->component_type == cgltf_component_type_r_16u); CASSERT_MSG(accessor->type == cgltf_type_vec4, "Joint indices should be a vec4"); - Vec4u tmp_joint_index; + Vec4i tmp_joint_index; Vec4 joints_as_floats; for (cgltf_size v = 0; v < accessor->count; ++v) { cgltf_accessor_read_float(accessor, v, &joints_as_floats.x, 4); @@ -133,7 +133,7 @@ void load_joint_index_components(Vec4u_darray* joint_indices, cgltf_accessor* ac tmp_joint_index.w = (u32)joints_as_floats.w; printf("Joints affecting vertex %d : %d %d %d %d\n", v, tmp_joint_index.x, tmp_joint_index.y, tmp_joint_index.z, tmp_joint_index.w); - Vec4u_darray_push(joint_indices, tmp_joint_index); + Vec4i_darray_push(joint_indices, tmp_joint_index); } } @@ -168,6 +168,7 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel // --- Skin size_t num_skins = data->skins_count; bool is_skinned = false; + Armature main_skeleton = {0}; if (num_skins == 1) { is_skinned = true; } else if (num_skins > 1) { @@ -218,9 +219,9 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel 16); Joint_darray_push(armature.joints, joint_i); } - - out_model->armature = armature; - out_model->has_joints = true; + main_skeleton = armature; + // out_model->armature = armature; + // out_model->has_joints = true; } // --- Materials @@ -335,6 +336,7 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel Mesh m = Mesh_Create(geometry, false); if (is_skinned) { m.is_skinned = true; + m.armature = main_skeleton; } Mesh_darray_push(tmp_meshes, m); @@ -356,7 +358,8 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel if (!out_model->animations) { out_model->animations = AnimationClip_darray_new(num_animations); } - arena* arena = &out_model->armature.arena; + out_model->anim_arena = arena_create(malloc(MB(1)), MB(1)); + arena* arena = &out_model->anim_arena; for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { cgltf_animation animation = data->animations[anim_idx]; @@ -395,12 +398,10 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel } sampler->current_index = 0; - // printf("1 %d index\n", sampler->current_index); sampler->animation.interpolation = INTERPOLATION_LINEAR; // NOTE: hardcoded for now // Keyframe times size_t n_frames = channel.sampler->input->count; - assert(channel.sampler->input->component_type == cgltf_component_type_r_32f); CASSERT_MSG(channel.sampler->input->component_type == cgltf_component_type_r_32f, "Expected animation sampler input component to be type f32"); f32* times = arena_alloc(arena, n_frames * sizeof(f32)); @@ -408,9 +409,6 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel sampler->animation.timestamps = times; cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames); - // assert_path_type_matches_component_type(channel.target_path, - // channel.sampler->output); - // Keyframe values size_t n_values = channel.sampler->output->count; CASSERT_MSG(n_frames == n_values, "keyframe times = keyframe values"); @@ -451,8 +449,8 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel sampler->max = channel.sampler->input->max[0]; *target_property = sampler; - printf("%d timestamps\n", sampler->animation.n_timestamps); - printf("%d index\n", sampler->current_index); + printf("%d timestamps between %f and %f\n", sampler->animation.n_timestamps, sampler->min, + sampler->max); } AnimationClip_darray_push(out_model->animations, clip); |