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; |
