From afab154eb14f48f0992f35eb420515a83fc16c61 Mon Sep 17 00:00:00 2001 From: yesfish Date: Thu, 3 Oct 2024 07:25:00 +0100 Subject: [PATCH] Import custom attributes --- .../doc_classes/GLTFDocumentExtension.xml | 6 + .../editor/editor_scene_importer_blend.cpp | 6 + .../extensions/gltf_document_extension.cpp | 7 + .../gltf/extensions/gltf_document_extension.h | 2 + modules/gltf/gltf_document.cpp | 431 ++++++++---------- modules/gltf/gltf_document.h | 41 +- 6 files changed, 221 insertions(+), 272 deletions(-) diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index abdbce7eebdf..1f5b0dc5161b 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -199,6 +199,12 @@ Runs when parsing the texture JSON from the glTF textures array. This can be used to set the source image index to use as the texture. + + + + + + diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 5ba9ee3fa6b4..7e6d71064dab 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -279,6 +279,11 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ } else { parameters_map["export_def_bones"] = false; } + if (p_options.has(SNAME("blender/meshes/export_attributes")) && p_options[SNAME("blender/meshes/export_attributes")]) { + parameters_map["export_attributes"] = true; + } else { + parameters_map["export_attributes"] = false; + } if (p_options.has(SNAME("blender/nodes/modifiers")) && p_options[SNAME("blender/nodes/modifiers")]) { parameters_map["export_apply"] = true; } else { @@ -375,6 +380,7 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li ADD_OPTION_BOOL("blender/meshes/tangents", true); ADD_OPTION_ENUM("blender/meshes/skins", "None,4 Influences (Compatible),All Influences", BLEND_BONE_INFLUENCES_ALL); ADD_OPTION_BOOL("blender/meshes/export_bones_deforming_mesh_only", false); + ADD_OPTION_BOOL("blender/meshes/export_attributes", false); ADD_OPTION_BOOL("blender/materials/unpack_enabled", true); ADD_OPTION_ENUM("blender/materials/export_materials", "Placeholder,Export", BLEND_MATERIAL_EXPORT_EXPORT); ADD_OPTION_BOOL("blender/animation/limit_playback", true); diff --git a/modules/gltf/extensions/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp index 0806eee6bfef..23b7d8b14c7d 100644 --- a/modules/gltf/extensions/gltf_document_extension.cpp +++ b/modules/gltf/extensions/gltf_document_extension.cpp @@ -34,6 +34,7 @@ void GLTFDocumentExtension::_bind_methods() { // Import process. GDVIRTUAL_BIND(_import_preflight, "state", "extensions"); GDVIRTUAL_BIND(_get_supported_extensions); + GDVIRTUAL_BIND(_remap_custom_attribute, "name"); GDVIRTUAL_BIND(_parse_node_extensions, "state", "gltf_node", "extensions"); GDVIRTUAL_BIND(_parse_image_data, "state", "image_data", "mime_type", "ret_image"); GDVIRTUAL_BIND(_get_image_file_extension); @@ -66,6 +67,12 @@ Error GLTFDocumentExtension::import_preflight(Ref p_state, Vector GLTFDocumentExtension::get_supported_extensions() { Vector ret; GDVIRTUAL_CALL(_get_supported_extensions, ret); diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h index a6368ea78089..719b9b510889 100644 --- a/modules/gltf/extensions/gltf_document_extension.h +++ b/modules/gltf/extensions/gltf_document_extension.h @@ -45,6 +45,7 @@ class GLTFDocumentExtension : public Resource { // Import process. virtual Error import_preflight(Ref p_state, Vector p_extensions); virtual Vector get_supported_extensions(); + virtual int remap_custom_attribute(const String &p_name); virtual Error parse_node_extensions(Ref p_state, Ref p_gltf_node, Dictionary &p_extensions); virtual Error parse_image_data(Ref p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref r_image); virtual String get_image_file_extension(); @@ -71,6 +72,7 @@ class GLTFDocumentExtension : public Resource { // Import process. GDVIRTUAL2R(Error, _import_preflight, Ref, Vector); GDVIRTUAL0R(Vector, _get_supported_extensions); + GDVIRTUAL1R(int, _remap_custom_attribute, String); GDVIRTUAL3R(Error, _parse_node_extensions, Ref, Ref, Dictionary); GDVIRTUAL4R(Error, _parse_image_data, Ref, PackedByteArray, String, Ref); GDVIRTUAL0R(String, _get_image_file_extension); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 2f36c29ec4a5..173e76b014e5 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -73,6 +73,114 @@ constexpr int COMPONENT_COUNT_FOR_ACCESSOR_TYPE[7] = { 1, 2, 3, 4, 4, 9, 16 }; +template +Vector GLTFDocument::_decode_accessor_func(Ref p_state, + const GLTFAccessorIndex p_accessor, + const bool p_for_vertex, + const Vector &p_packed_vertex_ids, + Func &&p_func) { + Vector ret; + + const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); + + if (attribs.size() == 0) { + return ret; + } + + const bool packed = !p_packed_vertex_ids.is_empty(); + const int attr_size = attribs.size() / Elements; + + ERR_FAIL_COND_V_MSG(((attribs.size() % Elements) != 0) || (packed && *(--p_packed_vertex_ids.end()) >= attr_size), + ret, "Custom attribute data is invalid."); + + const int ret_size = (packed ? p_packed_vertex_ids.size() : attr_size); + + ret.resize(ret_size * Multiplier); + + for (int i = 0; i < ret_size; ++i) { + p_func(&ret.write[i * Multiplier], &attribs.ptr()[(packed ? p_packed_vertex_ids[i] : i) * Elements]); + } + + return ret; +} + +template +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, [](T *dst, const double *src) { + for (int i = 0; i < Elements; ++i) { + dst[i] = src[i]; + } + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, [](Vector2 *dst, const double *src) { + dst[0] = Vector2(src[0], src[1]); + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, [](Vector3 *dst, const double *src) { + dst[0] = Vector3(src[0], src[1], src[2]); + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, [](Quaternion *dst, const double *src) { + dst[0] = Quaternion(src[0], src[1], src[2], src[3]).normalized(); + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, + [](Transform2D *dst, const double *src) { + dst[0][0] = Vector2(src[0], src[1]); + dst[0][1] = Vector2(src[2], src[3]); + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, + [](Basis *dst, const double *src) { + dst[0].set_column(0, Vector3(src[0], src[1], src[2])); + dst[0].set_column(1, Vector3(src[3], src[4], src[5])); + dst[0].set_column(2, Vector3(src[6], src[7], src[8])); + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, + [](Transform3D *dst, const double *src) { + dst[0].basis.set_column(0, Vector3(src[0], src[1], src[2])); + dst[0].basis.set_column(1, Vector3(src[4], src[5], src[6])); + dst[0].basis.set_column(2, Vector3(src[8], src[9], src[10])); + dst[0].set_origin(Vector3(src[12], src[13], src[14])); + }); +} + +template <> +_FORCE_INLINE_ Vector GLTFDocument::_decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { + switch (p_state->accessors[p_accessor]->accessor_type) { + case GLTFAccessor::TYPE_VEC4: { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, + [](Color *dst, const double *src) { dst[0] = Color(src[0], src[1], src[2], src[3]); }); + } break; + case GLTFAccessor::TYPE_VEC3: { + return _decode_accessor_func(p_state, p_accessor, p_for_vertex, p_packed_vertex_ids, + [](Color *dst, const double *src) { dst[0] = Color(src[0], src[1], src[2]); }); + } break; + default: { + ERR_FAIL_V_MSG(Vector(), "Color data is invalid."); + } break; + } +} + static void _attach_extras_to_meta(const Dictionary &p_extras, Ref p_node) { if (!p_extras.is_empty()) { p_node->set_meta("extras", p_extras); @@ -1689,56 +1797,6 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref p_state, return p_state->accessors.size() - 1; } -Vector GLTFDocument::_decode_accessor_as_ints(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - const double *attribs_ptr = attribs.ptr(); - int ret_size = attribs.size(); - if (!p_packed_vertex_ids.is_empty()) { - ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret); - ret_size = p_packed_vertex_ids.size(); - } - ret.resize(ret_size); - for (int i = 0; i < ret_size; i++) { - int src_i = i; - if (!p_packed_vertex_ids.is_empty()) { - src_i = p_packed_vertex_ids[i]; - } - ret.write[i] = int(attribs_ptr[src_i]); - } - return ret; -} - -Vector GLTFDocument::_decode_accessor_as_floats(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - const double *attribs_ptr = attribs.ptr(); - int ret_size = attribs.size(); - if (!p_packed_vertex_ids.is_empty()) { - ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret); - ret_size = p_packed_vertex_ids.size(); - } - ret.resize(ret_size); - for (int i = 0; i < ret_size; i++) { - int src_i = i; - if (!p_packed_vertex_ids.is_empty()) { - src_i = p_packed_vertex_ids[i]; - } - ret.write[i] = float(attribs_ptr[src_i]); - } - return ret; -} - void GLTFDocument::_round_min_max_components(Vector &r_type_min, Vector &r_type_max) { // 3.6.2.5: For floating-point components, JSON-stored minimum and maximum values represent single precision // floats and SHOULD be rounded to single precision before usage to avoid any potential boundary mismatches. @@ -2022,32 +2080,6 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref p return p_state->accessors.size() - 1; } -Vector GLTFDocument::_decode_accessor_as_vec2(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret); - const double *attribs_ptr = attribs.ptr(); - int ret_size = attribs.size() / 2; - if (!p_packed_vertex_ids.is_empty()) { - ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret); - ret_size = p_packed_vertex_ids.size(); - } - ret.resize(ret_size); - for (int i = 0; i < ret_size; i++) { - int src_i = i; - if (!p_packed_vertex_ids.is_empty()) { - src_i = p_packed_vertex_ids[i]; - } - ret.write[i] = Vector2(attribs_ptr[src_i * 2 + 0], attribs_ptr[src_i * 2 + 1]); - } - return ret; -} - GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref p_state, const Vector p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; @@ -2328,137 +2360,6 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref p_state return p_state->accessors.size() - 1; } -Vector GLTFDocument::_decode_accessor_as_vec3(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret); - const double *attribs_ptr = attribs.ptr(); - int ret_size = attribs.size() / 3; - if (!p_packed_vertex_ids.is_empty()) { - ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret); - ret_size = p_packed_vertex_ids.size(); - } - ret.resize(ret_size); - for (int i = 0; i < ret_size; i++) { - int src_i = i; - if (!p_packed_vertex_ids.is_empty()) { - src_i = p_packed_vertex_ids[i]; - } - ret.write[i] = Vector3(attribs_ptr[src_i * 3 + 0], attribs_ptr[src_i * 3 + 1], attribs_ptr[src_i * 3 + 2]); - } - return ret; -} - -Vector GLTFDocument::_decode_accessor_as_color(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - const int accessor_type = p_state->accessors[p_accessor]->accessor_type; - ERR_FAIL_COND_V(!(accessor_type == GLTFAccessor::TYPE_VEC3 || accessor_type == GLTFAccessor::TYPE_VEC4), ret); - int vec_len = 3; - if (accessor_type == GLTFAccessor::TYPE_VEC4) { - vec_len = 4; - } - - ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret); - const double *attribs_ptr = attribs.ptr(); - int ret_size = attribs.size() / vec_len; - if (!p_packed_vertex_ids.is_empty()) { - ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret); - ret_size = p_packed_vertex_ids.size(); - } - ret.resize(ret_size); - for (int i = 0; i < ret_size; i++) { - int src_i = i; - if (!p_packed_vertex_ids.is_empty()) { - src_i = p_packed_vertex_ids[i]; - } - ret.write[i] = Color(attribs_ptr[src_i * vec_len + 0], attribs_ptr[src_i * vec_len + 1], attribs_ptr[src_i * vec_len + 2], vec_len == 4 ? attribs_ptr[src_i * 4 + 3] : 1.0); - } - return ret; -} -Vector GLTFDocument::_decode_accessor_as_quaternion(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size() / 4; - ret.resize(ret_size); - { - for (int i = 0; i < ret_size; i++) { - ret.write[i] = Quaternion(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); - } - } - return ret; -} -Vector GLTFDocument::_decode_accessor_as_xform2d(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); - ret.resize(attribs.size() / 4); - for (int i = 0; i < ret.size(); i++) { - ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]); - ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]); - } - return ret; -} - -Vector GLTFDocument::_decode_accessor_as_basis(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); - ret.resize(attribs.size() / 9); - for (int i = 0; i < ret.size(); i++) { - ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); - ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); - ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); - } - return ret; -} - -Vector GLTFDocument::_decode_accessor_as_xform(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); - Vector ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); - ret.resize(attribs.size() / 16); - for (int i = 0; i < ret.size(); i++) { - ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); - ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); - ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); - ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); - } - return ret; -} - Vector GLTFDocument::_decode_accessor_as_variant(Ref p_state, const GLTFAccessorIndex p_accessor, Variant::Type p_variant_type, GLTFAccessor::GLTFAccessorType p_accessor_type) { const Vector attribs = _decode_accessor(p_state, p_accessor, false); Vector ret; @@ -3269,7 +3170,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { int32_t orig_vertex_num = 0; ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR); if (a.has("POSITION")) { - PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true); + PackedVector3Array vertices = _decode_accessor(p_state, a["POSITION"], true); array[Mesh::ARRAY_VERTEX] = vertices; orig_vertex_num = vertices.size(); } @@ -3280,7 +3181,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { Vector indices_rev_mapping; Vector indices_vec4_mapping; if (mesh_prim.has("indices")) { - indices = _decode_accessor_as_ints(p_state, mesh_prim["indices"], false); + indices = _decode_accessor(p_state, mesh_prim["indices"], false); const int is = indices.size(); if (primitive == Mesh::PRIMITIVE_TRIANGLES) { @@ -3307,10 +3208,6 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { if (used_w[vert_i]) { rev_w[vert_i] = indices_mapping.size(); indices_mapping.push_back(vert_i); - indices_vec4_mapping.push_back(vert_i * 4 + 0); - indices_vec4_mapping.push_back(vert_i * 4 + 1); - indices_vec4_mapping.push_back(vert_i * 4 + 2); - indices_vec4_mapping.push_back(vert_i * 4 + 3); vertex_num++; } } @@ -3318,20 +3215,20 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { ERR_FAIL_COND_V(vertex_num <= 0, ERR_INVALID_DECLARATION); if (a.has("POSITION")) { - PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true, indices_mapping); + PackedVector3Array vertices = _decode_accessor(p_state, a["POSITION"], true, indices_mapping); array[Mesh::ARRAY_VERTEX] = vertices; } if (a.has("NORMAL")) { - array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], true, indices_mapping); + array[Mesh::ARRAY_NORMAL] = _decode_accessor(p_state, a["NORMAL"], true, indices_mapping); } if (a.has("TANGENT")) { - array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT"], true, indices_vec4_mapping); + array[Mesh::ARRAY_TANGENT] = _decode_accessor(p_state, a["TANGENT"], true, indices_mapping); } if (a.has("TEXCOORD_0")) { - array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], true, indices_mapping); + array[Mesh::ARRAY_TEX_UV] = _decode_accessor(p_state, a["TEXCOORD_0"], true, indices_mapping); } if (a.has("TEXCOORD_1")) { - array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], true, indices_mapping); + array[Mesh::ARRAY_TEX_UV2] = _decode_accessor(p_state, a["TEXCOORD_1"], true, indices_mapping); } for (int custom_i = 0; custom_i < 3; custom_i++) { Vector cur_custom; @@ -3342,12 +3239,12 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i); int num_channels = 0; if (a.has(gltf_texcoord_key)) { - texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true, indices_mapping); + texcoord_first = _decode_accessor(p_state, a[gltf_texcoord_key], true, indices_mapping); num_channels = 2; } gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1); if (a.has(gltf_texcoord_key)) { - texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true, indices_mapping); + texcoord_second = _decode_accessor(p_state, a[gltf_texcoord_key], true, indices_mapping); num_channels = 4; } if (!num_channels) { @@ -3388,16 +3285,16 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { } } if (a.has("COLOR_0")) { - array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], true, indices_mapping); + array[Mesh::ARRAY_COLOR] = _decode_accessor(p_state, a["COLOR_0"], true, indices_mapping); has_vertex_color = true; } if (a.has("JOINTS_0") && !a.has("JOINTS_1")) { - PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true, indices_vec4_mapping); + PackedInt32Array joints_0 = _decode_accessor(p_state, a["JOINTS_0"], true, indices_mapping); ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA); array[Mesh::ARRAY_BONES] = joints_0; } else if (a.has("JOINTS_0") && a.has("JOINTS_1")) { - PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true, indices_vec4_mapping); - PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1"], true, indices_vec4_mapping); + PackedInt32Array joints_0 = _decode_accessor(p_state, a["JOINTS_0"], true, indices_mapping); + PackedInt32Array joints_1 = _decode_accessor(p_state, a["JOINTS_1"], true, indices_mapping); ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA); ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA); int32_t weight_8_count = JOINT_GROUP_SIZE * 2; @@ -3416,7 +3313,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { array[Mesh::ARRAY_BONES] = joints; } if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) { - Vector weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true, indices_vec4_mapping); + Vector weights = _decode_accessor(p_state, a["WEIGHTS_0"], true, indices_mapping); ERR_FAIL_COND_V(weights.size() != 4 * vertex_num, ERR_INVALID_DATA); { // glTF does not seem to normalize the weights for some reason. int wc = weights.size(); @@ -3438,8 +3335,8 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { } array[Mesh::ARRAY_WEIGHTS] = weights; } else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) { - Vector weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true, indices_vec4_mapping); - Vector weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1"], true, indices_vec4_mapping); + Vector weights_0 = _decode_accessor(p_state, a["WEIGHTS_0"], true, indices_mapping); + Vector weights_1 = _decode_accessor(p_state, a["WEIGHTS_1"], true, indices_mapping); Vector weights; ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA); ERR_FAIL_COND_V(weights_0.size() != 4 * vertex_num, ERR_INVALID_DATA); @@ -3569,6 +3466,60 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { } } + for (Ref ext : document_extensions) { + for (const Variant &attrib_name : a.keys()) { + const int custom_i = ext->remap_custom_attribute(attrib_name); + if (custom_i == -1) { + continue; + } + + ERR_CONTINUE_MSG(custom_i < Mesh::ARRAY_CUSTOM0 || custom_i > Mesh::ARRAY_CUSTOM3, "Invalid MESH_CUSTOM index, ignoring attribute."); + ERR_CONTINUE_MSG(array[custom_i].get_type() != Variant::NIL, "Data already exists for MESH_CUSTOM index, ignoring attribute."); + + bool format_okay = true; + Mesh::ArrayCustomFormat format{}; + const Ref accessor = p_state->accessors[a[attrib_name]]; + switch (accessor->accessor_type) { + case GLTFAccessor::TYPE_SCALAR: { + array[custom_i] = _decode_accessor(p_state, a[attrib_name], true, indices_mapping); + format = Mesh::ARRAY_CUSTOM_R_FLOAT; + } break; + case GLTFAccessor::TYPE_VEC2: { + array[custom_i] = _decode_accessor(p_state, a[attrib_name], true, indices_mapping); + format = Mesh::ARRAY_CUSTOM_RG_FLOAT; + } break; + case GLTFAccessor::TYPE_VEC3: { + array[custom_i] = _decode_accessor(p_state, a[attrib_name], true, indices_mapping); + format = Mesh::ARRAY_CUSTOM_RGB_FLOAT; + } break; + case GLTFAccessor::TYPE_VEC4: { + array[custom_i] = _decode_accessor(p_state, a[attrib_name], true, indices_mapping); + format = Mesh::ARRAY_CUSTOM_RGBA_FLOAT; + } break; + default: { + format_okay = false; + } break; + } + + ERR_CONTINUE_MSG(!format_okay, "Unknown format for MESH_CUSTOM, ignoring attribute."); + + switch (custom_i) { + case Mesh::ARRAY_CUSTOM0: { + flags |= format << Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT; + } break; + case Mesh::ARRAY_CUSTOM1: { + flags |= format << Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT; + } break; + case Mesh::ARRAY_CUSTOM2: { + flags |= format << Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT; + } break; + case Mesh::ARRAY_CUSTOM3: { + flags |= format << Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT; + } break; + } + } + } + Array morphs; // Blend shapes if (mesh_prim.has("targets")) { @@ -3601,7 +3552,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { } if (t.has("POSITION")) { - Vector varr = _decode_accessor_as_vec3(p_state, t["POSITION"], true, indices_mapping); + Vector varr = _decode_accessor(p_state, t["POSITION"], true, indices_mapping); const Vector src_varr = array[Mesh::ARRAY_VERTEX]; const int size = src_varr.size(); ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); @@ -3623,7 +3574,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { array_copy[Mesh::ARRAY_VERTEX] = varr; } if (t.has("NORMAL")) { - Vector narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], true, indices_mapping); + Vector narr = _decode_accessor(p_state, t["NORMAL"], true, indices_mapping); const Vector src_narr = array[Mesh::ARRAY_NORMAL]; int size = src_narr.size(); ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); @@ -3645,7 +3596,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { array_copy[Mesh::ARRAY_NORMAL] = narr; } if (t.has("TANGENT")) { - const Vector tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], true, indices_mapping); + const Vector tangents_v3 = _decode_accessor(p_state, t["TANGENT"], true, indices_mapping); const Vector src_tangents = array[Mesh::ARRAY_TANGENT]; ERR_FAIL_COND_V(src_tangents.is_empty(), ERR_PARSE_ERROR); @@ -4962,7 +4913,7 @@ Error GLTFDocument::_parse_skins(Ref p_state) { const Array &joints = d["joints"]; if (d.has("inverseBindMatrices")) { - skin->inverse_binds = _decode_accessor_as_xform(p_state, d["inverseBindMatrices"], false); + skin->inverse_binds = _decode_accessor(p_state, d["inverseBindMatrices"], false); ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR); } @@ -5508,22 +5459,22 @@ Error GLTFDocument::_parse_animations(Ref p_state) { track = &animation->get_node_tracks()[node]; if (path == "translation") { - const Vector positions = _decode_accessor_as_vec3(p_state, output_value_accessor_index, false); + const Vector positions = _decode_accessor(p_state, output_value_accessor_index, false); track->position_track.interpolation = interp; track->position_track.times = times; track->position_track.values = positions; } else if (path == "rotation") { - const Vector rotations = _decode_accessor_as_quaternion(p_state, output_value_accessor_index, false); + const Vector rotations = _decode_accessor(p_state, output_value_accessor_index, false); track->rotation_track.interpolation = interp; track->rotation_track.times = times; track->rotation_track.values = rotations; } else if (path == "scale") { - const Vector scales = _decode_accessor_as_vec3(p_state, output_value_accessor_index, false); + const Vector scales = _decode_accessor(p_state, output_value_accessor_index, false); track->scale_track.interpolation = interp; track->scale_track.times = times; track->scale_track.values = scales; } else if (path == "weights") { - const Vector weights = _decode_accessor_as_floats(p_state, output_value_accessor_index, false); + const Vector weights = _decode_accessor(p_state, output_value_accessor_index, false); ERR_FAIL_INDEX_V(p_state->nodes[node]->mesh, p_state->meshes.size(), ERR_PARSE_ERROR); Ref mesh = p_state->meshes[p_state->nodes[node]->mesh]; @@ -5579,22 +5530,22 @@ void GLTFDocument::_parse_animation_pointer(Ref p_state, const String } GLTFAnimation::NodeTrack *track = &node_tracks[node_index]; if (split[2] == "translation") { - const Vector positions = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index, false); + const Vector positions = _decode_accessor(p_state, p_output_value_accessor_index, false); track->position_track.interpolation = p_interp; track->position_track.times = p_times; track->position_track.values = positions; } else if (split[2] == "rotation") { - const Vector rotations = _decode_accessor_as_quaternion(p_state, p_output_value_accessor_index, false); + const Vector rotations = _decode_accessor(p_state, p_output_value_accessor_index, false); track->rotation_track.interpolation = p_interp; track->rotation_track.times = p_times; track->rotation_track.values = rotations; } else if (split[2] == "scale") { - const Vector scales = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index, false); + const Vector scales = _decode_accessor(p_state, p_output_value_accessor_index, false); track->scale_track.interpolation = p_interp; track->scale_track.times = p_times; track->scale_track.values = scales; } else if (split[2] == "matrix") { - const Vector transforms = _decode_accessor_as_xform(p_state, p_output_value_accessor_index, false); + const Vector transforms = _decode_accessor(p_state, p_output_value_accessor_index, false); track->position_track.interpolation = p_interp; track->position_track.times = p_times; track->position_track.values.resize(transforms.size()); @@ -5610,7 +5561,7 @@ void GLTFDocument::_parse_animation_pointer(Ref p_state, const String track->scale_track.values.write[i] = transforms[i].basis.get_scale(); } } else { // if (split[2] == "weights") - const Vector accessor_weights = _decode_accessor_as_floats(p_state, p_output_value_accessor_index, false); + const Vector accessor_weights = _decode_accessor(p_state, p_output_value_accessor_index, false); const GLTFMeshIndex mesh_index = p_state->nodes[node_index]->mesh; ERR_FAIL_INDEX(mesh_index, p_state->meshes.size()); const Ref gltf_mesh = p_state->meshes[mesh_index]; diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index a6d6caa3f0a7..4e15dabaf6d4 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -143,38 +143,15 @@ class GLTFDocument : public Resource { Vector _decode_accessor(Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector _decode_accessor_as_floats(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex, - const Vector &p_packed_vertex_ids = Vector()); - Vector _decode_accessor_as_ints(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex, - const Vector &p_packed_vertex_ids = Vector()); - Vector _decode_accessor_as_vec2(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex, - const Vector &p_packed_vertex_ids = Vector()); - Vector _decode_accessor_as_vec3(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex, - const Vector &p_packed_vertex_ids = Vector()); - Vector _decode_accessor_as_color(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex, - const Vector &p_packed_vertex_ids = Vector()); - Vector _decode_accessor_as_quaternion(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex); - Vector _decode_accessor_as_xform2d(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex); - Vector _decode_accessor_as_basis(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex); - Vector _decode_accessor_as_xform(Ref p_state, - const GLTFAccessorIndex p_accessor, - const bool p_for_vertex); + + template + _FORCE_INLINE_ Vector _decode_accessor_func( + Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids, Func &&p_func); + + template + _FORCE_INLINE_ Vector _decode_accessor( + Ref p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector &p_packed_vertex_ids = Vector()); + Vector _decode_accessor_as_variant(Ref p_state, const GLTFAccessorIndex p_accessor, Variant::Type p_variant_type,