From dbbdcf4be06c05f60798b322890c88b79d802bd8 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 11 Feb 2023 09:13:18 -0800 Subject: Create default material for meshes that do not specify one. --- gfx/src/util/scene.c | 101 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 31 deletions(-) diff --git a/gfx/src/util/scene.c b/gfx/src/util/scene.c index 49e661d..6f34922 100644 --- a/gfx/src/util/scene.c +++ b/gfx/src/util/scene.c @@ -803,13 +803,44 @@ static bool load_materials( return true; } +/// Create a default material for meshes that do not have a material. +static Material* make_default_material() { + MaterialDesc desc = (MaterialDesc){0}; + + assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); + desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ + .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), + .type = UniformVec4, + .value.vec4 = vec4_make(1, 1, 1, 1)}; + + assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); + desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ + .name = sstring_make(UNIFORM_METALLIC_FACTOR), + .type = UniformFloat, + .value.scalar = 0}; + + assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); + desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ + .name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), + .type = UniformFloat, + .value.scalar = 1}; + + assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); + desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ + .name = sstring_make(UNIFORM_EMISSIVE_FACTOR), + .type = UniformVec3, + .value.vec3 = vec3_make(0, 0, 0)}; + + return gfx_make_material(&desc); +} + /// Load all meshes from the glTF scene. static bool load_meshes( const cgltf_data* data, Gfx* gfx, Buffer** buffers, Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, - cgltf_size num_tangent_buffers, Material** materials, ShaderProgram* shader, - size_t primitive_count, Geometry** geometries, Mesh** meshes, - SceneObject** scene_objects) { + cgltf_size num_tangent_buffers, Material** materials, + ShaderProgram* const shader, size_t primitive_count, Geometry** geometries, + Mesh** meshes, SceneObject** scene_objects) { // Walk through the mesh primitives to create Meshes. A GLTF mesh primitive // has a material (Mesh) and vertex data (Geometry). A GLTF mesh maps to // a SceneObject. @@ -852,16 +883,21 @@ static bool load_meshes( const cgltf_primitive* prim = &mesh->primitives[p]; const cgltf_material* mat = prim->material; - MeshPermutation perm = {0}; - perm.has_normal_map = mat->normal_texture.texture != 0; - perm.has_occlusion_map = mat->occlusion_texture.texture != 0; - perm.has_emissive_map = mat->emissive_texture.texture != 0; - // TODO: specular/glossiness and other material parameters. - if (mat->has_pbr_metallic_roughness) { - const cgltf_pbr_metallic_roughness* pbr = &mat->pbr_metallic_roughness; - perm.has_albedo_map = pbr->base_color_texture.texture != 0; - perm.has_metallic_roughness_map = - pbr->metallic_roughness_texture.texture != 0; + MeshPermutation perm = {0}; + if (mat) { + perm.has_normal_map = mat->normal_texture.texture != 0; + perm.has_occlusion_map = mat->occlusion_texture.texture != 0; + perm.has_emissive_map = mat->emissive_texture.texture != 0; + + if (mat->has_pbr_metallic_roughness) { + const cgltf_pbr_metallic_roughness* pbr = + &mat->pbr_metallic_roughness; + perm.has_albedo_map = pbr->base_color_texture.texture != 0; + perm.has_metallic_roughness_map = + pbr->metallic_roughness_texture.texture != 0; + } else { + // TODO: specular/glossiness and other material parameters. + } } GeometryDesc geometry_desc = { @@ -1034,36 +1070,39 @@ static bool load_meshes( CHECK_COUNT(weights.u16, uint16_t, 4); CHECK_COUNT(weights.floats, float, 4); - const cgltf_size material_index = prim->material - data->materials; - assert(material_index < data->materials_count); - Material* material = materials[material_index]; + Material* material = 0; + if (mat) { + const cgltf_size material_index = mat - data->materials; + assert(material_index < data->materials_count); + material = materials[material_index]; + } else { + // Create a default material for meshes that do not specify one. + material = make_default_material(); + } + assert(material); geometries[next_mesh] = gfx_make_geometry(render_backend, &geometry_desc); if (!geometries[next_mesh]) { return false; } - // If the user specifies a custom shader, use that instead. - // else TODO: Build a shader based on permutation. + // If the user specifies a custom shader, use that instead. Otherwise + // compile a shader based on the mesh's permutation. // - // TODO: We should cache shader permutations to re-use shader programs. - // Caching should not be done locally here because a caller may call - // gfx_load_scene() multiple times to load multiple scenes, and we want - // shader re-use across scenes too. + // Note that Gfx takes care of caching shaders and shader programs. // - // On the other hand, caching materials is not necessary since, provided - // they can share shaders, the renderer can check later whether uniforms - // have the same values. Also, changing uniforms is much faster than - // swapping shaders, so shader caching is the most important thing here. - if (!shader) { - shader = make_shader_permutation(render_backend, perm); - } - assert(shader); + // Caching materials could be useful, but, provided they can share + // shaders, the renderer can check later whether uniforms have the same + // values. Also, changing uniforms is much faster than swapping shaders, + // so shader caching is the most important thing here. + ShaderProgram* mesh_shader = + shader ? shader : make_shader_permutation(render_backend, perm); + assert(mesh_shader); meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){ .geometry = geometries[next_mesh], .material = material, - .shader = shader}); + .shader = mesh_shader}); if (!meshes[next_mesh]) { return false; -- cgit v1.2.3