From 4469d8f94d38fcc6eab4417c7fdd68c92c58ff73 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 1 Feb 2021 23:06:22 -0800 Subject: [PATCH] gltfpack: Implement initial support for KHR_materials_variants This change implements basic support for material variants. Each mesh now keeps track of a set of material mappings; mesh merging is limited to cases when the variant set is the same, and all material variants are preserved. Since we don't correctly compute the UV bounds for variant materials, this only works without quantization so far. --- gltf/gltfpack.cpp | 39 +++++++++++++++++++++++++++++++++++++++ gltf/gltfpack.h | 4 ++++ gltf/material.cpp | 10 ++++++++++ gltf/mesh.cpp | 20 ++++++++++++++++++++ gltf/parsegltf.cpp | 2 ++ gltf/stream.cpp | 1 + 6 files changed, 76 insertions(+) diff --git a/gltf/gltfpack.cpp b/gltf/gltfpack.cpp index be36cbb83..44792644c 100644 --- a/gltf/gltfpack.cpp +++ b/gltf/gltfpack.cpp @@ -511,6 +511,26 @@ static void process(cgltf_data* data, const char* input_path, const char* output append(json_meshes, size_t(mi.remap)); } + if (mesh.variants.size()) + { + append(json_meshes, ",\"extensions\":{\"KHR_materials_variants\":{\"mappings\":["); + + for (size_t j = 0; j < mesh.variants.size(); ++j) + { + MaterialInfo& mi = materials[mesh.variants[j].material - data->materials]; + + assert(mi.keep); + comma(json_meshes); + append(json_meshes, "{\"material\":"); + append(json_meshes, size_t(mi.remap)); + append(json_meshes, ",\"variants\":["); + append(json_meshes, size_t(mesh.variants[j].variant)); + append(json_meshes, "]}"); + } + + append(json_meshes, "]}}"); + } + append(json_meshes, "}"); } @@ -661,6 +681,24 @@ static void process(cgltf_data* data, const char* input_path, const char* output append(json_extensions, "]}"); } + if (data->variants_count > 0) + { + comma(json_extensions); + append(json_extensions, "\"KHR_materials_variants\":{\"variants\":["); + + for (size_t i = 0; i < data->variants_count; ++i) + { + const cgltf_material_variant& variant = data->variants[i]; + + comma(json_extensions); + append(json_extensions, "{\"name\":\""); + append(json_extensions, variant.name); + append(json_extensions, "\"}"); + } + + append(json_extensions, "]}"); + } + append(json, "\"asset\":{"); append(json, "\"version\":\"2.0\",\"generator\":\"gltfpack "); append(json, getVersion()); @@ -680,6 +718,7 @@ static void process(cgltf_data* data, const char* input_path, const char* output {"KHR_materials_sheen", ext_sheen, false}, {"KHR_materials_volume", ext_volume, false}, {"KHR_materials_unlit", ext_unlit, false}, + {"KHR_materials_variants", data->variants_count > 0, false}, {"KHR_lights_punctual", data->lights_count > 0, false}, {"KHR_texture_basisu", !json_textures.empty() && settings.texture_ktx2, true}, {"EXT_mesh_gpu_instancing", ext_instancing, true}, diff --git a/gltf/gltfpack.h b/gltf/gltfpack.h index 86cb9d335..455478d96 100644 --- a/gltf/gltfpack.h +++ b/gltf/gltfpack.h @@ -54,6 +54,8 @@ struct Mesh size_t targets; std::vector target_weights; std::vector target_names; + + std::vector variants; }; struct Track @@ -255,7 +257,9 @@ void debugSimplify(const Mesh& mesh, const MaterialInfo& mi, Mesh& kinds, Mesh& void debugMeshlets(const Mesh& mesh, Mesh& meshlets, Mesh& bounds, int max_vertices, bool scan); bool compareMeshTargets(const Mesh& lhs, const Mesh& rhs); +bool compareMeshVariants(const Mesh& lhs, const Mesh& rhs); bool compareMeshNodes(const Mesh& lhs, const Mesh& rhs); + void mergeMeshInstances(Mesh& mesh); void mergeMeshes(std::vector& meshes, const Settings& settings); void filterEmptyMeshes(std::vector& meshes); diff --git a/gltf/material.cpp b/gltf/material.cpp index 99f07fca5..cd4b2728c 100644 --- a/gltf/material.cpp +++ b/gltf/material.cpp @@ -282,6 +282,9 @@ void mergeMeshMaterials(cgltf_data* data, std::vector& meshes, const Setti break; } } + + // TODO: merge variants + // TODO: clip useless variants } } @@ -298,6 +301,13 @@ void markNeededMaterials(cgltf_data* data, std::vector& materials, mi.keep = true; } + + for (size_t j = 0; j < mesh.variants.size(); ++j) + { + MaterialInfo& mi = materials[mesh.variants[j].material - data->materials]; + + mi.keep = true; + } } // mark all named materials as kept if requested diff --git a/gltf/mesh.cpp b/gltf/mesh.cpp index 347bce4c1..e6a36f812 100644 --- a/gltf/mesh.cpp +++ b/gltf/mesh.cpp @@ -131,6 +131,23 @@ bool compareMeshTargets(const Mesh& lhs, const Mesh& rhs) return true; } +bool compareMeshVariants(const Mesh& lhs, const Mesh& rhs) +{ + if (lhs.variants.size() != rhs.variants.size()) + return false; + + for (size_t i = 0; i < lhs.variants.size(); ++i) + { + if (lhs.variants[i].variant != rhs.variants[i].variant) + return false; + + if (lhs.variants[i].material != rhs.variants[i].material) + return false; + } + + return true; +} + bool compareMeshNodes(const Mesh& lhs, const Mesh& rhs) { if (lhs.nodes.size() != rhs.nodes.size()) @@ -198,6 +215,9 @@ static bool canMergeMeshes(const Mesh& lhs, const Mesh& rhs, const Settings& set if (!compareMeshTargets(lhs, rhs)) return false; + if (!compareMeshVariants(lhs, rhs)) + return false; + if (lhs.indices.empty() != rhs.indices.empty()) return false; diff --git a/gltf/parsegltf.cpp b/gltf/parsegltf.cpp index 55fd76e26..ec7b633f6 100644 --- a/gltf/parsegltf.cpp +++ b/gltf/parsegltf.cpp @@ -244,6 +244,8 @@ static void parseMeshesGltf(cgltf_data* data, std::vector& meshes, std::ve result.targets = primitive.targets_count; result.target_weights.assign(mesh.weights, mesh.weights + mesh.weights_count); result.target_names.assign(mesh.target_names, mesh.target_names + mesh.target_names_count); + + result.variants.assign(primitive.mappings, primitive.mappings + primitive.mappings_count); } mesh_remap[mi] = std::make_pair(remap_offset, meshes.size()); diff --git a/gltf/stream.cpp b/gltf/stream.cpp index 88aa393c6..138dae491 100644 --- a/gltf/stream.cpp +++ b/gltf/stream.cpp @@ -114,6 +114,7 @@ void prepareQuantizationTexture(cgltf_data* data, std::vector