From e5495790aeba905505152ad3b6690f459a44df03 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:28:24 +1100 Subject: close. --- examples/gltf_loading/ex_gltf_loading.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'examples/gltf_loading') diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c index 867ddb2..1d279eb 100644 --- a/examples/gltf_loading/ex_gltf_loading.c +++ b/examples/gltf_loading/ex_gltf_loading.c @@ -1,8 +1,10 @@ #include +#include "animation.h" #include "camera.h" #include "core.h" #include "loaders.h" +#include "log.h" #include "maths.h" #include "maths_types.h" #include "render.h" @@ -54,6 +56,9 @@ int main() { scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); + animation_clip track = cube->animations->data[0]; + f32 total_time = 0.0; + while (!glfwWindowShouldClose(core->renderer.window)) { currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; -- cgit v1.2.3-70-g09d2 From 6793c8317208bc2c8cb878554eeff166a418b2f2 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:09:18 +1100 Subject: storing joints and weights --- examples/gltf_loading/ex_gltf_loading.c | 2 -- src/renderer/render_types.h | 5 +++- src/resources/gltf.c | 42 ++++++++++++++++++++++++++------- 3 files changed, 38 insertions(+), 11 deletions(-) (limited to 'examples/gltf_loading') diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c index 1d279eb..7b69127 100644 --- a/examples/gltf_loading/ex_gltf_loading.c +++ b/examples/gltf_loading/ex_gltf_loading.c @@ -56,8 +56,6 @@ int main() { scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); - animation_clip track = cube->animations->data[0]; - f32 total_time = 0.0; while (!glfwWindowShouldClose(core->renderer.window)) { currentFrame = glfwGetTime(); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 377cdc7..e4d3127 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -128,11 +128,14 @@ typedef struct skinned_vertex { #ifndef TYPED_VERTEX_ARRAY KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" +KITC_DECL_TYPED_ARRAY(skinned_vertex) // creates "skinned_vertex_darray" #define TYPED_VERTEX_ARRAY #endif typedef struct mesh { - vertex_darray *vertices; + vertex_darray* vertices; + // skinned_vertex_darray* skinned_vertices; // only used if model needs it + // bool is_skinned; u32 vertex_size; /** size in bytes of each vertex including necessary padding */ bool has_indices; u32 *indices; diff --git a/src/resources/gltf.c b/src/resources/gltf.c index ae4fd48..7fbef3b 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -28,6 +28,7 @@ KITC_DECL_TYPED_ARRAY(vec3) KITC_DECL_TYPED_ARRAY(vec2) KITC_DECL_TYPED_ARRAY(u32) KITC_DECL_TYPED_ARRAY(vec4i) +KITC_DECL_TYPED_ARRAY(vec4) KITC_DECL_TYPED_ARRAY(face) bool model_load_gltf_str(const char *file_string, const char *filepath, str8 relative_path, @@ -84,7 +85,8 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel vec3_darray *tmp_normals = vec3_darray_new(1000); vec2_darray *tmp_uvs = vec2_darray_new(1000); face_darray *tmp_faces = face_darray_new(1000); - vec4i_darray *tmp_joints = face_darray_new(1000); + vec4i_darray *tmp_joints = vec4i_darray_new(1000); + vec4_darray *tmp_weights = vec4_darray_new(1000); cgltf_options options = { 0 }; cgltf_data *data = NULL; @@ -108,8 +110,8 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel return false; } - { - cgltf_skin* gltf_skin = data->skins; + if (is_skinned) { + cgltf_skin *gltf_skin = data->skins; TRACE("loading skin %s", gltf_skin->name); } @@ -157,7 +159,7 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel for (size_t m = 0; m < num_meshes; m++) { cgltf_primitive primitive = data->meshes[m].primitives[0]; DEBUG("Found %d attributes", primitive.attributes_count); - DEBUG("Number of this primitive %d", pri) + // DEBUG("Number of this primitive %d", primitive.) for (int a = 0; a < data->meshes[m].primitives[0].attributes_count; a++) { cgltf_attribute attribute = data->meshes[m].primitives[0].attributes[a]; @@ -168,6 +170,8 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel assert(accessor->component_type == cgltf_component_type_r_32f); // CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex positions should be a vec3"); + TRACE("Loading %d vec3 components", accessor->count); + for (cgltf_size v = 0; v < accessor->count; ++v) { vec3 pos; cgltf_accessor_read_float(accessor, v, &pos.x, 3); @@ -202,19 +206,41 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel vec2_darray_push(tmp_uvs, tex); } } else if (attribute.type == cgltf_attribute_type_joints) { + TRACE("Load joint indices from accessor"); cgltf_accessor *accessor = attribute.data; assert(accessor->component_type == cgltf_component_type_r_16u); - u16 joint_indices[4]; - // ERROR("Access count %d", accessor.); + assert(accessor->type == cgltf_type_vec4); + vec4i joint_indices; + vec4 joints_as_floats; + for (cgltf_size v = 0; v < accessor->count; ++v) { + cgltf_accessor_read_float(accessor, v, &joints_as_floats.x, 4); + joint_indices.x = (u32)joints_as_floats.x; + joint_indices.y = (u32)joints_as_floats.y; + joint_indices.z = (u32)joints_as_floats.z; + joint_indices.w = (u32)joints_as_floats.w; + printf("Joints affecting %d %d %d %d\n", joint_indices.x, joint_indices.y, + joint_indices.z, joint_indices.w); + vec4i_darray_push(tmp_joints, joint_indices); + } + + } else if (attribute.type == cgltf_attribute_type_weights) { + TRACE("Load joint weights from accessor"); + cgltf_accessor *accessor = attribute.data; + assert(accessor->component_type == cgltf_component_type_r_32f); + assert(accessor->type == cgltf_type_vec4); + for (cgltf_size v = 0; v < accessor->count; ++v) { - // cgltf_accessor_read_uint(accessor, v, cgltf_uint *out, cgltf_size element_size) + vec4 weights; + cgltf_accessor_read_float(accessor, v, &weights.x, 4); + printf("Weights affecting %f %f %f %f\n", weights.x, weights.y, weights.z, weights.w); + vec4_darray_push(tmp_weights, weights); } } else { WARN("Unhandled cgltf_attribute_type: %s. skipping..", attribute.name); } } - mesh mesh; + mesh mesh = {0}; mesh.vertices = vertex_darray_new(10); cgltf_accessor *indices = primitive.indices; -- cgit v1.2.3-70-g09d2 From d9f9479694d8a4d74822a876516282329db5ea3d Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 6 Apr 2024 22:24:52 +1100 Subject: separate pipeline for skinned meshes --- assets/shaders/skinned.vert | 47 ++++++++ examples/gltf_loading/ex_gltf_loading.c | 1 - examples/skinned_animation/ex_skinned_animation.c | 4 +- src/animation.h | 6 + src/renderer/render.c | 134 +++++++++++++++++----- src/renderer/render.h | 2 + src/renderer/render_types.h | 18 +-- src/resources/gltf.c | 67 +++++++++-- 8 files changed, 234 insertions(+), 45 deletions(-) create mode 100644 assets/shaders/skinned.vert (limited to 'examples/gltf_loading') diff --git a/assets/shaders/skinned.vert b/assets/shaders/skinned.vert new file mode 100644 index 0000000..3d0c2cd --- /dev/null +++ b/assets/shaders/skinned.vert @@ -0,0 +1,47 @@ +#version 410 core +// Inputs +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inTexCoords; +layout (location = 3) in ivec4 inBoneIndices; +layout (location = 4) in vec4 inWeights; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +uniform mat4 lightSpaceMatrix; + +const int MAX_BONES = 100; +const int MAX_BONE_INFLUENCES = 4; +uniform mat4 finalBoneMatrices[MAX_BONES]; + +// Output +out VS_OUT { + vec3 FragPos; + vec3 Normal; + vec2 TexCoords; + vec4 FragPosLightSpace; +} vs_out; + +void main() { + vec4 totalPosition = vec4(0.0f); + for(int i = 0 ; i < MAX_BONE_INFLUENCES ; i++) { + if(inBoneIndices[i] == -1) + continue; + if(inBoneIndices[i] >=MAX_BONES) + { + totalPosition = vec4(inPos,1.0f); + break; + } + vec4 localPosition = finalBoneMatrices[inBoneIndices[i]] * vec4(inPos,1.0f); + totalPosition += localPosition * inWeights[i]; + vec3 localNormal = mat3(finalBoneMatrices[inBoneIndices[i]]) * inNormal; + vs_out.Normal = localNormal; + } + + vs_out.FragPos = vec3(model * vec4(inPos, 1.0)); + // vs_out.Normal = inNormal; + vs_out.TexCoords = inTexCoords; + vs_out.FragPosLightSpace = lightSpaceMatrix * vec4(vs_out.FragPos, 1.0); + gl_Position = projection * view * model * totalPosition; +} \ No newline at end of file diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c index 7b69127..5d53e78 100644 --- a/examples/gltf_loading/ex_gltf_loading.c +++ b/examples/gltf_loading/ex_gltf_loading.c @@ -56,7 +56,6 @@ int main() { scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); - while (!glfwWindowShouldClose(core->renderer.window)) { currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; diff --git a/examples/skinned_animation/ex_skinned_animation.c b/examples/skinned_animation/ex_skinned_animation.c index 9efffc6..3138256 100644 --- a/examples/skinned_animation/ex_skinned_animation.c +++ b/examples/skinned_animation/ex_skinned_animation.c @@ -37,7 +37,7 @@ int main() { scene our_scene = make_default_scene(); - vec3 cam_pos = vec3_create(5, 5, 5); + vec3 cam_pos = vec3_create(0, 5, 8); game_state game = { .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)), .camera_euler = vec3_create(90, 0, 0), @@ -86,7 +86,7 @@ int main() { quat rot = quat_ident(); transform tf = transform_create(VEC3_ZERO, rot, 1.0); - draw_model(&core->renderer, &game.camera, cube, tf, &our_scene); + draw_skinned_model(&core->renderer, &game.camera, cube, tf, &our_scene); // gfx_backend_draw_frame(&core->renderer, &game.camera, model, NULL); diff --git a/src/animation.h b/src/animation.h index 81e150a..18d3ba9 100644 --- a/src/animation.h +++ b/src/animation.h @@ -28,6 +28,12 @@ typedef struct keyframes { size_t count; } keyframes; +typedef struct joint { + char* name; // optional + transform transform_components; + mat4 local_transform; +} joint; + typedef struct animation_spline { f32* timestamps; size_t n_timestamps; diff --git a/src/renderer/render.c b/src/renderer/render.c index 806979d..e420043 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,3 +1,7 @@ +#include +#include +#include +#include "maths_types.h" #include "mem.h" #define STB_IMAGE_IMPLEMENTATION #include @@ -59,6 +63,9 @@ bool renderer_init(renderer* ren) { ren->blinn_phong = shader_create_separate("assets/shaders/blinn_phong.vert", "assets/shaders/blinn_phong.frag"); + ren->skinned = + shader_create_separate("assets/shaders/skinned.vert", "assets/shaders/blinn_phong.frag"); + default_material_init(); return true; @@ -158,6 +165,59 @@ void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* vie draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); } +void draw_skinned_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, + mat4* proj) { + shader lighting_shader = ren->skinned; + + // bind buffer + bind_mesh_vertex_buffer(ren->backend_state, mesh); + + // bind textures + bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0 + bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 + uniform_f32(lighting_shader.program_id, "material.shininess", 32.); + + // upload model transform + mat4 trans = mat4_translation(tf.position); + mat4 rot = mat4_rotation(tf.rotation); + mat4 scale = mat4_scale(tf.scale); + mat4 model_tf = mat4_mult(trans, mat4_mult(rot, scale)); + + uniform_mat4f(lighting_shader.program_id, "model", &model_tf); + // upload view & projection matrices + uniform_mat4f(lighting_shader.program_id, "view", view); + uniform_mat4f(lighting_shader.program_id, "projection", proj); + + // draw triangles + u32 num_vertices = vertex_darray_len(mesh->vertices); + draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); +} + +void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene) { + mat4 view; + mat4 proj; + camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + + set_shader(ren->skinned); + + // set camera uniform + uniform_vec3f(ren->blinn_phong.program_id, "viewPos", &cam->position); + // set light uniforms + dir_light_upload_uniforms(ren->blinn_phong, &scene->dir_light); + for (int i = 0; i < scene->n_point_lights; i++) { + point_light_upload_uniforms(ren->blinn_phong, &scene->point_lights[i], '0' + i); + } + + for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) { + mesh* m = &model->meshes->data[i]; + if (vertex_darray_len(m->vertices) == 0) { + continue; + } + material* mat = &model->materials->data[m->material_index]; + draw_skinned_mesh(ren, m, tf, mat, &view, &proj); + } +} + void model_upload_meshes(renderer* ren, model* model) { INFO("Upload mesh vertex data to GPU for model %s", model->name); @@ -173,6 +233,7 @@ void model_upload_meshes(renderer* ren, model* model) { // upload each mesh to the GPU for (int mesh_i = 0; mesh_i < num_meshes; mesh_i++) { + mesh mesh = model->meshes->data[mesh_i]; model->meshes->data[mesh_i].vao = VAOs[mesh_i]; model->meshes->data[mesh_i].vbo = VBOs[mesh_i]; // 3. bind buffers @@ -185,34 +246,51 @@ void model_upload_meshes(renderer* ren, model* model) { // TODO: convert this garbage into a function f32 verts[num_vertices * 8]; // for each face - for (int i = 0; i < (num_vertices / 3); i++) { - // for each vert in face - for (int j = 0; j < 3; j++) { - size_t stride = (i * 24) + j * 8; - // printf("i: %d, stride: %ld, loc %d\n", i, stride, i * 3 + j); - vertex vert = model->meshes->data[mesh_i].vertices->data[i]; - // printf("pos %f %f %f\n", vert.position.x, vert.position.y, vert.position.z); - // printf("norm %f %f %f\n", vert.normal.x, vert.normal.y, vert.normal.z); - // printf("tex %f %f\n", vert.uv.x, vert.uv.y); - verts[stride + 0] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.x; - verts[stride + 1] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.y; - verts[stride + 2] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.z; - verts[stride + 3] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.x; - verts[stride + 4] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.y; - verts[stride + 5] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.z; - verts[stride + 6] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].uv.x; - verts[stride + 7] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].uv.y; - } + // for (int i = 0; i < (num_vertices / 3); i++) { + // // for each vert in face + // for (int j = 0; j < 3; j++) { + // size_t stride = (i * 24) + j * 8; + // // printf("i: %d, stride: %ld, loc %d\n", i, stride, i * 3 + j); + // vertex vert = model->meshes->data[mesh_i].vertices->data[i]; + // // printf("pos %f %f %f\n", vert.position.x, vert.position.y, vert.position.z); + // // printf("norm %f %f %f\n", vert.normal.x, vert.normal.y, vert.normal.z); + // // printf("tex %f %f\n", vert.uv.x, vert.uv.y); + // verts[stride + 0] = + // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.x; + // verts[stride + 1] = + // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.y; + // verts[stride + 2] = + // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.z; + // verts[stride + 3] = + // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.x; + // verts[stride + 4] = + // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.y; + // verts[stride + 5] = + // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.z; + // verts[stride + 6] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + + // j].uv.x; verts[stride + 7] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + // + j].uv.y; + // } + // } + size_t vertex_size = mesh.is_skinned + ? sizeof(vec3) * 2 + sizeof(vec2) + sizeof(u32) * 4 + sizeof(vec4) + : sizeof(vec3) * 2 + sizeof(vec2); + if (!mesh.is_skinned) { + printf("sizeof(vertex) -> %ld, vertex_size -> %ld\n", sizeof(vertex), vertex_size); + assert(vertex_size == sizeof(vertex)); + } + size_t buffer_size = vertex_size * num_vertices; + u8* bytes = malloc(buffer_size); + + for (int i = 0; i < num_vertices; i++) { + u8* p = bytes + vertex_size * i; + u8* bone_data_offset = p + sizeof(u32) * 4 + sizeof(vec4); + memcpy(p, &mesh.vertices->data[i], sizeof(vertex)); + memcpy(bone_data_offset, &mesh.vertex_bone_data->data[i], sizeof(vertex_bone_data)); } // 4. upload data - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, buffer_size, bytes, GL_STATIC_DRAW); // 5. cont. set mesh vertex layout glBindVertexArray(model->meshes->data[mesh_i].vao); @@ -225,6 +303,10 @@ void model_upload_meshes(renderer* ren, model* model) { // tex coords glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); + + // skinning (optional) + if (mesh.is_skinned) { + } } INFO("Uploaded %d submeshes with a total of %d vertices\n", num_meshes, total_verts); @@ -242,7 +324,7 @@ texture texture_data_load(const char* path, bool invert_y) { stbi_set_flip_vertically_on_load(invert_y); #pragma GCC diagnostic ignored "-Wpointer-sign" - char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); + char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); if (data) { DEBUG("loaded texture: %s", path); } else { diff --git a/src/renderer/render.h b/src/renderer/render.h index f0118b6..ba2cbdc 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -35,6 +35,8 @@ void model_upload_meshes(renderer* ren, model* model); void draw_model(renderer* ren, camera* camera, model* model, transform tf, scene* scene); void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, mat4* proj); +void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene); + void model_destroy(model* model); // --- diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index e4d3127..61571e1 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -46,6 +46,7 @@ typedef struct renderer { renderer_config config; // shaders shader blinn_phong; + shader skinned; } renderer; // --- Lighting & Materials @@ -118,24 +119,25 @@ typedef struct vertex { vec2 uv; } vertex; -typedef struct skinned_vertex { - vec3 position; - vec3 normal; - vec2 uv; +typedef struct vertex_bone_data { vec4i joints; /** @brief 4 indices of joints that influence vectors position */ vec4 weights; /** @brief weight (0,1) of each joint */ -} skinned_vertex; +} vertex_bone_data; +#include "animation.h" #ifndef TYPED_VERTEX_ARRAY KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" -KITC_DECL_TYPED_ARRAY(skinned_vertex) // creates "skinned_vertex_darray" +KITC_DECL_TYPED_ARRAY(vertex_bone_data) // creates "skinned_vertex_darray" +KITC_DECL_TYPED_ARRAY(joint) #define TYPED_VERTEX_ARRAY #endif + typedef struct mesh { vertex_darray* vertices; - // skinned_vertex_darray* skinned_vertices; // only used if model needs it - // bool is_skinned; + vertex_bone_data_darray* vertex_bone_data; // only used if model needs it + joint_darray* bones; + bool is_skinned; u32 vertex_size; /** size in bytes of each vertex including necessary padding */ bool has_indices; u32 *indices; diff --git a/src/resources/gltf.c b/src/resources/gltf.c index 7fbef3b..c7c1f55 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -7,6 +7,7 @@ #include "file.h" #include "loaders.h" #include "log.h" +#include "maths.h" #include "maths_types.h" #include "mem.h" #include "path.h" @@ -30,6 +31,7 @@ KITC_DECL_TYPED_ARRAY(u32) KITC_DECL_TYPED_ARRAY(vec4i) KITC_DECL_TYPED_ARRAY(vec4) KITC_DECL_TYPED_ARRAY(face) +// KITC_DECL_TYPED_ARRAY(joint) bool model_load_gltf_str(const char *file_string, const char *filepath, str8 relative_path, model *out_model, bool invert_textures_y); @@ -84,9 +86,9 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel vec3_darray *tmp_positions = vec3_darray_new(1000); vec3_darray *tmp_normals = vec3_darray_new(1000); vec2_darray *tmp_uvs = vec2_darray_new(1000); - face_darray *tmp_faces = face_darray_new(1000); - vec4i_darray *tmp_joints = vec4i_darray_new(1000); + vec4i_darray *tmp_joint_indices = vec4i_darray_new(1000); vec4_darray *tmp_weights = vec4_darray_new(1000); + joint_darray *tmp_joints = joint_darray_new(256); cgltf_options options = { 0 }; cgltf_data *data = NULL; @@ -112,7 +114,33 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel if (is_skinned) { cgltf_skin *gltf_skin = data->skins; - TRACE("loading skin %s", gltf_skin->name); + DEBUG("loading skin %s", gltf_skin->name); + size_t num_joints = gltf_skin->joints_count; + DEBUG("# Joints %d", num_joints); + + // for each one we'll spit out a joint + for (size_t i = 0; i < num_joints; i++) { + cgltf_node *joint_node = gltf_skin->joints[i]; + + joint joint_i = { .name = "testjoint" }; + if (joint_node->children_count > 0 && !joint_node->has_translation && + !joint_node->has_rotation) { + WARN("joint Node with index %d is the root node", i); + joint_i.transform_components = TRANSFORM_DEFAULT; + } else { + TRACE("Storing joint transform"); + joint_i.transform_components = TRANSFORM_DEFAULT; + if (joint_node->has_translation) { + memcpy(&joint_i.transform_components.position, &joint_node->translation, 3 * sizeof(f32)); + } + if (joint_node->has_rotation) { + memcpy(&joint_i.transform_components.rotation, &joint_node->rotation, 4 * sizeof(f32)); + } + // TODO: support scaling as vec instead of float + } + joint_i.local_transform = transform_to_mat(&joint_i.transform_components); + joint_darray_push(tmp_joints, joint_i); + } } // --- Materials @@ -218,9 +246,9 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel joint_indices.y = (u32)joints_as_floats.y; joint_indices.z = (u32)joints_as_floats.z; joint_indices.w = (u32)joints_as_floats.w; - printf("Joints affecting %d %d %d %d\n", joint_indices.x, joint_indices.y, - joint_indices.z, joint_indices.w); - vec4i_darray_push(tmp_joints, joint_indices); + // printf("Joints affecting %d %d %d %d\n", joint_indices.x, joint_indices.y, + // joint_indices.z, joint_indices.w); + vec4i_darray_push(tmp_joint_indices, joint_indices); } } else if (attribute.type == cgltf_attribute_type_weights) { @@ -232,7 +260,7 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel for (cgltf_size v = 0; v < accessor->count; ++v) { vec4 weights; cgltf_accessor_read_float(accessor, v, &weights.x, 4); - printf("Weights affecting %f %f %f %f\n", weights.x, weights.y, weights.z, weights.w); + // printf("Weights affecting %f %f %f %f\n", weights.x, weights.y, weights.z, weights.w); vec4_darray_push(tmp_weights, weights); } } else { @@ -240,7 +268,7 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel } } - mesh mesh = {0}; + mesh mesh = { 0 }; mesh.vertices = vertex_darray_new(10); cgltf_accessor *indices = primitive.indices; @@ -282,7 +310,30 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel } } + if (is_skinned) { + mesh.vertex_bone_data = vertex_bone_data_darray_new(tmp_joint_indices->len); + mesh.bones = joint_darray_new(tmp_joints->len); + for (int i = 0; i < tmp_joint_indices->len; i++) { + vertex_bone_data data; + data.joints = tmp_joint_indices->data[i]; + data.weights =tmp_weights->data[i]; + vertex_bone_data_darray_push(mesh.vertex_bone_data, data); + } + for (int i = 0; i < tmp_joints->len; i++) { + joint data = tmp_joints->data[i]; + joint_darray_push(mesh.bones, data); + } + } + mesh_darray_push(out_model->meshes, mesh); + + // clear data for each mesh + vec3_darray_clear(tmp_positions); + vec3_darray_clear(tmp_normals); + vec2_darray_free(tmp_uvs); + vec4i_darray_clear(tmp_joint_indices); + vec4_darray_clear(tmp_weights); + joint_darray_clear(tmp_joints); } for (int i = 0; i < out_model->meshes->len; i++) { -- cgit v1.2.3-70-g09d2 From 1fc69f183bf8f105048b9d47e096ccd402107bbb Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 21 Apr 2024 12:34:00 +1000 Subject: misc cleanup --- assets/shaders/blinn_phong.frag | 2 +- assets/shaders/blinn_phong.vert | 2 + examples/gltf_loading/ex_gltf_loading.c | 2 +- examples/obj_loading/ex_obj_loading.c | 2 +- src/animation.h | 2 +- src/maths/maths.h | 65 ++++++++++++++++----------------- src/renderer/render.c | 31 +--------------- src/renderer/render_types.h | 9 ++--- 8 files changed, 42 insertions(+), 73 deletions(-) (limited to 'examples/gltf_loading') diff --git a/assets/shaders/blinn_phong.frag b/assets/shaders/blinn_phong.frag index adcc53e..a0ba905 100644 --- a/assets/shaders/blinn_phong.frag +++ b/assets/shaders/blinn_phong.frag @@ -56,7 +56,7 @@ void main() { result += CalcPointLight(pointLights[i], norm, fs_in.FragPos, viewDir); } - // FragColor = vec4(result, 1.0); +// FragColor = vec4(result, 1.0); FragColor = fs_in.Color + 0.5; } diff --git a/assets/shaders/blinn_phong.vert b/assets/shaders/blinn_phong.vert index 6028178..06dc5e7 100644 --- a/assets/shaders/blinn_phong.vert +++ b/assets/shaders/blinn_phong.vert @@ -15,6 +15,7 @@ out VS_OUT { vec3 Normal; vec2 TexCoords; vec4 FragPosLightSpace; + vec4 Color; } vs_out; void main() { @@ -22,5 +23,6 @@ void main() { vs_out.Normal = inNormal; vs_out.TexCoords = inTexCoords; vs_out.FragPosLightSpace = lightSpaceMatrix * vec4(vs_out.FragPos, 1.0); + vs_out.Color = vec4(1.0); gl_Position = projection * view * model * vec4(inPos, 1.0); } \ No newline at end of file diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c index b181426..900cf1b 100644 --- a/examples/gltf_loading/ex_gltf_loading.c +++ b/examples/gltf_loading/ex_gltf_loading.c @@ -56,7 +56,7 @@ int main() { scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); - while (!glfwWindowShouldClose(core->renderer.window)) { + while (!should_exit(core)) { currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; diff --git a/examples/obj_loading/ex_obj_loading.c b/examples/obj_loading/ex_obj_loading.c index aaed2a0..906816b 100644 --- a/examples/obj_loading/ex_obj_loading.c +++ b/examples/obj_loading/ex_obj_loading.c @@ -55,7 +55,7 @@ int main() { memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); // --- Enter Main loop - while (!glfwWindowShouldClose(core->renderer.window)) { + while (!should_exit(core)) { input_update(&core->input); threadpool_process_results(&core->threadpool, 1); diff --git a/src/animation.h b/src/animation.h index 9d5d03b..5462e65 100644 --- a/src/animation.h +++ b/src/animation.h @@ -29,7 +29,7 @@ typedef struct keyframes { } keyframes; typedef struct joint { - char* name; // optional + char* name; // optional transform transform_components; mat4 inverse_bind_matrix; mat4 local_transform; diff --git a/src/maths/maths.h b/src/maths/maths.h index 8e48435..e0d39d7 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -91,45 +91,42 @@ static inline quat quat_slerp(quat a, quat b, f32 percentage) { quat q1 = quat_normalise(b); // Compute the cosine of the angle between the two vectors. - f32 dot = quat_dot(q0, q1); - - // If the dot product is negative, slerp won't take - // the shorter path. Note that v1 and -v1 are equivalent when - // the negation is applied to all four components. Fix by - // reversing one quaternion. - if (dot < 0.0f) { - q1.x = -q1.x; - q1.y = -q1.y; - q1.z = -q1.z; - q1.w = -q1.w; - dot = -dot; - } + f32 dot = quat_dot(q0, q1); + + // If the dot product is negative, slerp won't take + // the shorter path. Note that v1 and -v1 are equivalent when + // the negation is applied to all four components. Fix by + // reversing one quaternion. + if (dot < 0.0f) { + q1.x = -q1.x; + q1.y = -q1.y; + q1.z = -q1.z; + q1.w = -q1.w; + dot = -dot; + } - const f32 DOT_THRESHOLD = 0.9995f; - if (dot > DOT_THRESHOLD) { - // If the inputs are too close for comfort, linearly interpolate - // and normalize the result. - out_quaternion = (quat){q0.x + ((q1.x - q0.x) * percentage), - q0.y + ((q1.y - q0.y) * percentage), - q0.z + ((q1.z - q0.z) * percentage), - q0.w + ((q1.w - q0.w) * percentage)}; + const f32 DOT_THRESHOLD = 0.9995f; + if (dot > DOT_THRESHOLD) { + // If the inputs are too close for comfort, linearly interpolate + // and normalize the result. + out_quaternion = + (quat){ q0.x + ((q1.x - q0.x) * percentage), q0.y + ((q1.y - q0.y) * percentage), + q0.z + ((q1.z - q0.z) * percentage), q0.w + ((q1.w - q0.w) * percentage) }; - return quat_normalise(out_quaternion); - } + return quat_normalise(out_quaternion); + } - // Since dot is in range [0, DOT_THRESHOLD], acos is safe - f32 theta_0 = cos(dot); // theta_0 = angle between input vectors - f32 theta = theta_0 * percentage; // theta = angle between v0 and result - f32 sin_theta = sin(theta); // compute this value only once - f32 sin_theta_0 = sin(theta_0); // compute this value only once + // Since dot is in range [0, DOT_THRESHOLD], acos is safe + f32 theta_0 = cos(dot); // theta_0 = angle between input vectors + f32 theta = theta_0 * percentage; // theta = angle between v0 and result + f32 sin_theta = sin(theta); // compute this value only once + f32 sin_theta_0 = sin(theta_0); // compute this value only once - f32 s0 = - cos(theta) - - dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0) - f32 s1 = sin_theta / sin_theta_0; + f32 s0 = cos(theta) - dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0) + f32 s1 = sin_theta / sin_theta_0; - return (quat){(q0.x * s0) + (q1.x * s1), (q0.y * s0) + (q1.y * s1), - (q0.z * s0) + (q1.z * s1), (q0.w * s0) + (q1.w * s1)}; + return (quat){ (q0.x * s0) + (q1.x * s1), (q0.y * s0) + (q1.y * s1), (q0.z * s0) + (q1.z * s1), + (q0.w * s0) + (q1.w * s1) }; } // --- Matrix Implementations diff --git a/src/renderer/render.c b/src/renderer/render.c index b688613..b1e2a46 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -176,7 +176,6 @@ void draw_mesh(renderer* ren, mesh* mesh, mat4* model_tf, material* mat, mat4* v bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 uniform_f32(lighting_shader.program_id, "material.shininess", 32.); - // upload model, view, and projection matrices uniform_mat4f(lighting_shader.program_id, "model", model_tf); uniform_mat4f(lighting_shader.program_id, "view", view); @@ -295,35 +294,6 @@ void model_upload_meshes(renderer* ren, model* model) { // TRACE("Uploading vertex array data: %d verts", num_vertices); total_verts += num_vertices; - // TODO: convert this garbage into a function - f32 verts[num_vertices * 8]; - // for each face - // for (int i = 0; i < (num_vertices / 3); i++) { - // // for each vert in face - // for (int j = 0; j < 3; j++) { - // size_t stride = (i * 24) + j * 8; - // // printf("i: %d, stride: %ld, loc %d\n", i, stride, i * 3 + j); - // vertex vert = model->meshes->data[mesh_i].vertices->data[i]; - // // printf("pos %f %f %f\n", vert.position.x, vert.position.y, vert.position.z); - // // printf("norm %f %f %f\n", vert.normal.x, vert.normal.y, vert.normal.z); - // // printf("tex %f %f\n", vert.uv.x, vert.uv.y); - // verts[stride + 0] = - // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.x; - // verts[stride + 1] = - // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.y; - // verts[stride + 2] = - // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.z; - // verts[stride + 3] = - // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.x; - // verts[stride + 4] = - // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.y; - // verts[stride + 5] = - // ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.z; - // verts[stride + 6] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + - // j].uv.x; verts[stride + 7] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 - // + j].uv.y; - // } - // } size_t static_vertex_size = 2 * sizeof(vec3) + sizeof(vec2); size_t skinned_vertex_size = 2 * sizeof(vec3) + sizeof(vec2) + 4 * sizeof(u32) + sizeof(vec4); size_t vertex_size = mesh.is_skinned ? skinned_vertex_size : static_vertex_size; @@ -335,6 +305,7 @@ void model_upload_meshes(renderer* ren, model* model) { assert(vertex_size == sizeof(vertex)); assert(vertex_size == 8 * sizeof(float)); } + size_t buffer_size = vertex_size * num_vertices; u8* bytes = malloc(buffer_size); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 6e69708..423b58f 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -127,17 +127,16 @@ typedef struct vertex_bone_data { #include "animation.h" #ifndef TYPED_VERTEX_ARRAY -KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" +KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" KITC_DECL_TYPED_ARRAY(vertex_bone_data) // creates "skinned_vertex_darray" KITC_DECL_TYPED_ARRAY(joint) #define TYPED_VERTEX_ARRAY #endif - typedef struct mesh { - vertex_darray* vertices; - vertex_bone_data_darray* vertex_bone_data; // only used if model needs it - joint_darray* bones; + vertex_darray *vertices; + vertex_bone_data_darray *vertex_bone_data; // only used if model needs it + joint_darray *bones; bool is_skinned; u32 vertex_size; /** size in bytes of each vertex including necessary padding */ bool has_indices; -- cgit v1.2.3-70-g09d2