diff options
-rw-r--r-- | gfx/src/util/scene.c | 101 |
1 files 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( | |||
803 | return true; | 803 | return true; |
804 | } | 804 | } |
805 | 805 | ||
806 | /// Create a default material for meshes that do not have a material. | ||
807 | static Material* make_default_material() { | ||
808 | MaterialDesc desc = (MaterialDesc){0}; | ||
809 | |||
810 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
811 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
812 | .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), | ||
813 | .type = UniformVec4, | ||
814 | .value.vec4 = vec4_make(1, 1, 1, 1)}; | ||
815 | |||
816 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
817 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
818 | .name = sstring_make(UNIFORM_METALLIC_FACTOR), | ||
819 | .type = UniformFloat, | ||
820 | .value.scalar = 0}; | ||
821 | |||
822 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
823 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
824 | .name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), | ||
825 | .type = UniformFloat, | ||
826 | .value.scalar = 1}; | ||
827 | |||
828 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
829 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
830 | .name = sstring_make(UNIFORM_EMISSIVE_FACTOR), | ||
831 | .type = UniformVec3, | ||
832 | .value.vec3 = vec3_make(0, 0, 0)}; | ||
833 | |||
834 | return gfx_make_material(&desc); | ||
835 | } | ||
836 | |||
806 | /// Load all meshes from the glTF scene. | 837 | /// Load all meshes from the glTF scene. |
807 | static bool load_meshes( | 838 | static bool load_meshes( |
808 | const cgltf_data* data, Gfx* gfx, Buffer** buffers, | 839 | const cgltf_data* data, Gfx* gfx, Buffer** buffers, |
809 | Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, | 840 | Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, |
810 | cgltf_size num_tangent_buffers, Material** materials, ShaderProgram* shader, | 841 | cgltf_size num_tangent_buffers, Material** materials, |
811 | size_t primitive_count, Geometry** geometries, Mesh** meshes, | 842 | ShaderProgram* const shader, size_t primitive_count, Geometry** geometries, |
812 | SceneObject** scene_objects) { | 843 | Mesh** meshes, SceneObject** scene_objects) { |
813 | // Walk through the mesh primitives to create Meshes. A GLTF mesh primitive | 844 | // Walk through the mesh primitives to create Meshes. A GLTF mesh primitive |
814 | // has a material (Mesh) and vertex data (Geometry). A GLTF mesh maps to | 845 | // has a material (Mesh) and vertex data (Geometry). A GLTF mesh maps to |
815 | // a SceneObject. | 846 | // a SceneObject. |
@@ -852,16 +883,21 @@ static bool load_meshes( | |||
852 | const cgltf_primitive* prim = &mesh->primitives[p]; | 883 | const cgltf_primitive* prim = &mesh->primitives[p]; |
853 | const cgltf_material* mat = prim->material; | 884 | const cgltf_material* mat = prim->material; |
854 | 885 | ||
855 | MeshPermutation perm = {0}; | 886 | MeshPermutation perm = {0}; |
856 | perm.has_normal_map = mat->normal_texture.texture != 0; | 887 | if (mat) { |
857 | perm.has_occlusion_map = mat->occlusion_texture.texture != 0; | 888 | perm.has_normal_map = mat->normal_texture.texture != 0; |
858 | perm.has_emissive_map = mat->emissive_texture.texture != 0; | 889 | perm.has_occlusion_map = mat->occlusion_texture.texture != 0; |
859 | // TODO: specular/glossiness and other material parameters. | 890 | perm.has_emissive_map = mat->emissive_texture.texture != 0; |
860 | if (mat->has_pbr_metallic_roughness) { | 891 | |
861 | const cgltf_pbr_metallic_roughness* pbr = &mat->pbr_metallic_roughness; | 892 | if (mat->has_pbr_metallic_roughness) { |
862 | perm.has_albedo_map = pbr->base_color_texture.texture != 0; | 893 | const cgltf_pbr_metallic_roughness* pbr = |
863 | perm.has_metallic_roughness_map = | 894 | &mat->pbr_metallic_roughness; |
864 | pbr->metallic_roughness_texture.texture != 0; | 895 | perm.has_albedo_map = pbr->base_color_texture.texture != 0; |
896 | perm.has_metallic_roughness_map = | ||
897 | pbr->metallic_roughness_texture.texture != 0; | ||
898 | } else { | ||
899 | // TODO: specular/glossiness and other material parameters. | ||
900 | } | ||
865 | } | 901 | } |
866 | 902 | ||
867 | GeometryDesc geometry_desc = { | 903 | GeometryDesc geometry_desc = { |
@@ -1034,36 +1070,39 @@ static bool load_meshes( | |||
1034 | CHECK_COUNT(weights.u16, uint16_t, 4); | 1070 | CHECK_COUNT(weights.u16, uint16_t, 4); |
1035 | CHECK_COUNT(weights.floats, float, 4); | 1071 | CHECK_COUNT(weights.floats, float, 4); |
1036 | 1072 | ||
1037 | const cgltf_size material_index = prim->material - data->materials; | 1073 | Material* material = 0; |
1038 | assert(material_index < data->materials_count); | 1074 | if (mat) { |
1039 | Material* material = materials[material_index]; | 1075 | const cgltf_size material_index = mat - data->materials; |
1076 | assert(material_index < data->materials_count); | ||
1077 | material = materials[material_index]; | ||
1078 | } else { | ||
1079 | // Create a default material for meshes that do not specify one. | ||
1080 | material = make_default_material(); | ||
1081 | } | ||
1082 | assert(material); | ||
1040 | 1083 | ||
1041 | geometries[next_mesh] = gfx_make_geometry(render_backend, &geometry_desc); | 1084 | geometries[next_mesh] = gfx_make_geometry(render_backend, &geometry_desc); |
1042 | if (!geometries[next_mesh]) { | 1085 | if (!geometries[next_mesh]) { |
1043 | return false; | 1086 | return false; |
1044 | } | 1087 | } |
1045 | 1088 | ||
1046 | // If the user specifies a custom shader, use that instead. | 1089 | // If the user specifies a custom shader, use that instead. Otherwise |
1047 | // else TODO: Build a shader based on permutation. | 1090 | // compile a shader based on the mesh's permutation. |
1048 | // | 1091 | // |
1049 | // TODO: We should cache shader permutations to re-use shader programs. | 1092 | // Note that Gfx takes care of caching shaders and shader programs. |
1050 | // Caching should not be done locally here because a caller may call | ||
1051 | // gfx_load_scene() multiple times to load multiple scenes, and we want | ||
1052 | // shader re-use across scenes too. | ||
1053 | // | 1093 | // |
1054 | // On the other hand, caching materials is not necessary since, provided | 1094 | // Caching materials could be useful, but, provided they can share |
1055 | // they can share shaders, the renderer can check later whether uniforms | 1095 | // shaders, the renderer can check later whether uniforms have the same |
1056 | // have the same values. Also, changing uniforms is much faster than | 1096 | // values. Also, changing uniforms is much faster than swapping shaders, |
1057 | // swapping shaders, so shader caching is the most important thing here. | 1097 | // so shader caching is the most important thing here. |
1058 | if (!shader) { | 1098 | ShaderProgram* mesh_shader = |
1059 | shader = make_shader_permutation(render_backend, perm); | 1099 | shader ? shader : make_shader_permutation(render_backend, perm); |
1060 | } | 1100 | assert(mesh_shader); |
1061 | assert(shader); | ||
1062 | 1101 | ||
1063 | meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){ | 1102 | meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){ |
1064 | .geometry = geometries[next_mesh], | 1103 | .geometry = geometries[next_mesh], |
1065 | .material = material, | 1104 | .material = material, |
1066 | .shader = shader}); | 1105 | .shader = mesh_shader}); |
1067 | 1106 | ||
1068 | if (!meshes[next_mesh]) { | 1107 | if (!meshes[next_mesh]) { |
1069 | return false; | 1108 | return false; |