| 1 | /**************************************************************************/ |
| 2 | /* gltf_document.cpp */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #include "gltf_document.h" |
| 32 | |
| 33 | #include "extensions/gltf_spec_gloss.h" |
| 34 | |
| 35 | #include "core/config/project_settings.h" |
| 36 | #include "core/crypto/crypto_core.h" |
| 37 | #include "core/io/config_file.h" |
| 38 | #include "core/io/dir_access.h" |
| 39 | #include "core/io/file_access.h" |
| 40 | #include "core/io/file_access_memory.h" |
| 41 | #include "core/io/json.h" |
| 42 | #include "core/io/stream_peer.h" |
| 43 | #include "core/math/disjoint_set.h" |
| 44 | #include "core/version.h" |
| 45 | #include "scene/3d/bone_attachment_3d.h" |
| 46 | #include "scene/3d/camera_3d.h" |
| 47 | #include "scene/3d/importer_mesh_instance_3d.h" |
| 48 | #include "scene/3d/light_3d.h" |
| 49 | #include "scene/3d/mesh_instance_3d.h" |
| 50 | #include "scene/3d/multimesh_instance_3d.h" |
| 51 | #include "scene/resources/image_texture.h" |
| 52 | #include "scene/resources/portable_compressed_texture.h" |
| 53 | #include "scene/resources/skin.h" |
| 54 | #include "scene/resources/surface_tool.h" |
| 55 | |
| 56 | #include "modules/modules_enabled.gen.h" // For csg, gridmap. |
| 57 | |
| 58 | #ifdef TOOLS_ENABLED |
| 59 | #include "editor/editor_file_system.h" |
| 60 | #endif |
| 61 | #ifdef MODULE_CSG_ENABLED |
| 62 | #include "modules/csg/csg_shape.h" |
| 63 | #endif // MODULE_CSG_ENABLED |
| 64 | #ifdef MODULE_GRIDMAP_ENABLED |
| 65 | #include "modules/gridmap/grid_map.h" |
| 66 | #endif // MODULE_GRIDMAP_ENABLED |
| 67 | |
| 68 | // FIXME: Hardcoded to avoid editor dependency. |
| 69 | #define GLTF_IMPORT_USE_NAMED_SKIN_BINDS 16 |
| 70 | #define GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS 32 |
| 71 | |
| 72 | #include <stdio.h> |
| 73 | #include <stdlib.h> |
| 74 | #include <cstdint> |
| 75 | #include <limits> |
| 76 | |
| 77 | static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) { |
| 78 | Ref<ImporterMesh> importer_mesh; |
| 79 | importer_mesh.instantiate(); |
| 80 | if (p_mesh.is_null()) { |
| 81 | return importer_mesh; |
| 82 | } |
| 83 | |
| 84 | Ref<ArrayMesh> array_mesh = p_mesh; |
| 85 | if (p_mesh->get_blend_shape_count()) { |
| 86 | ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; |
| 87 | if (array_mesh.is_valid()) { |
| 88 | shape_mode = array_mesh->get_blend_shape_mode(); |
| 89 | } |
| 90 | importer_mesh->set_blend_shape_mode(shape_mode); |
| 91 | for (int morph_i = 0; morph_i < p_mesh->get_blend_shape_count(); morph_i++) { |
| 92 | importer_mesh->add_blend_shape(p_mesh->get_blend_shape_name(morph_i)); |
| 93 | } |
| 94 | } |
| 95 | for (int32_t surface_i = 0; surface_i < p_mesh->get_surface_count(); surface_i++) { |
| 96 | Array array = p_mesh->surface_get_arrays(surface_i); |
| 97 | Ref<Material> mat = p_mesh->surface_get_material(surface_i); |
| 98 | String mat_name; |
| 99 | if (mat.is_valid()) { |
| 100 | mat_name = mat->get_name(); |
| 101 | } else { |
| 102 | // Assign default material when no material is assigned. |
| 103 | mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); |
| 104 | } |
| 105 | importer_mesh->add_surface(p_mesh->surface_get_primitive_type(surface_i), |
| 106 | array, p_mesh->surface_get_blend_shape_arrays(surface_i), p_mesh->surface_get_lods(surface_i), mat, |
| 107 | mat_name, p_mesh->surface_get_format(surface_i)); |
| 108 | } |
| 109 | return importer_mesh; |
| 110 | } |
| 111 | |
| 112 | Error GLTFDocument::_serialize(Ref<GLTFState> p_state) { |
| 113 | if (!p_state->buffers.size()) { |
| 114 | p_state->buffers.push_back(Vector<uint8_t>()); |
| 115 | } |
| 116 | |
| 117 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 118 | ERR_CONTINUE(ext.is_null()); |
| 119 | Error err = ext->export_preserialize(p_state); |
| 120 | ERR_CONTINUE(err != OK); |
| 121 | } |
| 122 | |
| 123 | /* STEP CONVERT MESH INSTANCES */ |
| 124 | _convert_mesh_instances(p_state); |
| 125 | |
| 126 | /* STEP SERIALIZE CAMERAS */ |
| 127 | Error err = _serialize_cameras(p_state); |
| 128 | if (err != OK) { |
| 129 | return Error::FAILED; |
| 130 | } |
| 131 | |
| 132 | /* STEP 3 CREATE SKINS */ |
| 133 | err = _serialize_skins(p_state); |
| 134 | if (err != OK) { |
| 135 | return Error::FAILED; |
| 136 | } |
| 137 | |
| 138 | /* STEP SERIALIZE MESHES (we have enough info now) */ |
| 139 | err = _serialize_meshes(p_state); |
| 140 | if (err != OK) { |
| 141 | return Error::FAILED; |
| 142 | } |
| 143 | |
| 144 | /* STEP SERIALIZE TEXTURES */ |
| 145 | err = _serialize_materials(p_state); |
| 146 | if (err != OK) { |
| 147 | return Error::FAILED; |
| 148 | } |
| 149 | |
| 150 | /* STEP SERIALIZE TEXTURE SAMPLERS */ |
| 151 | err = _serialize_texture_samplers(p_state); |
| 152 | if (err != OK) { |
| 153 | return Error::FAILED; |
| 154 | } |
| 155 | |
| 156 | /* STEP SERIALIZE ANIMATIONS */ |
| 157 | err = _serialize_animations(p_state); |
| 158 | if (err != OK) { |
| 159 | return Error::FAILED; |
| 160 | } |
| 161 | |
| 162 | /* STEP SERIALIZE ACCESSORS */ |
| 163 | err = _encode_accessors(p_state); |
| 164 | if (err != OK) { |
| 165 | return Error::FAILED; |
| 166 | } |
| 167 | |
| 168 | /* STEP SERIALIZE IMAGES */ |
| 169 | err = _serialize_images(p_state); |
| 170 | if (err != OK) { |
| 171 | return Error::FAILED; |
| 172 | } |
| 173 | |
| 174 | /* STEP SERIALIZE TEXTURES */ |
| 175 | err = _serialize_textures(p_state); |
| 176 | if (err != OK) { |
| 177 | return Error::FAILED; |
| 178 | } |
| 179 | |
| 180 | for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { |
| 181 | p_state->buffer_views.write[i]->buffer = 0; |
| 182 | } |
| 183 | |
| 184 | /* STEP SERIALIZE BUFFER VIEWS */ |
| 185 | err = _encode_buffer_views(p_state); |
| 186 | if (err != OK) { |
| 187 | return Error::FAILED; |
| 188 | } |
| 189 | |
| 190 | /* STEP SERIALIZE NODES */ |
| 191 | err = _serialize_nodes(p_state); |
| 192 | if (err != OK) { |
| 193 | return Error::FAILED; |
| 194 | } |
| 195 | |
| 196 | /* STEP SERIALIZE SCENE */ |
| 197 | err = _serialize_scenes(p_state); |
| 198 | if (err != OK) { |
| 199 | return Error::FAILED; |
| 200 | } |
| 201 | |
| 202 | /* STEP SERIALIZE LIGHTS */ |
| 203 | err = _serialize_lights(p_state); |
| 204 | if (err != OK) { |
| 205 | return Error::FAILED; |
| 206 | } |
| 207 | |
| 208 | /* STEP SERIALIZE EXTENSIONS */ |
| 209 | err = _serialize_gltf_extensions(p_state); |
| 210 | if (err != OK) { |
| 211 | return Error::FAILED; |
| 212 | } |
| 213 | |
| 214 | /* STEP SERIALIZE VERSION */ |
| 215 | err = _serialize_asset_header(p_state); |
| 216 | if (err != OK) { |
| 217 | return Error::FAILED; |
| 218 | } |
| 219 | |
| 220 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 221 | ERR_CONTINUE(ext.is_null()); |
| 222 | err = ext->export_post(p_state); |
| 223 | ERR_FAIL_COND_V(err != OK, err); |
| 224 | } |
| 225 | |
| 226 | return OK; |
| 227 | } |
| 228 | |
| 229 | Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> p_state) const { |
| 230 | Vector<String> extensions_used = p_state->extensions_used; |
| 231 | Vector<String> extensions_required = p_state->extensions_required; |
| 232 | if (!p_state->lights.is_empty()) { |
| 233 | extensions_used.push_back("KHR_lights_punctual" ); |
| 234 | } |
| 235 | if (p_state->use_khr_texture_transform) { |
| 236 | extensions_used.push_back("KHR_texture_transform" ); |
| 237 | extensions_required.push_back("KHR_texture_transform" ); |
| 238 | } |
| 239 | if (!extensions_used.is_empty()) { |
| 240 | extensions_used.sort(); |
| 241 | p_state->json["extensionsUsed" ] = extensions_used; |
| 242 | } |
| 243 | if (!extensions_required.is_empty()) { |
| 244 | extensions_required.sort(); |
| 245 | p_state->json["extensionsRequired" ] = extensions_required; |
| 246 | } |
| 247 | return OK; |
| 248 | } |
| 249 | |
| 250 | Error GLTFDocument::_serialize_scenes(Ref<GLTFState> p_state) { |
| 251 | ERR_FAIL_COND_V_MSG(p_state->root_nodes.size() == 0, ERR_INVALID_DATA, "GLTF export: The scene must have at least one root node." ); |
| 252 | // Godot only supports one scene per glTF file. |
| 253 | Array scenes; |
| 254 | Dictionary scene_dict; |
| 255 | scenes.append(scene_dict); |
| 256 | p_state->json["scenes" ] = scenes; |
| 257 | p_state->json["scene" ] = 0; |
| 258 | // Add nodes to the scene dict. |
| 259 | scene_dict["nodes" ] = p_state->root_nodes; |
| 260 | if (!p_state->scene_name.is_empty()) { |
| 261 | scene_dict["name" ] = p_state->scene_name; |
| 262 | } |
| 263 | return OK; |
| 264 | } |
| 265 | |
| 266 | Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> p_state) { |
| 267 | Error err; |
| 268 | Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); |
| 269 | if (file.is_null()) { |
| 270 | return err; |
| 271 | } |
| 272 | |
| 273 | Vector<uint8_t> array; |
| 274 | array.resize(file->get_length()); |
| 275 | file->get_buffer(array.ptrw(), array.size()); |
| 276 | String text; |
| 277 | text.parse_utf8((const char *)array.ptr(), array.size()); |
| 278 | |
| 279 | JSON json; |
| 280 | err = json.parse(text); |
| 281 | if (err != OK) { |
| 282 | _err_print_error("" , p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); |
| 283 | return err; |
| 284 | } |
| 285 | p_state->json = json.get_data(); |
| 286 | |
| 287 | return OK; |
| 288 | } |
| 289 | |
| 290 | Error GLTFDocument::_parse_glb(Ref<FileAccess> p_file, Ref<GLTFState> p_state) { |
| 291 | ERR_FAIL_NULL_V(p_file, ERR_INVALID_PARAMETER); |
| 292 | ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); |
| 293 | ERR_FAIL_COND_V(p_file->get_position() != 0, ERR_FILE_CANT_READ); |
| 294 | uint32_t magic = p_file->get_32(); |
| 295 | ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF |
| 296 | p_file->get_32(); // version |
| 297 | p_file->get_32(); // length |
| 298 | uint32_t chunk_length = p_file->get_32(); |
| 299 | uint32_t chunk_type = p_file->get_32(); |
| 300 | |
| 301 | ERR_FAIL_COND_V(chunk_type != 0x4E4F534A, ERR_PARSE_ERROR); //JSON |
| 302 | Vector<uint8_t> json_data; |
| 303 | json_data.resize(chunk_length); |
| 304 | uint32_t len = p_file->get_buffer(json_data.ptrw(), chunk_length); |
| 305 | ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); |
| 306 | |
| 307 | String text; |
| 308 | text.parse_utf8((const char *)json_data.ptr(), json_data.size()); |
| 309 | |
| 310 | JSON json; |
| 311 | Error err = json.parse(text); |
| 312 | if (err != OK) { |
| 313 | _err_print_error("" , "" , json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); |
| 314 | return err; |
| 315 | } |
| 316 | |
| 317 | p_state->json = json.get_data(); |
| 318 | |
| 319 | //data? |
| 320 | |
| 321 | chunk_length = p_file->get_32(); |
| 322 | chunk_type = p_file->get_32(); |
| 323 | |
| 324 | if (p_file->eof_reached()) { |
| 325 | return OK; //all good |
| 326 | } |
| 327 | |
| 328 | ERR_FAIL_COND_V(chunk_type != 0x004E4942, ERR_PARSE_ERROR); //BIN |
| 329 | |
| 330 | p_state->glb_data.resize(chunk_length); |
| 331 | len = p_file->get_buffer(p_state->glb_data.ptrw(), chunk_length); |
| 332 | ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); |
| 333 | |
| 334 | return OK; |
| 335 | } |
| 336 | |
| 337 | static Array _vec3_to_arr(const Vector3 &p_vec3) { |
| 338 | Array array; |
| 339 | array.resize(3); |
| 340 | array[0] = p_vec3.x; |
| 341 | array[1] = p_vec3.y; |
| 342 | array[2] = p_vec3.z; |
| 343 | return array; |
| 344 | } |
| 345 | |
| 346 | static Vector3 _arr_to_vec3(const Array &p_array) { |
| 347 | ERR_FAIL_COND_V(p_array.size() != 3, Vector3()); |
| 348 | return Vector3(p_array[0], p_array[1], p_array[2]); |
| 349 | } |
| 350 | |
| 351 | static Array _quaternion_to_array(const Quaternion &p_quaternion) { |
| 352 | Array array; |
| 353 | array.resize(4); |
| 354 | array[0] = p_quaternion.x; |
| 355 | array[1] = p_quaternion.y; |
| 356 | array[2] = p_quaternion.z; |
| 357 | array[3] = p_quaternion.w; |
| 358 | return array; |
| 359 | } |
| 360 | |
| 361 | static Quaternion _arr_to_quaternion(const Array &p_array) { |
| 362 | ERR_FAIL_COND_V(p_array.size() != 4, Quaternion()); |
| 363 | return Quaternion(p_array[0], p_array[1], p_array[2], p_array[3]); |
| 364 | } |
| 365 | |
| 366 | static Transform3D _arr_to_xform(const Array &p_array) { |
| 367 | ERR_FAIL_COND_V(p_array.size() != 16, Transform3D()); |
| 368 | |
| 369 | Transform3D xform; |
| 370 | xform.basis.set_column(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2])); |
| 371 | xform.basis.set_column(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6])); |
| 372 | xform.basis.set_column(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10])); |
| 373 | xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14])); |
| 374 | |
| 375 | return xform; |
| 376 | } |
| 377 | |
| 378 | static Vector<real_t> _xform_to_array(const Transform3D p_transform) { |
| 379 | Vector<real_t> array; |
| 380 | array.resize(16); |
| 381 | Vector3 axis_x = p_transform.get_basis().get_column(Vector3::AXIS_X); |
| 382 | array.write[0] = axis_x.x; |
| 383 | array.write[1] = axis_x.y; |
| 384 | array.write[2] = axis_x.z; |
| 385 | array.write[3] = 0.0f; |
| 386 | Vector3 axis_y = p_transform.get_basis().get_column(Vector3::AXIS_Y); |
| 387 | array.write[4] = axis_y.x; |
| 388 | array.write[5] = axis_y.y; |
| 389 | array.write[6] = axis_y.z; |
| 390 | array.write[7] = 0.0f; |
| 391 | Vector3 axis_z = p_transform.get_basis().get_column(Vector3::AXIS_Z); |
| 392 | array.write[8] = axis_z.x; |
| 393 | array.write[9] = axis_z.y; |
| 394 | array.write[10] = axis_z.z; |
| 395 | array.write[11] = 0.0f; |
| 396 | Vector3 origin = p_transform.get_origin(); |
| 397 | array.write[12] = origin.x; |
| 398 | array.write[13] = origin.y; |
| 399 | array.write[14] = origin.z; |
| 400 | array.write[15] = 1.0f; |
| 401 | return array; |
| 402 | } |
| 403 | |
| 404 | Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) { |
| 405 | Array nodes; |
| 406 | for (int i = 0; i < p_state->nodes.size(); i++) { |
| 407 | Dictionary node; |
| 408 | Ref<GLTFNode> gltf_node = p_state->nodes[i]; |
| 409 | Dictionary extensions; |
| 410 | node["extensions" ] = extensions; |
| 411 | if (!gltf_node->get_name().is_empty()) { |
| 412 | node["name" ] = gltf_node->get_name(); |
| 413 | } |
| 414 | if (gltf_node->camera != -1) { |
| 415 | node["camera" ] = gltf_node->camera; |
| 416 | } |
| 417 | if (gltf_node->light != -1) { |
| 418 | Dictionary lights_punctual; |
| 419 | extensions["KHR_lights_punctual" ] = lights_punctual; |
| 420 | lights_punctual["light" ] = gltf_node->light; |
| 421 | } |
| 422 | if (gltf_node->mesh != -1) { |
| 423 | node["mesh" ] = gltf_node->mesh; |
| 424 | } |
| 425 | if (gltf_node->skin != -1) { |
| 426 | node["skin" ] = gltf_node->skin; |
| 427 | } |
| 428 | if (gltf_node->skeleton != -1 && gltf_node->skin < 0) { |
| 429 | } |
| 430 | if (gltf_node->xform != Transform3D()) { |
| 431 | node["matrix" ] = _xform_to_array(gltf_node->xform); |
| 432 | } |
| 433 | |
| 434 | if (!gltf_node->rotation.is_equal_approx(Quaternion())) { |
| 435 | node["rotation" ] = _quaternion_to_array(gltf_node->rotation); |
| 436 | } |
| 437 | |
| 438 | if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { |
| 439 | node["scale" ] = _vec3_to_arr(gltf_node->scale); |
| 440 | } |
| 441 | |
| 442 | if (!gltf_node->position.is_zero_approx()) { |
| 443 | node["translation" ] = _vec3_to_arr(gltf_node->position); |
| 444 | } |
| 445 | if (gltf_node->children.size()) { |
| 446 | Array children; |
| 447 | for (int j = 0; j < gltf_node->children.size(); j++) { |
| 448 | children.push_back(gltf_node->children[j]); |
| 449 | } |
| 450 | node["children" ] = children; |
| 451 | } |
| 452 | |
| 453 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 454 | ERR_CONTINUE(ext.is_null()); |
| 455 | ERR_CONTINUE(!p_state->scene_nodes.find(i)); |
| 456 | Error err = ext->export_node(p_state, gltf_node, node, p_state->scene_nodes[i]); |
| 457 | ERR_CONTINUE(err != OK); |
| 458 | } |
| 459 | |
| 460 | nodes.push_back(node); |
| 461 | } |
| 462 | p_state->json["nodes" ] = nodes; |
| 463 | return OK; |
| 464 | } |
| 465 | |
| 466 | String GLTFDocument::_gen_unique_name(Ref<GLTFState> p_state, const String &p_name) { |
| 467 | const String s_name = p_name.validate_node_name(); |
| 468 | |
| 469 | String u_name; |
| 470 | int index = 1; |
| 471 | while (true) { |
| 472 | u_name = s_name; |
| 473 | |
| 474 | if (index > 1) { |
| 475 | u_name += itos(index); |
| 476 | } |
| 477 | if (!p_state->unique_names.has(u_name)) { |
| 478 | break; |
| 479 | } |
| 480 | index++; |
| 481 | } |
| 482 | |
| 483 | p_state->unique_names.insert(u_name); |
| 484 | |
| 485 | return u_name; |
| 486 | } |
| 487 | |
| 488 | String GLTFDocument::_sanitize_animation_name(const String &p_name) { |
| 489 | // Animations disallow the normal node invalid characters as well as "," and "[" |
| 490 | // (See animation/animation_player.cpp::add_animation) |
| 491 | |
| 492 | // TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node. |
| 493 | String anim_name = p_name.validate_node_name(); |
| 494 | anim_name = anim_name.replace("," , "" ); |
| 495 | anim_name = anim_name.replace("[" , "" ); |
| 496 | return anim_name; |
| 497 | } |
| 498 | |
| 499 | String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name) { |
| 500 | const String s_name = _sanitize_animation_name(p_name); |
| 501 | |
| 502 | String u_name; |
| 503 | int index = 1; |
| 504 | while (true) { |
| 505 | u_name = s_name; |
| 506 | |
| 507 | if (index > 1) { |
| 508 | u_name += itos(index); |
| 509 | } |
| 510 | if (!p_state->unique_animation_names.has(u_name)) { |
| 511 | break; |
| 512 | } |
| 513 | index++; |
| 514 | } |
| 515 | |
| 516 | p_state->unique_animation_names.insert(u_name); |
| 517 | |
| 518 | return u_name; |
| 519 | } |
| 520 | |
| 521 | String GLTFDocument::_sanitize_bone_name(const String &p_name) { |
| 522 | String bone_name = p_name; |
| 523 | bone_name = bone_name.replace(":" , "_" ); |
| 524 | bone_name = bone_name.replace("/" , "_" ); |
| 525 | return bone_name; |
| 526 | } |
| 527 | |
| 528 | String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i, const String &p_name) { |
| 529 | String s_name = _sanitize_bone_name(p_name); |
| 530 | if (s_name.is_empty()) { |
| 531 | s_name = "bone" ; |
| 532 | } |
| 533 | String u_name; |
| 534 | int index = 1; |
| 535 | while (true) { |
| 536 | u_name = s_name; |
| 537 | |
| 538 | if (index > 1) { |
| 539 | u_name += "_" + itos(index); |
| 540 | } |
| 541 | if (!p_state->skeletons[p_skel_i]->unique_names.has(u_name)) { |
| 542 | break; |
| 543 | } |
| 544 | index++; |
| 545 | } |
| 546 | |
| 547 | p_state->skeletons.write[p_skel_i]->unique_names.insert(u_name); |
| 548 | |
| 549 | return u_name; |
| 550 | } |
| 551 | |
| 552 | Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) { |
| 553 | p_state->unique_names.insert("Skeleton3D" ); // Reserve skeleton name. |
| 554 | ERR_FAIL_COND_V(!p_state->json.has("scenes" ), ERR_FILE_CORRUPT); |
| 555 | const Array &scenes = p_state->json["scenes" ]; |
| 556 | int loaded_scene = 0; |
| 557 | if (p_state->json.has("scene" )) { |
| 558 | loaded_scene = p_state->json["scene" ]; |
| 559 | } else { |
| 560 | WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene." ); |
| 561 | } |
| 562 | |
| 563 | if (scenes.size()) { |
| 564 | ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT); |
| 565 | const Dictionary &scene_dict = scenes[loaded_scene]; |
| 566 | ERR_FAIL_COND_V(!scene_dict.has("nodes" ), ERR_UNAVAILABLE); |
| 567 | const Array &nodes = scene_dict["nodes" ]; |
| 568 | for (int j = 0; j < nodes.size(); j++) { |
| 569 | p_state->root_nodes.push_back(nodes[j]); |
| 570 | } |
| 571 | // Determine what to use for the scene name. |
| 572 | if (scene_dict.has("name" ) && !String(scene_dict["name" ]).is_empty() && !((String)scene_dict["name" ]).begins_with("Scene" )) { |
| 573 | p_state->scene_name = scene_dict["name" ]; |
| 574 | } else { |
| 575 | p_state->scene_name = p_state->filename; |
| 576 | } |
| 577 | } |
| 578 | |
| 579 | return OK; |
| 580 | } |
| 581 | |
| 582 | Error GLTFDocument::_parse_nodes(Ref<GLTFState> p_state) { |
| 583 | ERR_FAIL_COND_V(!p_state->json.has("nodes" ), ERR_FILE_CORRUPT); |
| 584 | const Array &nodes = p_state->json["nodes" ]; |
| 585 | for (int i = 0; i < nodes.size(); i++) { |
| 586 | Ref<GLTFNode> node; |
| 587 | node.instantiate(); |
| 588 | const Dictionary &n = nodes[i]; |
| 589 | |
| 590 | if (n.has("name" )) { |
| 591 | node->set_name(n["name" ]); |
| 592 | } |
| 593 | if (n.has("camera" )) { |
| 594 | node->camera = n["camera" ]; |
| 595 | } |
| 596 | if (n.has("mesh" )) { |
| 597 | node->mesh = n["mesh" ]; |
| 598 | } |
| 599 | if (n.has("skin" )) { |
| 600 | node->skin = n["skin" ]; |
| 601 | } |
| 602 | if (n.has("matrix" )) { |
| 603 | node->xform = _arr_to_xform(n["matrix" ]); |
| 604 | } else { |
| 605 | if (n.has("translation" )) { |
| 606 | node->position = _arr_to_vec3(n["translation" ]); |
| 607 | } |
| 608 | if (n.has("rotation" )) { |
| 609 | node->rotation = _arr_to_quaternion(n["rotation" ]); |
| 610 | } |
| 611 | if (n.has("scale" )) { |
| 612 | node->scale = _arr_to_vec3(n["scale" ]); |
| 613 | } |
| 614 | |
| 615 | node->xform.basis.set_quaternion_scale(node->rotation, node->scale); |
| 616 | node->xform.origin = node->position; |
| 617 | } |
| 618 | |
| 619 | if (n.has("extensions" )) { |
| 620 | Dictionary extensions = n["extensions" ]; |
| 621 | if (extensions.has("KHR_lights_punctual" )) { |
| 622 | Dictionary lights_punctual = extensions["KHR_lights_punctual" ]; |
| 623 | if (lights_punctual.has("light" )) { |
| 624 | GLTFLightIndex light = lights_punctual["light" ]; |
| 625 | node->light = light; |
| 626 | } |
| 627 | } |
| 628 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 629 | ERR_CONTINUE(ext.is_null()); |
| 630 | Error err = ext->parse_node_extensions(p_state, node, extensions); |
| 631 | ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing node extensions for node " + node->get_name() + " in file " + p_state->filename + ". Continuing." ); |
| 632 | } |
| 633 | } |
| 634 | |
| 635 | if (n.has("children" )) { |
| 636 | const Array &children = n["children" ]; |
| 637 | for (int j = 0; j < children.size(); j++) { |
| 638 | node->children.push_back(children[j]); |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | p_state->nodes.push_back(node); |
| 643 | } |
| 644 | |
| 645 | // build the hierarchy |
| 646 | for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { |
| 647 | for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) { |
| 648 | GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j]; |
| 649 | |
| 650 | ERR_FAIL_INDEX_V(child_i, p_state->nodes.size(), ERR_FILE_CORRUPT); |
| 651 | ERR_CONTINUE(p_state->nodes[child_i]->parent != -1); //node already has a parent, wtf. |
| 652 | |
| 653 | p_state->nodes.write[child_i]->parent = node_i; |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | _compute_node_heights(p_state); |
| 658 | |
| 659 | return OK; |
| 660 | } |
| 661 | |
| 662 | void GLTFDocument::_compute_node_heights(Ref<GLTFState> p_state) { |
| 663 | p_state->root_nodes.clear(); |
| 664 | for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { |
| 665 | Ref<GLTFNode> node = p_state->nodes[node_i]; |
| 666 | node->height = 0; |
| 667 | |
| 668 | GLTFNodeIndex current_i = node_i; |
| 669 | while (current_i >= 0) { |
| 670 | const GLTFNodeIndex parent_i = p_state->nodes[current_i]->parent; |
| 671 | if (parent_i >= 0) { |
| 672 | ++node->height; |
| 673 | } |
| 674 | current_i = parent_i; |
| 675 | } |
| 676 | |
| 677 | if (node->height == 0) { |
| 678 | p_state->root_nodes.push_back(node_i); |
| 679 | } |
| 680 | } |
| 681 | } |
| 682 | |
| 683 | static Vector<uint8_t> _parse_base64_uri(const String &p_uri) { |
| 684 | int start = p_uri.find("," ); |
| 685 | ERR_FAIL_COND_V(start == -1, Vector<uint8_t>()); |
| 686 | |
| 687 | CharString substr = p_uri.substr(start + 1).ascii(); |
| 688 | |
| 689 | int strlen = substr.length(); |
| 690 | |
| 691 | Vector<uint8_t> buf; |
| 692 | buf.resize(strlen / 4 * 3 + 1 + 1); |
| 693 | |
| 694 | size_t len = 0; |
| 695 | ERR_FAIL_COND_V(CryptoCore::b64_decode(buf.ptrw(), buf.size(), &len, (unsigned char *)substr.get_data(), strlen) != OK, Vector<uint8_t>()); |
| 696 | |
| 697 | buf.resize(len); |
| 698 | |
| 699 | return buf; |
| 700 | } |
| 701 | |
| 702 | Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path) { |
| 703 | print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); |
| 704 | |
| 705 | if (!p_state->buffers.size()) { |
| 706 | return OK; |
| 707 | } |
| 708 | Array buffers; |
| 709 | if (p_state->buffers.size()) { |
| 710 | Vector<uint8_t> buffer_data = p_state->buffers[0]; |
| 711 | Dictionary gltf_buffer; |
| 712 | |
| 713 | gltf_buffer["byteLength" ] = buffer_data.size(); |
| 714 | buffers.push_back(gltf_buffer); |
| 715 | } |
| 716 | |
| 717 | for (GLTFBufferIndex i = 1; i < p_state->buffers.size() - 1; i++) { |
| 718 | Vector<uint8_t> buffer_data = p_state->buffers[i]; |
| 719 | Dictionary gltf_buffer; |
| 720 | String filename = p_path.get_basename().get_file() + itos(i) + ".bin" ; |
| 721 | String path = p_path.get_base_dir() + "/" + filename; |
| 722 | Error err; |
| 723 | Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err); |
| 724 | if (file.is_null()) { |
| 725 | return err; |
| 726 | } |
| 727 | if (buffer_data.size() == 0) { |
| 728 | return OK; |
| 729 | } |
| 730 | file->create(FileAccess::ACCESS_RESOURCES); |
| 731 | file->store_buffer(buffer_data.ptr(), buffer_data.size()); |
| 732 | gltf_buffer["uri" ] = filename; |
| 733 | gltf_buffer["byteLength" ] = buffer_data.size(); |
| 734 | buffers.push_back(gltf_buffer); |
| 735 | } |
| 736 | p_state->json["buffers" ] = buffers; |
| 737 | |
| 738 | return OK; |
| 739 | } |
| 740 | |
| 741 | Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path) { |
| 742 | print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); |
| 743 | |
| 744 | if (!p_state->buffers.size()) { |
| 745 | return OK; |
| 746 | } |
| 747 | Array buffers; |
| 748 | |
| 749 | for (GLTFBufferIndex i = 0; i < p_state->buffers.size(); i++) { |
| 750 | Vector<uint8_t> buffer_data = p_state->buffers[i]; |
| 751 | Dictionary gltf_buffer; |
| 752 | String filename = p_path.get_basename().get_file() + itos(i) + ".bin" ; |
| 753 | String path = p_path.get_base_dir() + "/" + filename; |
| 754 | Error err; |
| 755 | Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err); |
| 756 | if (file.is_null()) { |
| 757 | return err; |
| 758 | } |
| 759 | if (buffer_data.size() == 0) { |
| 760 | return OK; |
| 761 | } |
| 762 | file->create(FileAccess::ACCESS_RESOURCES); |
| 763 | file->store_buffer(buffer_data.ptr(), buffer_data.size()); |
| 764 | gltf_buffer["uri" ] = filename; |
| 765 | gltf_buffer["byteLength" ] = buffer_data.size(); |
| 766 | buffers.push_back(gltf_buffer); |
| 767 | } |
| 768 | p_state->json["buffers" ] = buffers; |
| 769 | |
| 770 | return OK; |
| 771 | } |
| 772 | |
| 773 | Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_path) { |
| 774 | if (!p_state->json.has("buffers" )) { |
| 775 | return OK; |
| 776 | } |
| 777 | |
| 778 | const Array &buffers = p_state->json["buffers" ]; |
| 779 | for (GLTFBufferIndex i = 0; i < buffers.size(); i++) { |
| 780 | if (i == 0 && p_state->glb_data.size()) { |
| 781 | p_state->buffers.push_back(p_state->glb_data); |
| 782 | |
| 783 | } else { |
| 784 | const Dictionary &buffer = buffers[i]; |
| 785 | if (buffer.has("uri" )) { |
| 786 | Vector<uint8_t> buffer_data; |
| 787 | String uri = buffer["uri" ]; |
| 788 | |
| 789 | if (uri.begins_with("data:" )) { // Embedded data using base64. |
| 790 | // Validate data MIME types and throw an error if it's one we don't know/support. |
| 791 | if (!uri.begins_with("data:application/octet-stream;base64" ) && |
| 792 | !uri.begins_with("data:application/gltf-buffer;base64" )) { |
| 793 | ERR_PRINT("glTF: Got buffer with an unknown URI data type: " + uri); |
| 794 | } |
| 795 | buffer_data = _parse_base64_uri(uri); |
| 796 | } else { // Relative path to an external image file. |
| 797 | ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); |
| 798 | uri = uri.uri_decode(); |
| 799 | uri = p_base_path.path_join(uri).replace("\\" , "/" ); // Fix for Windows. |
| 800 | buffer_data = FileAccess::get_file_as_bytes(uri); |
| 801 | ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); |
| 802 | } |
| 803 | |
| 804 | ERR_FAIL_COND_V(!buffer.has("byteLength" ), ERR_PARSE_ERROR); |
| 805 | int byteLength = buffer["byteLength" ]; |
| 806 | ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR); |
| 807 | p_state->buffers.push_back(buffer_data); |
| 808 | } |
| 809 | } |
| 810 | } |
| 811 | |
| 812 | print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); |
| 813 | |
| 814 | return OK; |
| 815 | } |
| 816 | |
| 817 | Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> p_state) { |
| 818 | Array buffers; |
| 819 | for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { |
| 820 | Dictionary d; |
| 821 | |
| 822 | Ref<GLTFBufferView> buffer_view = p_state->buffer_views[i]; |
| 823 | |
| 824 | d["buffer" ] = buffer_view->buffer; |
| 825 | d["byteLength" ] = buffer_view->byte_length; |
| 826 | |
| 827 | d["byteOffset" ] = buffer_view->byte_offset; |
| 828 | |
| 829 | if (buffer_view->byte_stride != -1) { |
| 830 | d["byteStride" ] = buffer_view->byte_stride; |
| 831 | } |
| 832 | |
| 833 | // TODO Sparse |
| 834 | // d["target"] = buffer_view->indices; |
| 835 | |
| 836 | ERR_FAIL_COND_V(!d.has("buffer" ), ERR_INVALID_DATA); |
| 837 | ERR_FAIL_COND_V(!d.has("byteLength" ), ERR_INVALID_DATA); |
| 838 | buffers.push_back(d); |
| 839 | } |
| 840 | print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size())); |
| 841 | if (!buffers.size()) { |
| 842 | return OK; |
| 843 | } |
| 844 | p_state->json["bufferViews" ] = buffers; |
| 845 | return OK; |
| 846 | } |
| 847 | |
| 848 | Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> p_state) { |
| 849 | if (!p_state->json.has("bufferViews" )) { |
| 850 | return OK; |
| 851 | } |
| 852 | const Array &buffers = p_state->json["bufferViews" ]; |
| 853 | for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) { |
| 854 | const Dictionary &d = buffers[i]; |
| 855 | |
| 856 | Ref<GLTFBufferView> buffer_view; |
| 857 | buffer_view.instantiate(); |
| 858 | |
| 859 | ERR_FAIL_COND_V(!d.has("buffer" ), ERR_PARSE_ERROR); |
| 860 | buffer_view->buffer = d["buffer" ]; |
| 861 | ERR_FAIL_COND_V(!d.has("byteLength" ), ERR_PARSE_ERROR); |
| 862 | buffer_view->byte_length = d["byteLength" ]; |
| 863 | |
| 864 | if (d.has("byteOffset" )) { |
| 865 | buffer_view->byte_offset = d["byteOffset" ]; |
| 866 | } |
| 867 | |
| 868 | if (d.has("byteStride" )) { |
| 869 | buffer_view->byte_stride = d["byteStride" ]; |
| 870 | } |
| 871 | |
| 872 | if (d.has("target" )) { |
| 873 | const int target = d["target" ]; |
| 874 | buffer_view->indices = target == GLTFDocument::ELEMENT_ARRAY_BUFFER; |
| 875 | } |
| 876 | |
| 877 | p_state->buffer_views.push_back(buffer_view); |
| 878 | } |
| 879 | |
| 880 | print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size())); |
| 881 | |
| 882 | return OK; |
| 883 | } |
| 884 | |
| 885 | Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) { |
| 886 | Array accessors; |
| 887 | for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) { |
| 888 | Dictionary d; |
| 889 | |
| 890 | Ref<GLTFAccessor> accessor = p_state->accessors[i]; |
| 891 | d["componentType" ] = accessor->component_type; |
| 892 | d["count" ] = accessor->count; |
| 893 | d["type" ] = _get_accessor_type_name(accessor->type); |
| 894 | d["byteOffset" ] = accessor->byte_offset; |
| 895 | d["normalized" ] = accessor->normalized; |
| 896 | d["max" ] = accessor->max; |
| 897 | d["min" ] = accessor->min; |
| 898 | d["bufferView" ] = accessor->buffer_view; //optional because it may be sparse... |
| 899 | |
| 900 | // Dictionary s; |
| 901 | // s["count"] = accessor->sparse_count; |
| 902 | // ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR); |
| 903 | |
| 904 | // s["indices"] = accessor->sparse_accessors; |
| 905 | // ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR); |
| 906 | |
| 907 | // Dictionary si; |
| 908 | |
| 909 | // si["bufferView"] = accessor->sparse_indices_buffer_view; |
| 910 | |
| 911 | // ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR); |
| 912 | // si["componentType"] = accessor->sparse_indices_component_type; |
| 913 | |
| 914 | // if (si.has("byteOffset")) { |
| 915 | // si["byteOffset"] = accessor->sparse_indices_byte_offset; |
| 916 | // } |
| 917 | |
| 918 | // ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR); |
| 919 | // s["indices"] = si; |
| 920 | // Dictionary sv; |
| 921 | |
| 922 | // sv["bufferView"] = accessor->sparse_values_buffer_view; |
| 923 | // if (sv.has("byteOffset")) { |
| 924 | // sv["byteOffset"] = accessor->sparse_values_byte_offset; |
| 925 | // } |
| 926 | // ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR); |
| 927 | // s["values"] = sv; |
| 928 | // ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR); |
| 929 | // d["sparse"] = s; |
| 930 | accessors.push_back(d); |
| 931 | } |
| 932 | |
| 933 | if (!accessors.size()) { |
| 934 | return OK; |
| 935 | } |
| 936 | p_state->json["accessors" ] = accessors; |
| 937 | ERR_FAIL_COND_V(!p_state->json.has("accessors" ), ERR_FILE_CORRUPT); |
| 938 | print_verbose("glTF: Total accessors: " + itos(p_state->accessors.size())); |
| 939 | |
| 940 | return OK; |
| 941 | } |
| 942 | |
| 943 | String GLTFDocument::_get_accessor_type_name(const GLTFType p_type) { |
| 944 | if (p_type == GLTFType::TYPE_SCALAR) { |
| 945 | return "SCALAR" ; |
| 946 | } |
| 947 | if (p_type == GLTFType::TYPE_VEC2) { |
| 948 | return "VEC2" ; |
| 949 | } |
| 950 | if (p_type == GLTFType::TYPE_VEC3) { |
| 951 | return "VEC3" ; |
| 952 | } |
| 953 | if (p_type == GLTFType::TYPE_VEC4) { |
| 954 | return "VEC4" ; |
| 955 | } |
| 956 | |
| 957 | if (p_type == GLTFType::TYPE_MAT2) { |
| 958 | return "MAT2" ; |
| 959 | } |
| 960 | if (p_type == GLTFType::TYPE_MAT3) { |
| 961 | return "MAT3" ; |
| 962 | } |
| 963 | if (p_type == GLTFType::TYPE_MAT4) { |
| 964 | return "MAT4" ; |
| 965 | } |
| 966 | ERR_FAIL_V("SCALAR" ); |
| 967 | } |
| 968 | |
| 969 | GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { |
| 970 | if (p_string == "SCALAR" ) { |
| 971 | return GLTFType::TYPE_SCALAR; |
| 972 | } |
| 973 | |
| 974 | if (p_string == "VEC2" ) { |
| 975 | return GLTFType::TYPE_VEC2; |
| 976 | } |
| 977 | if (p_string == "VEC3" ) { |
| 978 | return GLTFType::TYPE_VEC3; |
| 979 | } |
| 980 | if (p_string == "VEC4" ) { |
| 981 | return GLTFType::TYPE_VEC4; |
| 982 | } |
| 983 | |
| 984 | if (p_string == "MAT2" ) { |
| 985 | return GLTFType::TYPE_MAT2; |
| 986 | } |
| 987 | if (p_string == "MAT3" ) { |
| 988 | return GLTFType::TYPE_MAT3; |
| 989 | } |
| 990 | if (p_string == "MAT4" ) { |
| 991 | return GLTFType::TYPE_MAT4; |
| 992 | } |
| 993 | |
| 994 | ERR_FAIL_V(GLTFType::TYPE_SCALAR); |
| 995 | } |
| 996 | |
| 997 | Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) { |
| 998 | if (!p_state->json.has("accessors" )) { |
| 999 | return OK; |
| 1000 | } |
| 1001 | const Array &accessors = p_state->json["accessors" ]; |
| 1002 | for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) { |
| 1003 | const Dictionary &d = accessors[i]; |
| 1004 | |
| 1005 | Ref<GLTFAccessor> accessor; |
| 1006 | accessor.instantiate(); |
| 1007 | |
| 1008 | ERR_FAIL_COND_V(!d.has("componentType" ), ERR_PARSE_ERROR); |
| 1009 | accessor->component_type = d["componentType" ]; |
| 1010 | ERR_FAIL_COND_V(!d.has("count" ), ERR_PARSE_ERROR); |
| 1011 | accessor->count = d["count" ]; |
| 1012 | ERR_FAIL_COND_V(!d.has("type" ), ERR_PARSE_ERROR); |
| 1013 | accessor->type = _get_type_from_str(d["type" ]); |
| 1014 | |
| 1015 | if (d.has("bufferView" )) { |
| 1016 | accessor->buffer_view = d["bufferView" ]; //optional because it may be sparse... |
| 1017 | } |
| 1018 | |
| 1019 | if (d.has("byteOffset" )) { |
| 1020 | accessor->byte_offset = d["byteOffset" ]; |
| 1021 | } |
| 1022 | |
| 1023 | if (d.has("normalized" )) { |
| 1024 | accessor->normalized = d["normalized" ]; |
| 1025 | } |
| 1026 | |
| 1027 | if (d.has("max" )) { |
| 1028 | accessor->max = d["max" ]; |
| 1029 | } |
| 1030 | |
| 1031 | if (d.has("min" )) { |
| 1032 | accessor->min = d["min" ]; |
| 1033 | } |
| 1034 | |
| 1035 | if (d.has("sparse" )) { |
| 1036 | //eeh.. |
| 1037 | |
| 1038 | const Dictionary &s = d["sparse" ]; |
| 1039 | |
| 1040 | ERR_FAIL_COND_V(!s.has("count" ), ERR_PARSE_ERROR); |
| 1041 | accessor->sparse_count = s["count" ]; |
| 1042 | ERR_FAIL_COND_V(!s.has("indices" ), ERR_PARSE_ERROR); |
| 1043 | const Dictionary &si = s["indices" ]; |
| 1044 | |
| 1045 | ERR_FAIL_COND_V(!si.has("bufferView" ), ERR_PARSE_ERROR); |
| 1046 | accessor->sparse_indices_buffer_view = si["bufferView" ]; |
| 1047 | ERR_FAIL_COND_V(!si.has("componentType" ), ERR_PARSE_ERROR); |
| 1048 | accessor->sparse_indices_component_type = si["componentType" ]; |
| 1049 | |
| 1050 | if (si.has("byteOffset" )) { |
| 1051 | accessor->sparse_indices_byte_offset = si["byteOffset" ]; |
| 1052 | } |
| 1053 | |
| 1054 | ERR_FAIL_COND_V(!s.has("values" ), ERR_PARSE_ERROR); |
| 1055 | const Dictionary &sv = s["values" ]; |
| 1056 | |
| 1057 | ERR_FAIL_COND_V(!sv.has("bufferView" ), ERR_PARSE_ERROR); |
| 1058 | accessor->sparse_values_buffer_view = sv["bufferView" ]; |
| 1059 | if (sv.has("byteOffset" )) { |
| 1060 | accessor->sparse_values_byte_offset = sv["byteOffset" ]; |
| 1061 | } |
| 1062 | } |
| 1063 | |
| 1064 | p_state->accessors.push_back(accessor); |
| 1065 | } |
| 1066 | |
| 1067 | print_verbose("glTF: Total accessors: " + itos(p_state->accessors.size())); |
| 1068 | |
| 1069 | return OK; |
| 1070 | } |
| 1071 | |
| 1072 | double GLTFDocument::_filter_number(double p_float) { |
| 1073 | if (Math::is_nan(p_float)) { |
| 1074 | return 0.0f; |
| 1075 | } |
| 1076 | return p_float; |
| 1077 | } |
| 1078 | |
| 1079 | String GLTFDocument::_get_component_type_name(const uint32_t p_component) { |
| 1080 | switch (p_component) { |
| 1081 | case GLTFDocument::COMPONENT_TYPE_BYTE: |
| 1082 | return "Byte" ; |
| 1083 | case GLTFDocument::COMPONENT_TYPE_UNSIGNED_BYTE: |
| 1084 | return "UByte" ; |
| 1085 | case GLTFDocument::COMPONENT_TYPE_SHORT: |
| 1086 | return "Short" ; |
| 1087 | case GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT: |
| 1088 | return "UShort" ; |
| 1089 | case GLTFDocument::COMPONENT_TYPE_INT: |
| 1090 | return "Int" ; |
| 1091 | case GLTFDocument::COMPONENT_TYPE_FLOAT: |
| 1092 | return "Float" ; |
| 1093 | } |
| 1094 | |
| 1095 | return "<Error>" ; |
| 1096 | } |
| 1097 | |
| 1098 | String GLTFDocument::_get_type_name(const GLTFType p_component) { |
| 1099 | static const char *names[] = { |
| 1100 | "float" , |
| 1101 | "vec2" , |
| 1102 | "vec3" , |
| 1103 | "vec4" , |
| 1104 | "mat2" , |
| 1105 | "mat3" , |
| 1106 | "mat4" |
| 1107 | }; |
| 1108 | |
| 1109 | return names[p_component]; |
| 1110 | } |
| 1111 | |
| 1112 | Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, const int p_count, const GLTFType p_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor) { |
| 1113 | const int component_count_for_type[7] = { |
| 1114 | 1, 2, 3, 4, 4, 9, 16 |
| 1115 | }; |
| 1116 | |
| 1117 | const int component_count = component_count_for_type[p_type]; |
| 1118 | const int component_size = _get_component_type_size(p_component_type); |
| 1119 | ERR_FAIL_COND_V(component_size == 0, FAILED); |
| 1120 | |
| 1121 | int skip_every = 0; |
| 1122 | int skip_bytes = 0; |
| 1123 | //special case of alignments, as described in spec |
| 1124 | switch (p_component_type) { |
| 1125 | case COMPONENT_TYPE_BYTE: |
| 1126 | case COMPONENT_TYPE_UNSIGNED_BYTE: { |
| 1127 | if (p_type == TYPE_MAT2) { |
| 1128 | skip_every = 2; |
| 1129 | skip_bytes = 2; |
| 1130 | } |
| 1131 | if (p_type == TYPE_MAT3) { |
| 1132 | skip_every = 3; |
| 1133 | skip_bytes = 1; |
| 1134 | } |
| 1135 | } break; |
| 1136 | case COMPONENT_TYPE_SHORT: |
| 1137 | case COMPONENT_TYPE_UNSIGNED_SHORT: { |
| 1138 | if (p_type == TYPE_MAT3) { |
| 1139 | skip_every = 6; |
| 1140 | skip_bytes = 4; |
| 1141 | } |
| 1142 | } break; |
| 1143 | default: { |
| 1144 | } |
| 1145 | } |
| 1146 | |
| 1147 | Ref<GLTFBufferView> bv; |
| 1148 | bv.instantiate(); |
| 1149 | const uint32_t offset = bv->byte_offset = p_byte_offset; |
| 1150 | Vector<uint8_t> &gltf_buffer = p_state->buffers.write[0]; |
| 1151 | |
| 1152 | int stride = _get_component_type_size(p_component_type); |
| 1153 | if (p_for_vertex && stride % 4) { |
| 1154 | stride += 4 - (stride % 4); //according to spec must be multiple of 4 |
| 1155 | } |
| 1156 | //use to debug |
| 1157 | print_verbose("glTF: encoding type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); |
| 1158 | |
| 1159 | print_verbose("glTF: encoding accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length)); |
| 1160 | |
| 1161 | const int buffer_end = (stride * (p_count - 1)) + _get_component_type_size(p_component_type); |
| 1162 | // TODO define bv->byte_stride |
| 1163 | bv->byte_offset = gltf_buffer.size(); |
| 1164 | |
| 1165 | switch (p_component_type) { |
| 1166 | case COMPONENT_TYPE_BYTE: { |
| 1167 | Vector<int8_t> buffer; |
| 1168 | buffer.resize(p_count * component_count); |
| 1169 | int32_t dst_i = 0; |
| 1170 | for (int i = 0; i < p_count; i++) { |
| 1171 | for (int j = 0; j < component_count; j++) { |
| 1172 | if (skip_every && j > 0 && (j % skip_every) == 0) { |
| 1173 | dst_i += skip_bytes; |
| 1174 | } |
| 1175 | double d = *p_src; |
| 1176 | if (p_normalized) { |
| 1177 | buffer.write[dst_i] = d * 128.0; |
| 1178 | } else { |
| 1179 | buffer.write[dst_i] = d; |
| 1180 | } |
| 1181 | p_src++; |
| 1182 | dst_i++; |
| 1183 | } |
| 1184 | } |
| 1185 | int64_t old_size = gltf_buffer.size(); |
| 1186 | gltf_buffer.resize(old_size + (buffer.size() * sizeof(int8_t))); |
| 1187 | memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t)); |
| 1188 | bv->byte_length = buffer.size() * sizeof(int8_t); |
| 1189 | } break; |
| 1190 | case COMPONENT_TYPE_UNSIGNED_BYTE: { |
| 1191 | Vector<uint8_t> buffer; |
| 1192 | buffer.resize(p_count * component_count); |
| 1193 | int32_t dst_i = 0; |
| 1194 | for (int i = 0; i < p_count; i++) { |
| 1195 | for (int j = 0; j < component_count; j++) { |
| 1196 | if (skip_every && j > 0 && (j % skip_every) == 0) { |
| 1197 | dst_i += skip_bytes; |
| 1198 | } |
| 1199 | double d = *p_src; |
| 1200 | if (p_normalized) { |
| 1201 | buffer.write[dst_i] = d * 255.0; |
| 1202 | } else { |
| 1203 | buffer.write[dst_i] = d; |
| 1204 | } |
| 1205 | p_src++; |
| 1206 | dst_i++; |
| 1207 | } |
| 1208 | } |
| 1209 | gltf_buffer.append_array(buffer); |
| 1210 | bv->byte_length = buffer.size() * sizeof(uint8_t); |
| 1211 | } break; |
| 1212 | case COMPONENT_TYPE_SHORT: { |
| 1213 | Vector<int16_t> buffer; |
| 1214 | buffer.resize(p_count * component_count); |
| 1215 | int32_t dst_i = 0; |
| 1216 | for (int i = 0; i < p_count; i++) { |
| 1217 | for (int j = 0; j < component_count; j++) { |
| 1218 | if (skip_every && j > 0 && (j % skip_every) == 0) { |
| 1219 | dst_i += skip_bytes; |
| 1220 | } |
| 1221 | double d = *p_src; |
| 1222 | if (p_normalized) { |
| 1223 | buffer.write[dst_i] = d * 32768.0; |
| 1224 | } else { |
| 1225 | buffer.write[dst_i] = d; |
| 1226 | } |
| 1227 | p_src++; |
| 1228 | dst_i++; |
| 1229 | } |
| 1230 | } |
| 1231 | int64_t old_size = gltf_buffer.size(); |
| 1232 | gltf_buffer.resize(old_size + (buffer.size() * sizeof(int16_t))); |
| 1233 | memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t)); |
| 1234 | bv->byte_length = buffer.size() * sizeof(int16_t); |
| 1235 | } break; |
| 1236 | case COMPONENT_TYPE_UNSIGNED_SHORT: { |
| 1237 | Vector<uint16_t> buffer; |
| 1238 | buffer.resize(p_count * component_count); |
| 1239 | int32_t dst_i = 0; |
| 1240 | for (int i = 0; i < p_count; i++) { |
| 1241 | for (int j = 0; j < component_count; j++) { |
| 1242 | if (skip_every && j > 0 && (j % skip_every) == 0) { |
| 1243 | dst_i += skip_bytes; |
| 1244 | } |
| 1245 | double d = *p_src; |
| 1246 | if (p_normalized) { |
| 1247 | buffer.write[dst_i] = d * 65535.0; |
| 1248 | } else { |
| 1249 | buffer.write[dst_i] = d; |
| 1250 | } |
| 1251 | p_src++; |
| 1252 | dst_i++; |
| 1253 | } |
| 1254 | } |
| 1255 | int64_t old_size = gltf_buffer.size(); |
| 1256 | gltf_buffer.resize(old_size + (buffer.size() * sizeof(uint16_t))); |
| 1257 | memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t)); |
| 1258 | bv->byte_length = buffer.size() * sizeof(uint16_t); |
| 1259 | } break; |
| 1260 | case COMPONENT_TYPE_INT: { |
| 1261 | Vector<int> buffer; |
| 1262 | buffer.resize(p_count * component_count); |
| 1263 | int32_t dst_i = 0; |
| 1264 | for (int i = 0; i < p_count; i++) { |
| 1265 | for (int j = 0; j < component_count; j++) { |
| 1266 | if (skip_every && j > 0 && (j % skip_every) == 0) { |
| 1267 | dst_i += skip_bytes; |
| 1268 | } |
| 1269 | double d = *p_src; |
| 1270 | buffer.write[dst_i] = d; |
| 1271 | p_src++; |
| 1272 | dst_i++; |
| 1273 | } |
| 1274 | } |
| 1275 | int64_t old_size = gltf_buffer.size(); |
| 1276 | gltf_buffer.resize(old_size + (buffer.size() * sizeof(int32_t))); |
| 1277 | memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t)); |
| 1278 | bv->byte_length = buffer.size() * sizeof(int32_t); |
| 1279 | } break; |
| 1280 | case COMPONENT_TYPE_FLOAT: { |
| 1281 | Vector<float> buffer; |
| 1282 | buffer.resize(p_count * component_count); |
| 1283 | int32_t dst_i = 0; |
| 1284 | for (int i = 0; i < p_count; i++) { |
| 1285 | for (int j = 0; j < component_count; j++) { |
| 1286 | if (skip_every && j > 0 && (j % skip_every) == 0) { |
| 1287 | dst_i += skip_bytes; |
| 1288 | } |
| 1289 | double d = *p_src; |
| 1290 | buffer.write[dst_i] = d; |
| 1291 | p_src++; |
| 1292 | dst_i++; |
| 1293 | } |
| 1294 | } |
| 1295 | int64_t old_size = gltf_buffer.size(); |
| 1296 | gltf_buffer.resize(old_size + (buffer.size() * sizeof(float))); |
| 1297 | memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float)); |
| 1298 | bv->byte_length = buffer.size() * sizeof(float); |
| 1299 | } break; |
| 1300 | } |
| 1301 | ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA); |
| 1302 | |
| 1303 | ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA); |
| 1304 | r_accessor = bv->buffer = p_state->buffer_views.size(); |
| 1305 | p_state->buffer_views.push_back(bv); |
| 1306 | return OK; |
| 1307 | } |
| 1308 | |
| 1309 | Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, const GLTFType p_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex) { |
| 1310 | const Ref<GLTFBufferView> bv = p_state->buffer_views[p_buffer_view]; |
| 1311 | |
| 1312 | int stride = p_element_size; |
| 1313 | if (bv->byte_stride != -1) { |
| 1314 | stride = bv->byte_stride; |
| 1315 | } |
| 1316 | if (p_for_vertex && stride % 4) { |
| 1317 | stride += 4 - (stride % 4); //according to spec must be multiple of 4 |
| 1318 | } |
| 1319 | |
| 1320 | ERR_FAIL_INDEX_V(bv->buffer, p_state->buffers.size(), ERR_PARSE_ERROR); |
| 1321 | |
| 1322 | const uint32_t offset = bv->byte_offset + p_byte_offset; |
| 1323 | Vector<uint8_t> buffer = p_state->buffers[bv->buffer]; //copy on write, so no performance hit |
| 1324 | const uint8_t *bufptr = buffer.ptr(); |
| 1325 | |
| 1326 | //use to debug |
| 1327 | print_verbose("glTF: type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); |
| 1328 | print_verbose("glTF: accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length)); |
| 1329 | |
| 1330 | const int buffer_end = (stride * (p_count - 1)) + p_element_size; |
| 1331 | ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_PARSE_ERROR); |
| 1332 | |
| 1333 | ERR_FAIL_COND_V((int)(offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR); |
| 1334 | |
| 1335 | //fill everything as doubles |
| 1336 | |
| 1337 | for (int i = 0; i < p_count; i++) { |
| 1338 | const uint8_t *src = &bufptr[offset + i * stride]; |
| 1339 | |
| 1340 | for (int j = 0; j < p_component_count; j++) { |
| 1341 | if (p_skip_every && j > 0 && (j % p_skip_every) == 0) { |
| 1342 | src += p_skip_bytes; |
| 1343 | } |
| 1344 | |
| 1345 | double d = 0; |
| 1346 | |
| 1347 | switch (p_component_type) { |
| 1348 | case COMPONENT_TYPE_BYTE: { |
| 1349 | int8_t b = int8_t(*src); |
| 1350 | if (p_normalized) { |
| 1351 | d = (double(b) / 128.0); |
| 1352 | } else { |
| 1353 | d = double(b); |
| 1354 | } |
| 1355 | } break; |
| 1356 | case COMPONENT_TYPE_UNSIGNED_BYTE: { |
| 1357 | uint8_t b = *src; |
| 1358 | if (p_normalized) { |
| 1359 | d = (double(b) / 255.0); |
| 1360 | } else { |
| 1361 | d = double(b); |
| 1362 | } |
| 1363 | } break; |
| 1364 | case COMPONENT_TYPE_SHORT: { |
| 1365 | int16_t s = *(int16_t *)src; |
| 1366 | if (p_normalized) { |
| 1367 | d = (double(s) / 32768.0); |
| 1368 | } else { |
| 1369 | d = double(s); |
| 1370 | } |
| 1371 | } break; |
| 1372 | case COMPONENT_TYPE_UNSIGNED_SHORT: { |
| 1373 | uint16_t s = *(uint16_t *)src; |
| 1374 | if (p_normalized) { |
| 1375 | d = (double(s) / 65535.0); |
| 1376 | } else { |
| 1377 | d = double(s); |
| 1378 | } |
| 1379 | } break; |
| 1380 | case COMPONENT_TYPE_INT: { |
| 1381 | d = *(int *)src; |
| 1382 | } break; |
| 1383 | case COMPONENT_TYPE_FLOAT: { |
| 1384 | d = *(float *)src; |
| 1385 | } break; |
| 1386 | } |
| 1387 | |
| 1388 | *p_dst++ = d; |
| 1389 | src += p_component_size; |
| 1390 | } |
| 1391 | } |
| 1392 | |
| 1393 | return OK; |
| 1394 | } |
| 1395 | |
| 1396 | int GLTFDocument::_get_component_type_size(const int p_component_type) { |
| 1397 | switch (p_component_type) { |
| 1398 | case COMPONENT_TYPE_BYTE: |
| 1399 | case COMPONENT_TYPE_UNSIGNED_BYTE: |
| 1400 | return 1; |
| 1401 | break; |
| 1402 | case COMPONENT_TYPE_SHORT: |
| 1403 | case COMPONENT_TYPE_UNSIGNED_SHORT: |
| 1404 | return 2; |
| 1405 | break; |
| 1406 | case COMPONENT_TYPE_INT: |
| 1407 | case COMPONENT_TYPE_FLOAT: |
| 1408 | return 4; |
| 1409 | break; |
| 1410 | default: { |
| 1411 | ERR_FAIL_V(0); |
| 1412 | } |
| 1413 | } |
| 1414 | return 0; |
| 1415 | } |
| 1416 | |
| 1417 | Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 1418 | //spec, for reference: |
| 1419 | //https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment |
| 1420 | |
| 1421 | ERR_FAIL_INDEX_V(p_accessor, p_state->accessors.size(), Vector<double>()); |
| 1422 | |
| 1423 | const Ref<GLTFAccessor> a = p_state->accessors[p_accessor]; |
| 1424 | |
| 1425 | const int component_count_for_type[7] = { |
| 1426 | 1, 2, 3, 4, 4, 9, 16 |
| 1427 | }; |
| 1428 | |
| 1429 | const int component_count = component_count_for_type[a->type]; |
| 1430 | const int component_size = _get_component_type_size(a->component_type); |
| 1431 | ERR_FAIL_COND_V(component_size == 0, Vector<double>()); |
| 1432 | int element_size = component_count * component_size; |
| 1433 | |
| 1434 | int skip_every = 0; |
| 1435 | int skip_bytes = 0; |
| 1436 | //special case of alignments, as described in spec |
| 1437 | switch (a->component_type) { |
| 1438 | case COMPONENT_TYPE_BYTE: |
| 1439 | case COMPONENT_TYPE_UNSIGNED_BYTE: { |
| 1440 | if (a->type == TYPE_MAT2) { |
| 1441 | skip_every = 2; |
| 1442 | skip_bytes = 2; |
| 1443 | element_size = 8; //override for this case |
| 1444 | } |
| 1445 | if (a->type == TYPE_MAT3) { |
| 1446 | skip_every = 3; |
| 1447 | skip_bytes = 1; |
| 1448 | element_size = 12; //override for this case |
| 1449 | } |
| 1450 | } break; |
| 1451 | case COMPONENT_TYPE_SHORT: |
| 1452 | case COMPONENT_TYPE_UNSIGNED_SHORT: { |
| 1453 | if (a->type == TYPE_MAT3) { |
| 1454 | skip_every = 6; |
| 1455 | skip_bytes = 4; |
| 1456 | element_size = 16; //override for this case |
| 1457 | } |
| 1458 | } break; |
| 1459 | default: { |
| 1460 | } |
| 1461 | } |
| 1462 | |
| 1463 | Vector<double> dst_buffer; |
| 1464 | dst_buffer.resize(component_count * a->count); |
| 1465 | double *dst = dst_buffer.ptrw(); |
| 1466 | |
| 1467 | if (a->buffer_view >= 0) { |
| 1468 | ERR_FAIL_INDEX_V(a->buffer_view, p_state->buffer_views.size(), Vector<double>()); |
| 1469 | |
| 1470 | const Error err = _decode_buffer_view(p_state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex); |
| 1471 | if (err != OK) { |
| 1472 | return Vector<double>(); |
| 1473 | } |
| 1474 | } else { |
| 1475 | //fill with zeros, as bufferview is not defined. |
| 1476 | for (int i = 0; i < (a->count * component_count); i++) { |
| 1477 | dst_buffer.write[i] = 0; |
| 1478 | } |
| 1479 | } |
| 1480 | |
| 1481 | if (a->sparse_count > 0) { |
| 1482 | // I could not find any file using this, so this code is so far untested |
| 1483 | Vector<double> indices; |
| 1484 | indices.resize(a->sparse_count); |
| 1485 | const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type); |
| 1486 | |
| 1487 | Error err = _decode_buffer_view(p_state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false); |
| 1488 | if (err != OK) { |
| 1489 | return Vector<double>(); |
| 1490 | } |
| 1491 | |
| 1492 | Vector<double> data; |
| 1493 | data.resize(component_count * a->sparse_count); |
| 1494 | err = _decode_buffer_view(p_state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex); |
| 1495 | if (err != OK) { |
| 1496 | return Vector<double>(); |
| 1497 | } |
| 1498 | |
| 1499 | for (int i = 0; i < indices.size(); i++) { |
| 1500 | const int write_offset = int(indices[i]) * component_count; |
| 1501 | |
| 1502 | for (int j = 0; j < component_count; j++) { |
| 1503 | dst[write_offset + j] = data[i * component_count + j]; |
| 1504 | } |
| 1505 | } |
| 1506 | } |
| 1507 | |
| 1508 | return dst_buffer; |
| 1509 | } |
| 1510 | |
| 1511 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, const Vector<int32_t> p_attribs, const bool p_for_vertex) { |
| 1512 | if (p_attribs.size() == 0) { |
| 1513 | return -1; |
| 1514 | } |
| 1515 | const int element_count = 1; |
| 1516 | const int ret_size = p_attribs.size(); |
| 1517 | Vector<double> attribs; |
| 1518 | attribs.resize(ret_size); |
| 1519 | Vector<double> type_max; |
| 1520 | type_max.resize(element_count); |
| 1521 | Vector<double> type_min; |
| 1522 | type_min.resize(element_count); |
| 1523 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1524 | attribs.write[i] = Math::snapped(p_attribs[i], 1.0); |
| 1525 | if (i == 0) { |
| 1526 | for (int32_t type_i = 0; type_i < element_count; type_i++) { |
| 1527 | type_max.write[type_i] = attribs[(i * element_count) + type_i]; |
| 1528 | type_min.write[type_i] = attribs[(i * element_count) + type_i]; |
| 1529 | } |
| 1530 | } |
| 1531 | for (int32_t type_i = 0; type_i < element_count; type_i++) { |
| 1532 | type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]); |
| 1533 | type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]); |
| 1534 | type_max.write[type_i] = _filter_number(type_max.write[type_i]); |
| 1535 | type_min.write[type_i] = _filter_number(type_min.write[type_i]); |
| 1536 | } |
| 1537 | } |
| 1538 | |
| 1539 | ERR_FAIL_COND_V(attribs.size() == 0, -1); |
| 1540 | |
| 1541 | Ref<GLTFAccessor> accessor; |
| 1542 | accessor.instantiate(); |
| 1543 | GLTFBufferIndex buffer_view_i; |
| 1544 | int64_t size = p_state->buffers[0].size(); |
| 1545 | const GLTFType type = GLTFType::TYPE_SCALAR; |
| 1546 | const int component_type = GLTFDocument::COMPONENT_TYPE_INT; |
| 1547 | |
| 1548 | accessor->max = type_max; |
| 1549 | accessor->min = type_min; |
| 1550 | accessor->normalized = false; |
| 1551 | accessor->count = ret_size; |
| 1552 | accessor->type = type; |
| 1553 | accessor->component_type = component_type; |
| 1554 | accessor->byte_offset = 0; |
| 1555 | Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1556 | if (err != OK) { |
| 1557 | return -1; |
| 1558 | } |
| 1559 | accessor->buffer_view = buffer_view_i; |
| 1560 | p_state->accessors.push_back(accessor); |
| 1561 | return p_state->accessors.size() - 1; |
| 1562 | } |
| 1563 | |
| 1564 | Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 1565 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 1566 | Vector<int> ret; |
| 1567 | |
| 1568 | if (attribs.size() == 0) { |
| 1569 | return ret; |
| 1570 | } |
| 1571 | |
| 1572 | const double *attribs_ptr = attribs.ptr(); |
| 1573 | const int ret_size = attribs.size(); |
| 1574 | ret.resize(ret_size); |
| 1575 | { |
| 1576 | for (int i = 0; i < ret_size; i++) { |
| 1577 | ret.write[i] = int(attribs_ptr[i]); |
| 1578 | } |
| 1579 | } |
| 1580 | return ret; |
| 1581 | } |
| 1582 | |
| 1583 | Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 1584 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 1585 | Vector<float> ret; |
| 1586 | |
| 1587 | if (attribs.size() == 0) { |
| 1588 | return ret; |
| 1589 | } |
| 1590 | |
| 1591 | const double *attribs_ptr = attribs.ptr(); |
| 1592 | const int ret_size = attribs.size(); |
| 1593 | ret.resize(ret_size); |
| 1594 | { |
| 1595 | for (int i = 0; i < ret_size; i++) { |
| 1596 | ret.write[i] = float(attribs_ptr[i]); |
| 1597 | } |
| 1598 | } |
| 1599 | return ret; |
| 1600 | } |
| 1601 | |
| 1602 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> p_state, const Vector<Vector2> p_attribs, const bool p_for_vertex) { |
| 1603 | if (p_attribs.size() == 0) { |
| 1604 | return -1; |
| 1605 | } |
| 1606 | const int element_count = 2; |
| 1607 | |
| 1608 | const int ret_size = p_attribs.size() * element_count; |
| 1609 | Vector<double> attribs; |
| 1610 | attribs.resize(ret_size); |
| 1611 | Vector<double> type_max; |
| 1612 | type_max.resize(element_count); |
| 1613 | Vector<double> type_min; |
| 1614 | type_min.resize(element_count); |
| 1615 | |
| 1616 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1617 | Vector2 attrib = p_attribs[i]; |
| 1618 | attribs.write[(i * element_count) + 0] = Math::snapped(attrib.x, CMP_NORMALIZE_TOLERANCE); |
| 1619 | attribs.write[(i * element_count) + 1] = Math::snapped(attrib.y, CMP_NORMALIZE_TOLERANCE); |
| 1620 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1621 | } |
| 1622 | |
| 1623 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 1624 | |
| 1625 | Ref<GLTFAccessor> accessor; |
| 1626 | accessor.instantiate(); |
| 1627 | GLTFBufferIndex buffer_view_i; |
| 1628 | int64_t size = p_state->buffers[0].size(); |
| 1629 | const GLTFType type = GLTFType::TYPE_VEC2; |
| 1630 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 1631 | |
| 1632 | accessor->max = type_max; |
| 1633 | accessor->min = type_min; |
| 1634 | accessor->normalized = false; |
| 1635 | accessor->count = p_attribs.size(); |
| 1636 | accessor->type = type; |
| 1637 | accessor->component_type = component_type; |
| 1638 | accessor->byte_offset = 0; |
| 1639 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1640 | if (err != OK) { |
| 1641 | return -1; |
| 1642 | } |
| 1643 | accessor->buffer_view = buffer_view_i; |
| 1644 | p_state->accessors.push_back(accessor); |
| 1645 | return p_state->accessors.size() - 1; |
| 1646 | } |
| 1647 | |
| 1648 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { |
| 1649 | if (p_attribs.size() == 0) { |
| 1650 | return -1; |
| 1651 | } |
| 1652 | |
| 1653 | const int ret_size = p_attribs.size() * 4; |
| 1654 | Vector<double> attribs; |
| 1655 | attribs.resize(ret_size); |
| 1656 | |
| 1657 | const int element_count = 4; |
| 1658 | Vector<double> type_max; |
| 1659 | type_max.resize(element_count); |
| 1660 | Vector<double> type_min; |
| 1661 | type_min.resize(element_count); |
| 1662 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1663 | Color attrib = p_attribs[i]; |
| 1664 | attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE); |
| 1665 | attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE); |
| 1666 | attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE); |
| 1667 | attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE); |
| 1668 | |
| 1669 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1670 | } |
| 1671 | |
| 1672 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 1673 | |
| 1674 | Ref<GLTFAccessor> accessor; |
| 1675 | accessor.instantiate(); |
| 1676 | GLTFBufferIndex buffer_view_i; |
| 1677 | int64_t size = p_state->buffers[0].size(); |
| 1678 | const GLTFType type = GLTFType::TYPE_VEC4; |
| 1679 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 1680 | |
| 1681 | accessor->max = type_max; |
| 1682 | accessor->min = type_min; |
| 1683 | accessor->normalized = false; |
| 1684 | accessor->count = p_attribs.size(); |
| 1685 | accessor->type = type; |
| 1686 | accessor->component_type = component_type; |
| 1687 | accessor->byte_offset = 0; |
| 1688 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1689 | if (err != OK) { |
| 1690 | return -1; |
| 1691 | } |
| 1692 | accessor->buffer_view = buffer_view_i; |
| 1693 | p_state->accessors.push_back(accessor); |
| 1694 | return p_state->accessors.size() - 1; |
| 1695 | } |
| 1696 | |
| 1697 | void GLTFDocument::_calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min) { |
| 1698 | if (p_i == 0) { |
| 1699 | for (int32_t type_i = 0; type_i < p_element_count; type_i++) { |
| 1700 | p_type_max.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; |
| 1701 | p_type_min.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; |
| 1702 | } |
| 1703 | } |
| 1704 | for (int32_t type_i = 0; type_i < p_element_count; type_i++) { |
| 1705 | p_type_max.write[type_i] = MAX(p_attribs[(p_i * p_element_count) + type_i], p_type_max[type_i]); |
| 1706 | p_type_min.write[type_i] = MIN(p_attribs[(p_i * p_element_count) + type_i], p_type_min[type_i]); |
| 1707 | p_type_max.write[type_i] = _filter_number(p_type_max.write[type_i]); |
| 1708 | p_type_min.write[type_i] = _filter_number(p_type_min.write[type_i]); |
| 1709 | } |
| 1710 | } |
| 1711 | |
| 1712 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { |
| 1713 | if (p_attribs.size() == 0) { |
| 1714 | return -1; |
| 1715 | } |
| 1716 | |
| 1717 | const int ret_size = p_attribs.size() * 4; |
| 1718 | Vector<double> attribs; |
| 1719 | attribs.resize(ret_size); |
| 1720 | |
| 1721 | const int element_count = 4; |
| 1722 | |
| 1723 | Vector<double> type_max; |
| 1724 | type_max.resize(element_count); |
| 1725 | Vector<double> type_min; |
| 1726 | type_min.resize(element_count); |
| 1727 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1728 | Color attrib = p_attribs[i]; |
| 1729 | attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE); |
| 1730 | attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE); |
| 1731 | attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE); |
| 1732 | attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE); |
| 1733 | |
| 1734 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1735 | } |
| 1736 | |
| 1737 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 1738 | |
| 1739 | Ref<GLTFAccessor> accessor; |
| 1740 | accessor.instantiate(); |
| 1741 | GLTFBufferIndex buffer_view_i; |
| 1742 | int64_t size = p_state->buffers[0].size(); |
| 1743 | const GLTFType type = GLTFType::TYPE_VEC4; |
| 1744 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 1745 | |
| 1746 | accessor->max = type_max; |
| 1747 | accessor->min = type_min; |
| 1748 | accessor->normalized = false; |
| 1749 | accessor->count = p_attribs.size(); |
| 1750 | accessor->type = type; |
| 1751 | accessor->component_type = component_type; |
| 1752 | accessor->byte_offset = 0; |
| 1753 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1754 | if (err != OK) { |
| 1755 | return -1; |
| 1756 | } |
| 1757 | accessor->buffer_view = buffer_view_i; |
| 1758 | p_state->accessors.push_back(accessor); |
| 1759 | return p_state->accessors.size() - 1; |
| 1760 | } |
| 1761 | |
| 1762 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { |
| 1763 | if (p_attribs.size() == 0) { |
| 1764 | return -1; |
| 1765 | } |
| 1766 | |
| 1767 | const int element_count = 4; |
| 1768 | const int ret_size = p_attribs.size() * element_count; |
| 1769 | Vector<double> attribs; |
| 1770 | attribs.resize(ret_size); |
| 1771 | |
| 1772 | Vector<double> type_max; |
| 1773 | type_max.resize(element_count); |
| 1774 | Vector<double> type_min; |
| 1775 | type_min.resize(element_count); |
| 1776 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1777 | Color attrib = p_attribs[i]; |
| 1778 | attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE); |
| 1779 | attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE); |
| 1780 | attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE); |
| 1781 | attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE); |
| 1782 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1783 | } |
| 1784 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 1785 | |
| 1786 | Ref<GLTFAccessor> accessor; |
| 1787 | accessor.instantiate(); |
| 1788 | GLTFBufferIndex buffer_view_i; |
| 1789 | int64_t size = p_state->buffers[0].size(); |
| 1790 | const GLTFType type = GLTFType::TYPE_VEC4; |
| 1791 | const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; |
| 1792 | |
| 1793 | accessor->max = type_max; |
| 1794 | accessor->min = type_min; |
| 1795 | accessor->normalized = false; |
| 1796 | accessor->count = p_attribs.size(); |
| 1797 | accessor->type = type; |
| 1798 | accessor->component_type = component_type; |
| 1799 | accessor->byte_offset = 0; |
| 1800 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1801 | if (err != OK) { |
| 1802 | return -1; |
| 1803 | } |
| 1804 | accessor->buffer_view = buffer_view_i; |
| 1805 | p_state->accessors.push_back(accessor); |
| 1806 | return p_state->accessors.size() - 1; |
| 1807 | } |
| 1808 | |
| 1809 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p_state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) { |
| 1810 | if (p_attribs.size() == 0) { |
| 1811 | return -1; |
| 1812 | } |
| 1813 | const int element_count = 4; |
| 1814 | |
| 1815 | const int ret_size = p_attribs.size() * element_count; |
| 1816 | Vector<double> attribs; |
| 1817 | attribs.resize(ret_size); |
| 1818 | |
| 1819 | Vector<double> type_max; |
| 1820 | type_max.resize(element_count); |
| 1821 | Vector<double> type_min; |
| 1822 | type_min.resize(element_count); |
| 1823 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1824 | Quaternion quaternion = p_attribs[i]; |
| 1825 | attribs.write[(i * element_count) + 0] = Math::snapped(quaternion.x, CMP_NORMALIZE_TOLERANCE); |
| 1826 | attribs.write[(i * element_count) + 1] = Math::snapped(quaternion.y, CMP_NORMALIZE_TOLERANCE); |
| 1827 | attribs.write[(i * element_count) + 2] = Math::snapped(quaternion.z, CMP_NORMALIZE_TOLERANCE); |
| 1828 | attribs.write[(i * element_count) + 3] = Math::snapped(quaternion.w, CMP_NORMALIZE_TOLERANCE); |
| 1829 | |
| 1830 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1831 | } |
| 1832 | |
| 1833 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 1834 | |
| 1835 | Ref<GLTFAccessor> accessor; |
| 1836 | accessor.instantiate(); |
| 1837 | GLTFBufferIndex buffer_view_i; |
| 1838 | int64_t size = p_state->buffers[0].size(); |
| 1839 | const GLTFType type = GLTFType::TYPE_VEC4; |
| 1840 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 1841 | |
| 1842 | accessor->max = type_max; |
| 1843 | accessor->min = type_min; |
| 1844 | accessor->normalized = false; |
| 1845 | accessor->count = p_attribs.size(); |
| 1846 | accessor->type = type; |
| 1847 | accessor->component_type = component_type; |
| 1848 | accessor->byte_offset = 0; |
| 1849 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1850 | if (err != OK) { |
| 1851 | return -1; |
| 1852 | } |
| 1853 | accessor->buffer_view = buffer_view_i; |
| 1854 | p_state->accessors.push_back(accessor); |
| 1855 | return p_state->accessors.size() - 1; |
| 1856 | } |
| 1857 | |
| 1858 | Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 1859 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 1860 | Vector<Vector2> ret; |
| 1861 | |
| 1862 | if (attribs.size() == 0) { |
| 1863 | return ret; |
| 1864 | } |
| 1865 | |
| 1866 | ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret); |
| 1867 | const double *attribs_ptr = attribs.ptr(); |
| 1868 | const int ret_size = attribs.size() / 2; |
| 1869 | ret.resize(ret_size); |
| 1870 | { |
| 1871 | for (int i = 0; i < ret_size; i++) { |
| 1872 | ret.write[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]); |
| 1873 | } |
| 1874 | } |
| 1875 | return ret; |
| 1876 | } |
| 1877 | |
| 1878 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> p_state, const Vector<real_t> p_attribs, const bool p_for_vertex) { |
| 1879 | if (p_attribs.size() == 0) { |
| 1880 | return -1; |
| 1881 | } |
| 1882 | const int element_count = 1; |
| 1883 | const int ret_size = p_attribs.size(); |
| 1884 | Vector<double> attribs; |
| 1885 | attribs.resize(ret_size); |
| 1886 | |
| 1887 | Vector<double> type_max; |
| 1888 | type_max.resize(element_count); |
| 1889 | Vector<double> type_min; |
| 1890 | type_min.resize(element_count); |
| 1891 | |
| 1892 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1893 | attribs.write[i] = Math::snapped(p_attribs[i], CMP_NORMALIZE_TOLERANCE); |
| 1894 | |
| 1895 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1896 | } |
| 1897 | |
| 1898 | ERR_FAIL_COND_V(!attribs.size(), -1); |
| 1899 | |
| 1900 | Ref<GLTFAccessor> accessor; |
| 1901 | accessor.instantiate(); |
| 1902 | GLTFBufferIndex buffer_view_i; |
| 1903 | int64_t size = p_state->buffers[0].size(); |
| 1904 | const GLTFType type = GLTFType::TYPE_SCALAR; |
| 1905 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 1906 | |
| 1907 | accessor->max = type_max; |
| 1908 | accessor->min = type_min; |
| 1909 | accessor->normalized = false; |
| 1910 | accessor->count = ret_size; |
| 1911 | accessor->type = type; |
| 1912 | accessor->component_type = component_type; |
| 1913 | accessor->byte_offset = 0; |
| 1914 | Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1915 | if (err != OK) { |
| 1916 | return -1; |
| 1917 | } |
| 1918 | accessor->buffer_view = buffer_view_i; |
| 1919 | p_state->accessors.push_back(accessor); |
| 1920 | return p_state->accessors.size() - 1; |
| 1921 | } |
| 1922 | |
| 1923 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const bool p_for_vertex) { |
| 1924 | if (p_attribs.size() == 0) { |
| 1925 | return -1; |
| 1926 | } |
| 1927 | const int element_count = 3; |
| 1928 | const int ret_size = p_attribs.size() * element_count; |
| 1929 | Vector<double> attribs; |
| 1930 | attribs.resize(ret_size); |
| 1931 | |
| 1932 | Vector<double> type_max; |
| 1933 | type_max.resize(element_count); |
| 1934 | Vector<double> type_min; |
| 1935 | type_min.resize(element_count); |
| 1936 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1937 | Vector3 attrib = p_attribs[i]; |
| 1938 | attribs.write[(i * element_count) + 0] = Math::snapped(attrib.x, CMP_NORMALIZE_TOLERANCE); |
| 1939 | attribs.write[(i * element_count) + 1] = Math::snapped(attrib.y, CMP_NORMALIZE_TOLERANCE); |
| 1940 | attribs.write[(i * element_count) + 2] = Math::snapped(attrib.z, CMP_NORMALIZE_TOLERANCE); |
| 1941 | |
| 1942 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 1943 | } |
| 1944 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 1945 | |
| 1946 | Ref<GLTFAccessor> accessor; |
| 1947 | accessor.instantiate(); |
| 1948 | GLTFBufferIndex buffer_view_i; |
| 1949 | int64_t size = p_state->buffers[0].size(); |
| 1950 | const GLTFType type = GLTFType::TYPE_VEC3; |
| 1951 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 1952 | |
| 1953 | accessor->max = type_max; |
| 1954 | accessor->min = type_min; |
| 1955 | accessor->normalized = false; |
| 1956 | accessor->count = p_attribs.size(); |
| 1957 | accessor->type = type; |
| 1958 | accessor->component_type = component_type; |
| 1959 | accessor->byte_offset = 0; |
| 1960 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 1961 | if (err != OK) { |
| 1962 | return -1; |
| 1963 | } |
| 1964 | accessor->buffer_view = buffer_view_i; |
| 1965 | p_state->accessors.push_back(accessor); |
| 1966 | return p_state->accessors.size() - 1; |
| 1967 | } |
| 1968 | |
| 1969 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) { |
| 1970 | if (p_attribs.size() == 0) { |
| 1971 | return -1; |
| 1972 | } |
| 1973 | const int element_count = 16; |
| 1974 | const int ret_size = p_attribs.size() * element_count; |
| 1975 | Vector<double> attribs; |
| 1976 | attribs.resize(ret_size); |
| 1977 | |
| 1978 | Vector<double> type_max; |
| 1979 | type_max.resize(element_count); |
| 1980 | Vector<double> type_min; |
| 1981 | type_min.resize(element_count); |
| 1982 | for (int i = 0; i < p_attribs.size(); i++) { |
| 1983 | Transform3D attrib = p_attribs[i]; |
| 1984 | Basis basis = attrib.get_basis(); |
| 1985 | Vector3 axis_0 = basis.get_column(Vector3::AXIS_X); |
| 1986 | |
| 1987 | attribs.write[i * element_count + 0] = Math::snapped(axis_0.x, CMP_NORMALIZE_TOLERANCE); |
| 1988 | attribs.write[i * element_count + 1] = Math::snapped(axis_0.y, CMP_NORMALIZE_TOLERANCE); |
| 1989 | attribs.write[i * element_count + 2] = Math::snapped(axis_0.z, CMP_NORMALIZE_TOLERANCE); |
| 1990 | attribs.write[i * element_count + 3] = 0.0; |
| 1991 | |
| 1992 | Vector3 axis_1 = basis.get_column(Vector3::AXIS_Y); |
| 1993 | attribs.write[i * element_count + 4] = Math::snapped(axis_1.x, CMP_NORMALIZE_TOLERANCE); |
| 1994 | attribs.write[i * element_count + 5] = Math::snapped(axis_1.y, CMP_NORMALIZE_TOLERANCE); |
| 1995 | attribs.write[i * element_count + 6] = Math::snapped(axis_1.z, CMP_NORMALIZE_TOLERANCE); |
| 1996 | attribs.write[i * element_count + 7] = 0.0; |
| 1997 | |
| 1998 | Vector3 axis_2 = basis.get_column(Vector3::AXIS_Z); |
| 1999 | attribs.write[i * element_count + 8] = Math::snapped(axis_2.x, CMP_NORMALIZE_TOLERANCE); |
| 2000 | attribs.write[i * element_count + 9] = Math::snapped(axis_2.y, CMP_NORMALIZE_TOLERANCE); |
| 2001 | attribs.write[i * element_count + 10] = Math::snapped(axis_2.z, CMP_NORMALIZE_TOLERANCE); |
| 2002 | attribs.write[i * element_count + 11] = 0.0; |
| 2003 | |
| 2004 | Vector3 origin = attrib.get_origin(); |
| 2005 | attribs.write[i * element_count + 12] = Math::snapped(origin.x, CMP_NORMALIZE_TOLERANCE); |
| 2006 | attribs.write[i * element_count + 13] = Math::snapped(origin.y, CMP_NORMALIZE_TOLERANCE); |
| 2007 | attribs.write[i * element_count + 14] = Math::snapped(origin.z, CMP_NORMALIZE_TOLERANCE); |
| 2008 | attribs.write[i * element_count + 15] = 1.0; |
| 2009 | |
| 2010 | _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); |
| 2011 | } |
| 2012 | ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); |
| 2013 | |
| 2014 | Ref<GLTFAccessor> accessor; |
| 2015 | accessor.instantiate(); |
| 2016 | GLTFBufferIndex buffer_view_i; |
| 2017 | int64_t size = p_state->buffers[0].size(); |
| 2018 | const GLTFType type = GLTFType::TYPE_MAT4; |
| 2019 | const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; |
| 2020 | |
| 2021 | accessor->max = type_max; |
| 2022 | accessor->min = type_min; |
| 2023 | accessor->normalized = false; |
| 2024 | accessor->count = p_attribs.size(); |
| 2025 | accessor->type = type; |
| 2026 | accessor->component_type = component_type; |
| 2027 | accessor->byte_offset = 0; |
| 2028 | Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); |
| 2029 | if (err != OK) { |
| 2030 | return -1; |
| 2031 | } |
| 2032 | accessor->buffer_view = buffer_view_i; |
| 2033 | p_state->accessors.push_back(accessor); |
| 2034 | return p_state->accessors.size() - 1; |
| 2035 | } |
| 2036 | |
| 2037 | Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 2038 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 2039 | Vector<Vector3> ret; |
| 2040 | |
| 2041 | if (attribs.size() == 0) { |
| 2042 | return ret; |
| 2043 | } |
| 2044 | |
| 2045 | ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret); |
| 2046 | const double *attribs_ptr = attribs.ptr(); |
| 2047 | const int ret_size = attribs.size() / 3; |
| 2048 | ret.resize(ret_size); |
| 2049 | { |
| 2050 | for (int i = 0; i < ret_size; i++) { |
| 2051 | ret.write[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]); |
| 2052 | } |
| 2053 | } |
| 2054 | return ret; |
| 2055 | } |
| 2056 | |
| 2057 | Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 2058 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 2059 | Vector<Color> ret; |
| 2060 | |
| 2061 | if (attribs.size() == 0) { |
| 2062 | return ret; |
| 2063 | } |
| 2064 | |
| 2065 | const int type = p_state->accessors[p_accessor]->type; |
| 2066 | ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret); |
| 2067 | int vec_len = 3; |
| 2068 | if (type == TYPE_VEC4) { |
| 2069 | vec_len = 4; |
| 2070 | } |
| 2071 | |
| 2072 | ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret); |
| 2073 | const double *attribs_ptr = attribs.ptr(); |
| 2074 | const int ret_size = attribs.size() / vec_len; |
| 2075 | ret.resize(ret_size); |
| 2076 | { |
| 2077 | for (int i = 0; i < ret_size; i++) { |
| 2078 | ret.write[i] = Color(attribs_ptr[i * vec_len + 0], attribs_ptr[i * vec_len + 1], attribs_ptr[i * vec_len + 2], vec_len == 4 ? attribs_ptr[i * 4 + 3] : 1.0); |
| 2079 | } |
| 2080 | } |
| 2081 | return ret; |
| 2082 | } |
| 2083 | Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 2084 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 2085 | Vector<Quaternion> ret; |
| 2086 | |
| 2087 | if (attribs.size() == 0) { |
| 2088 | return ret; |
| 2089 | } |
| 2090 | |
| 2091 | ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); |
| 2092 | const double *attribs_ptr = attribs.ptr(); |
| 2093 | const int ret_size = attribs.size() / 4; |
| 2094 | ret.resize(ret_size); |
| 2095 | { |
| 2096 | for (int i = 0; i < ret_size; i++) { |
| 2097 | 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(); |
| 2098 | } |
| 2099 | } |
| 2100 | return ret; |
| 2101 | } |
| 2102 | Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 2103 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 2104 | Vector<Transform2D> ret; |
| 2105 | |
| 2106 | if (attribs.size() == 0) { |
| 2107 | return ret; |
| 2108 | } |
| 2109 | |
| 2110 | ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); |
| 2111 | ret.resize(attribs.size() / 4); |
| 2112 | for (int i = 0; i < ret.size(); i++) { |
| 2113 | ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]); |
| 2114 | ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]); |
| 2115 | } |
| 2116 | return ret; |
| 2117 | } |
| 2118 | |
| 2119 | Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 2120 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 2121 | Vector<Basis> ret; |
| 2122 | |
| 2123 | if (attribs.size() == 0) { |
| 2124 | return ret; |
| 2125 | } |
| 2126 | |
| 2127 | ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); |
| 2128 | ret.resize(attribs.size() / 9); |
| 2129 | for (int i = 0; i < ret.size(); i++) { |
| 2130 | ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); |
| 2131 | ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); |
| 2132 | ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); |
| 2133 | } |
| 2134 | return ret; |
| 2135 | } |
| 2136 | |
| 2137 | Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { |
| 2138 | const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); |
| 2139 | Vector<Transform3D> ret; |
| 2140 | |
| 2141 | if (attribs.size() == 0) { |
| 2142 | return ret; |
| 2143 | } |
| 2144 | |
| 2145 | ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); |
| 2146 | ret.resize(attribs.size() / 16); |
| 2147 | for (int i = 0; i < ret.size(); i++) { |
| 2148 | ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); |
| 2149 | ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); |
| 2150 | ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); |
| 2151 | ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); |
| 2152 | } |
| 2153 | return ret; |
| 2154 | } |
| 2155 | |
| 2156 | Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) { |
| 2157 | Array meshes; |
| 2158 | for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < p_state->meshes.size(); gltf_mesh_i++) { |
| 2159 | print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i)); |
| 2160 | Ref<ImporterMesh> import_mesh = p_state->meshes.write[gltf_mesh_i]->get_mesh(); |
| 2161 | if (import_mesh.is_null()) { |
| 2162 | continue; |
| 2163 | } |
| 2164 | Array instance_materials = p_state->meshes.write[gltf_mesh_i]->get_instance_materials(); |
| 2165 | Array primitives; |
| 2166 | Dictionary gltf_mesh; |
| 2167 | Array target_names; |
| 2168 | Array weights; |
| 2169 | for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { |
| 2170 | target_names.push_back(import_mesh->get_blend_shape_name(morph_i)); |
| 2171 | } |
| 2172 | for (int surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) { |
| 2173 | Array targets; |
| 2174 | Dictionary primitive; |
| 2175 | Mesh::PrimitiveType primitive_type = import_mesh->get_surface_primitive_type(surface_i); |
| 2176 | switch (primitive_type) { |
| 2177 | case Mesh::PRIMITIVE_POINTS: { |
| 2178 | primitive["mode" ] = 0; |
| 2179 | break; |
| 2180 | } |
| 2181 | case Mesh::PRIMITIVE_LINES: { |
| 2182 | primitive["mode" ] = 1; |
| 2183 | break; |
| 2184 | } |
| 2185 | // case Mesh::PRIMITIVE_LINE_LOOP: { |
| 2186 | // primitive["mode"] = 2; |
| 2187 | // break; |
| 2188 | // } |
| 2189 | case Mesh::PRIMITIVE_LINE_STRIP: { |
| 2190 | primitive["mode" ] = 3; |
| 2191 | break; |
| 2192 | } |
| 2193 | case Mesh::PRIMITIVE_TRIANGLES: { |
| 2194 | primitive["mode" ] = 4; |
| 2195 | break; |
| 2196 | } |
| 2197 | case Mesh::PRIMITIVE_TRIANGLE_STRIP: { |
| 2198 | primitive["mode" ] = 5; |
| 2199 | break; |
| 2200 | } |
| 2201 | // case Mesh::PRIMITIVE_TRIANGLE_FAN: { |
| 2202 | // primitive["mode"] = 6; |
| 2203 | // break; |
| 2204 | // } |
| 2205 | default: { |
| 2206 | ERR_FAIL_V(FAILED); |
| 2207 | } |
| 2208 | } |
| 2209 | |
| 2210 | Array array = import_mesh->get_surface_arrays(surface_i); |
| 2211 | uint32_t format = import_mesh->get_surface_format(surface_i); |
| 2212 | int32_t vertex_num = 0; |
| 2213 | Dictionary attributes; |
| 2214 | { |
| 2215 | Vector<Vector3> a = array[Mesh::ARRAY_VERTEX]; |
| 2216 | ERR_FAIL_COND_V(!a.size(), ERR_INVALID_DATA); |
| 2217 | attributes["POSITION" ] = _encode_accessor_as_vec3(p_state, a, true); |
| 2218 | vertex_num = a.size(); |
| 2219 | } |
| 2220 | { |
| 2221 | Vector<real_t> a = array[Mesh::ARRAY_TANGENT]; |
| 2222 | if (a.size()) { |
| 2223 | const int ret_size = a.size() / 4; |
| 2224 | Vector<Color> attribs; |
| 2225 | attribs.resize(ret_size); |
| 2226 | for (int i = 0; i < ret_size; i++) { |
| 2227 | Color out; |
| 2228 | out.r = a[(i * 4) + 0]; |
| 2229 | out.g = a[(i * 4) + 1]; |
| 2230 | out.b = a[(i * 4) + 2]; |
| 2231 | out.a = a[(i * 4) + 3]; |
| 2232 | attribs.write[i] = out; |
| 2233 | } |
| 2234 | attributes["TANGENT" ] = _encode_accessor_as_color(p_state, attribs, true); |
| 2235 | } |
| 2236 | } |
| 2237 | { |
| 2238 | Vector<Vector3> a = array[Mesh::ARRAY_NORMAL]; |
| 2239 | if (a.size()) { |
| 2240 | const int ret_size = a.size(); |
| 2241 | Vector<Vector3> attribs; |
| 2242 | attribs.resize(ret_size); |
| 2243 | for (int i = 0; i < ret_size; i++) { |
| 2244 | attribs.write[i] = Vector3(a[i]).normalized(); |
| 2245 | } |
| 2246 | attributes["NORMAL" ] = _encode_accessor_as_vec3(p_state, attribs, true); |
| 2247 | } |
| 2248 | } |
| 2249 | { |
| 2250 | Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV]; |
| 2251 | if (a.size()) { |
| 2252 | attributes["TEXCOORD_0" ] = _encode_accessor_as_vec2(p_state, a, true); |
| 2253 | } |
| 2254 | } |
| 2255 | { |
| 2256 | Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV2]; |
| 2257 | if (a.size()) { |
| 2258 | attributes["TEXCOORD_1" ] = _encode_accessor_as_vec2(p_state, a, true); |
| 2259 | } |
| 2260 | } |
| 2261 | for (int custom_i = 0; custom_i < 3; custom_i++) { |
| 2262 | Vector<float> a = array[Mesh::ARRAY_CUSTOM0 + custom_i]; |
| 2263 | if (a.size()) { |
| 2264 | int num_channels = 4; |
| 2265 | int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + custom_i * Mesh::ARRAY_FORMAT_CUSTOM_BITS; |
| 2266 | switch ((format >> custom_shift) & Mesh::ARRAY_FORMAT_CUSTOM_MASK) { |
| 2267 | case Mesh::ARRAY_CUSTOM_R_FLOAT: |
| 2268 | num_channels = 1; |
| 2269 | break; |
| 2270 | case Mesh::ARRAY_CUSTOM_RG_FLOAT: |
| 2271 | num_channels = 2; |
| 2272 | break; |
| 2273 | case Mesh::ARRAY_CUSTOM_RGB_FLOAT: |
| 2274 | num_channels = 3; |
| 2275 | break; |
| 2276 | case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: |
| 2277 | num_channels = 4; |
| 2278 | break; |
| 2279 | } |
| 2280 | int texcoord_i = 2 + 2 * custom_i; |
| 2281 | String gltf_texcoord_key; |
| 2282 | for (int prev_texcoord_i = 0; prev_texcoord_i < texcoord_i; prev_texcoord_i++) { |
| 2283 | gltf_texcoord_key = vformat("TEXCOORD_%d" , prev_texcoord_i); |
| 2284 | if (!attributes.has(gltf_texcoord_key)) { |
| 2285 | Vector<Vector2> empty; |
| 2286 | empty.resize(vertex_num); |
| 2287 | attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, empty, true); |
| 2288 | } |
| 2289 | } |
| 2290 | |
| 2291 | LocalVector<Vector2> first_channel; |
| 2292 | first_channel.resize(vertex_num); |
| 2293 | LocalVector<Vector2> second_channel; |
| 2294 | second_channel.resize(vertex_num); |
| 2295 | for (int32_t vert_i = 0; vert_i < vertex_num; vert_i++) { |
| 2296 | float u = a[vert_i * num_channels + 0]; |
| 2297 | float v = (num_channels == 1 ? 0.0f : a[vert_i * num_channels + 1]); |
| 2298 | first_channel[vert_i] = Vector2(u, v); |
| 2299 | u = 0; |
| 2300 | v = 0; |
| 2301 | if (num_channels >= 3) { |
| 2302 | u = a[vert_i * num_channels + 2]; |
| 2303 | v = (num_channels == 3 ? 0.0f : a[vert_i * num_channels + 3]); |
| 2304 | second_channel[vert_i] = Vector2(u, v); |
| 2305 | } |
| 2306 | } |
| 2307 | gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i); |
| 2308 | attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, first_channel, true); |
| 2309 | gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i + 1); |
| 2310 | attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, second_channel, true); |
| 2311 | } |
| 2312 | } |
| 2313 | { |
| 2314 | Vector<Color> a = array[Mesh::ARRAY_COLOR]; |
| 2315 | if (a.size()) { |
| 2316 | attributes["COLOR_0" ] = _encode_accessor_as_color(p_state, a, true); |
| 2317 | } |
| 2318 | } |
| 2319 | HashMap<int, int> joint_i_to_bone_i; |
| 2320 | for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { |
| 2321 | GLTFSkinIndex skin_i = -1; |
| 2322 | if (p_state->nodes[node_i]->mesh == gltf_mesh_i) { |
| 2323 | skin_i = p_state->nodes[node_i]->skin; |
| 2324 | } |
| 2325 | if (skin_i != -1) { |
| 2326 | joint_i_to_bone_i = p_state->skins[skin_i]->joint_i_to_bone_i; |
| 2327 | break; |
| 2328 | } |
| 2329 | } |
| 2330 | { |
| 2331 | const Array &a = array[Mesh::ARRAY_BONES]; |
| 2332 | const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX]; |
| 2333 | if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) { |
| 2334 | const int ret_size = a.size() / JOINT_GROUP_SIZE; |
| 2335 | Vector<Color> attribs; |
| 2336 | attribs.resize(ret_size); |
| 2337 | { |
| 2338 | for (int array_i = 0; array_i < attribs.size(); array_i++) { |
| 2339 | int32_t joint_0 = a[(array_i * JOINT_GROUP_SIZE) + 0]; |
| 2340 | int32_t joint_1 = a[(array_i * JOINT_GROUP_SIZE) + 1]; |
| 2341 | int32_t joint_2 = a[(array_i * JOINT_GROUP_SIZE) + 2]; |
| 2342 | int32_t joint_3 = a[(array_i * JOINT_GROUP_SIZE) + 3]; |
| 2343 | attribs.write[array_i] = Color(joint_0, joint_1, joint_2, joint_3); |
| 2344 | } |
| 2345 | } |
| 2346 | attributes["JOINTS_0" ] = _encode_accessor_as_joints(p_state, attribs, true); |
| 2347 | } else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) { |
| 2348 | Vector<Color> joints_0; |
| 2349 | joints_0.resize(vertex_num); |
| 2350 | Vector<Color> joints_1; |
| 2351 | joints_1.resize(vertex_num); |
| 2352 | int32_t weights_8_count = JOINT_GROUP_SIZE * 2; |
| 2353 | for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { |
| 2354 | Color joint_0; |
| 2355 | joint_0.r = a[vertex_i * weights_8_count + 0]; |
| 2356 | joint_0.g = a[vertex_i * weights_8_count + 1]; |
| 2357 | joint_0.b = a[vertex_i * weights_8_count + 2]; |
| 2358 | joint_0.a = a[vertex_i * weights_8_count + 3]; |
| 2359 | joints_0.write[vertex_i] = joint_0; |
| 2360 | Color joint_1; |
| 2361 | joint_1.r = a[vertex_i * weights_8_count + 4]; |
| 2362 | joint_1.g = a[vertex_i * weights_8_count + 5]; |
| 2363 | joint_1.b = a[vertex_i * weights_8_count + 6]; |
| 2364 | joint_1.a = a[vertex_i * weights_8_count + 7]; |
| 2365 | joints_1.write[vertex_i] = joint_1; |
| 2366 | } |
| 2367 | attributes["JOINTS_0" ] = _encode_accessor_as_joints(p_state, joints_0, true); |
| 2368 | attributes["JOINTS_1" ] = _encode_accessor_as_joints(p_state, joints_1, true); |
| 2369 | } |
| 2370 | } |
| 2371 | { |
| 2372 | const Array &a = array[Mesh::ARRAY_WEIGHTS]; |
| 2373 | const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX]; |
| 2374 | if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) { |
| 2375 | int32_t vertex_count = vertex_array.size(); |
| 2376 | Vector<Color> attribs; |
| 2377 | attribs.resize(vertex_count); |
| 2378 | for (int i = 0; i < vertex_count; i++) { |
| 2379 | attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]); |
| 2380 | } |
| 2381 | attributes["WEIGHTS_0" ] = _encode_accessor_as_weights(p_state, attribs, true); |
| 2382 | } else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) { |
| 2383 | Vector<Color> weights_0; |
| 2384 | weights_0.resize(vertex_num); |
| 2385 | Vector<Color> weights_1; |
| 2386 | weights_1.resize(vertex_num); |
| 2387 | int32_t weights_8_count = JOINT_GROUP_SIZE * 2; |
| 2388 | for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { |
| 2389 | Color weight_0; |
| 2390 | weight_0.r = a[vertex_i * weights_8_count + 0]; |
| 2391 | weight_0.g = a[vertex_i * weights_8_count + 1]; |
| 2392 | weight_0.b = a[vertex_i * weights_8_count + 2]; |
| 2393 | weight_0.a = a[vertex_i * weights_8_count + 3]; |
| 2394 | weights_0.write[vertex_i] = weight_0; |
| 2395 | Color weight_1; |
| 2396 | weight_1.r = a[vertex_i * weights_8_count + 4]; |
| 2397 | weight_1.g = a[vertex_i * weights_8_count + 5]; |
| 2398 | weight_1.b = a[vertex_i * weights_8_count + 6]; |
| 2399 | weight_1.a = a[vertex_i * weights_8_count + 7]; |
| 2400 | weights_1.write[vertex_i] = weight_1; |
| 2401 | } |
| 2402 | attributes["WEIGHTS_0" ] = _encode_accessor_as_weights(p_state, weights_0, true); |
| 2403 | attributes["WEIGHTS_1" ] = _encode_accessor_as_weights(p_state, weights_1, true); |
| 2404 | } |
| 2405 | } |
| 2406 | { |
| 2407 | Vector<int32_t> mesh_indices = array[Mesh::ARRAY_INDEX]; |
| 2408 | if (mesh_indices.size()) { |
| 2409 | if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) { |
| 2410 | //swap around indices, convert ccw to cw for front face |
| 2411 | const int is = mesh_indices.size(); |
| 2412 | for (int k = 0; k < is; k += 3) { |
| 2413 | SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]); |
| 2414 | } |
| 2415 | } |
| 2416 | primitive["indices" ] = _encode_accessor_as_ints(p_state, mesh_indices, true); |
| 2417 | } else { |
| 2418 | if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) { |
| 2419 | //generate indices because they need to be swapped for CW/CCW |
| 2420 | const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; |
| 2421 | Ref<SurfaceTool> st; |
| 2422 | st.instantiate(); |
| 2423 | st->create_from_triangle_arrays(array); |
| 2424 | st->index(); |
| 2425 | Vector<int32_t> generated_indices = st->commit_to_arrays()[Mesh::ARRAY_INDEX]; |
| 2426 | const int vs = vertices.size(); |
| 2427 | generated_indices.resize(vs); |
| 2428 | { |
| 2429 | for (int k = 0; k < vs; k += 3) { |
| 2430 | generated_indices.write[k] = k; |
| 2431 | generated_indices.write[k + 1] = k + 2; |
| 2432 | generated_indices.write[k + 2] = k + 1; |
| 2433 | } |
| 2434 | } |
| 2435 | primitive["indices" ] = _encode_accessor_as_ints(p_state, generated_indices, true); |
| 2436 | } |
| 2437 | } |
| 2438 | } |
| 2439 | |
| 2440 | primitive["attributes" ] = attributes; |
| 2441 | |
| 2442 | //blend shapes |
| 2443 | print_verbose("glTF: Mesh has targets" ); |
| 2444 | if (import_mesh->get_blend_shape_count()) { |
| 2445 | ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode(); |
| 2446 | for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { |
| 2447 | Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i); |
| 2448 | Dictionary t; |
| 2449 | Vector<Vector3> varr = array_morph[Mesh::ARRAY_VERTEX]; |
| 2450 | Array mesh_arrays = import_mesh->get_surface_arrays(surface_i); |
| 2451 | if (varr.size()) { |
| 2452 | Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; |
| 2453 | if (shape_mode == ArrayMesh::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED) { |
| 2454 | const int max_idx = src_varr.size(); |
| 2455 | for (int blend_i = 0; blend_i < max_idx; blend_i++) { |
| 2456 | varr.write[blend_i] = Vector3(varr[blend_i]) - src_varr[blend_i]; |
| 2457 | } |
| 2458 | } |
| 2459 | |
| 2460 | t["POSITION" ] = _encode_accessor_as_vec3(p_state, varr, true); |
| 2461 | } |
| 2462 | |
| 2463 | Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL]; |
| 2464 | if (narr.size()) { |
| 2465 | t["NORMAL" ] = _encode_accessor_as_vec3(p_state, narr, true); |
| 2466 | } |
| 2467 | Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT]; |
| 2468 | if (tarr.size()) { |
| 2469 | const int ret_size = tarr.size() / 4; |
| 2470 | Vector<Vector3> attribs; |
| 2471 | attribs.resize(ret_size); |
| 2472 | for (int i = 0; i < ret_size; i++) { |
| 2473 | Vector3 vec3; |
| 2474 | vec3.x = tarr[(i * 4) + 0]; |
| 2475 | vec3.y = tarr[(i * 4) + 1]; |
| 2476 | vec3.z = tarr[(i * 4) + 2]; |
| 2477 | } |
| 2478 | t["TANGENT" ] = _encode_accessor_as_vec3(p_state, attribs, true); |
| 2479 | } |
| 2480 | targets.push_back(t); |
| 2481 | } |
| 2482 | } |
| 2483 | |
| 2484 | Variant v; |
| 2485 | if (surface_i < instance_materials.size()) { |
| 2486 | v = instance_materials.get(surface_i); |
| 2487 | } |
| 2488 | Ref<Material> mat = v; |
| 2489 | if (!mat.is_valid()) { |
| 2490 | mat = import_mesh->get_surface_material(surface_i); |
| 2491 | } |
| 2492 | if (mat.is_valid()) { |
| 2493 | HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = p_state->material_cache.find(mat); |
| 2494 | if (material_cache_i && material_cache_i->value != -1) { |
| 2495 | primitive["material" ] = material_cache_i->value; |
| 2496 | } else { |
| 2497 | GLTFMaterialIndex mat_i = p_state->materials.size(); |
| 2498 | p_state->materials.push_back(mat); |
| 2499 | primitive["material" ] = mat_i; |
| 2500 | p_state->material_cache.insert(mat, mat_i); |
| 2501 | } |
| 2502 | } |
| 2503 | |
| 2504 | if (targets.size()) { |
| 2505 | primitive["targets" ] = targets; |
| 2506 | } |
| 2507 | |
| 2508 | primitives.push_back(primitive); |
| 2509 | } |
| 2510 | |
| 2511 | Dictionary e; |
| 2512 | e["targetNames" ] = target_names; |
| 2513 | |
| 2514 | weights.resize(target_names.size()); |
| 2515 | for (int name_i = 0; name_i < target_names.size(); name_i++) { |
| 2516 | real_t weight = 0.0; |
| 2517 | if (name_i < p_state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) { |
| 2518 | weight = p_state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i]; |
| 2519 | } |
| 2520 | weights[name_i] = weight; |
| 2521 | } |
| 2522 | if (weights.size()) { |
| 2523 | gltf_mesh["weights" ] = weights; |
| 2524 | } |
| 2525 | |
| 2526 | ERR_FAIL_COND_V(target_names.size() != weights.size(), FAILED); |
| 2527 | |
| 2528 | gltf_mesh["extras" ] = e; |
| 2529 | |
| 2530 | gltf_mesh["primitives" ] = primitives; |
| 2531 | |
| 2532 | meshes.push_back(gltf_mesh); |
| 2533 | } |
| 2534 | |
| 2535 | if (!meshes.size()) { |
| 2536 | return OK; |
| 2537 | } |
| 2538 | p_state->json["meshes" ] = meshes; |
| 2539 | print_verbose("glTF: Total meshes: " + itos(meshes.size())); |
| 2540 | |
| 2541 | return OK; |
| 2542 | } |
| 2543 | |
| 2544 | Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { |
| 2545 | if (!p_state->json.has("meshes" )) { |
| 2546 | return OK; |
| 2547 | } |
| 2548 | |
| 2549 | Array meshes = p_state->json["meshes" ]; |
| 2550 | for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { |
| 2551 | print_verbose("glTF: Parsing mesh: " + itos(i)); |
| 2552 | Dictionary d = meshes[i]; |
| 2553 | |
| 2554 | Ref<GLTFMesh> mesh; |
| 2555 | mesh.instantiate(); |
| 2556 | bool has_vertex_color = false; |
| 2557 | |
| 2558 | ERR_FAIL_COND_V(!d.has("primitives" ), ERR_PARSE_ERROR); |
| 2559 | |
| 2560 | Array primitives = d["primitives" ]; |
| 2561 | const Dictionary & = d.has("extras" ) ? (Dictionary)d["extras" ] : Dictionary(); |
| 2562 | Ref<ImporterMesh> import_mesh; |
| 2563 | import_mesh.instantiate(); |
| 2564 | String mesh_name = "mesh" ; |
| 2565 | if (d.has("name" ) && !String(d["name" ]).is_empty()) { |
| 2566 | mesh_name = d["name" ]; |
| 2567 | } |
| 2568 | import_mesh->set_name(_gen_unique_name(p_state, vformat("%s_%s" , p_state->scene_name, mesh_name))); |
| 2569 | |
| 2570 | for (int j = 0; j < primitives.size(); j++) { |
| 2571 | uint32_t flags = 0; |
| 2572 | Dictionary p = primitives[j]; |
| 2573 | |
| 2574 | Array array; |
| 2575 | array.resize(Mesh::ARRAY_MAX); |
| 2576 | |
| 2577 | ERR_FAIL_COND_V(!p.has("attributes" ), ERR_PARSE_ERROR); |
| 2578 | |
| 2579 | Dictionary a = p["attributes" ]; |
| 2580 | |
| 2581 | Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES; |
| 2582 | if (p.has("mode" )) { |
| 2583 | const int mode = p["mode" ]; |
| 2584 | ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); |
| 2585 | // Convert mesh.primitive.mode to Godot Mesh enum. See: |
| 2586 | // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode |
| 2587 | static const Mesh::PrimitiveType primitives2[7] = { |
| 2588 | Mesh::PRIMITIVE_POINTS, // 0 POINTS |
| 2589 | Mesh::PRIMITIVE_LINES, // 1 LINES |
| 2590 | Mesh::PRIMITIVE_LINES, // 2 LINE_LOOP; loop not supported, should be converted |
| 2591 | Mesh::PRIMITIVE_LINE_STRIP, // 3 LINE_STRIP |
| 2592 | Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES |
| 2593 | Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP |
| 2594 | Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted |
| 2595 | // TODO: Line loop and triangle fan are not supported and need to be converted to lines and triangles. |
| 2596 | }; |
| 2597 | |
| 2598 | primitive = primitives2[mode]; |
| 2599 | } |
| 2600 | |
| 2601 | ERR_FAIL_COND_V(!a.has("POSITION" ), ERR_PARSE_ERROR); |
| 2602 | int32_t vertex_num = 0; |
| 2603 | if (a.has("POSITION" )) { |
| 2604 | PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION" ], true); |
| 2605 | array[Mesh::ARRAY_VERTEX] = vertices; |
| 2606 | vertex_num = vertices.size(); |
| 2607 | } |
| 2608 | if (a.has("NORMAL" )) { |
| 2609 | array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL" ], true); |
| 2610 | } |
| 2611 | if (a.has("TANGENT" )) { |
| 2612 | array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT" ], true); |
| 2613 | } |
| 2614 | if (a.has("TEXCOORD_0" )) { |
| 2615 | array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0" ], true); |
| 2616 | } |
| 2617 | if (a.has("TEXCOORD_1" )) { |
| 2618 | array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1" ], true); |
| 2619 | } |
| 2620 | for (int custom_i = 0; custom_i < 3; custom_i++) { |
| 2621 | Vector<float> cur_custom; |
| 2622 | Vector<Vector2> texcoord_first; |
| 2623 | Vector<Vector2> texcoord_second; |
| 2624 | |
| 2625 | int texcoord_i = 2 + 2 * custom_i; |
| 2626 | String gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i); |
| 2627 | int num_channels = 0; |
| 2628 | if (a.has(gltf_texcoord_key)) { |
| 2629 | texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true); |
| 2630 | num_channels = 2; |
| 2631 | } |
| 2632 | gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i + 1); |
| 2633 | if (a.has(gltf_texcoord_key)) { |
| 2634 | texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true); |
| 2635 | num_channels = 4; |
| 2636 | } |
| 2637 | if (!num_channels) { |
| 2638 | break; |
| 2639 | } |
| 2640 | if (num_channels == 2 || num_channels == 4) { |
| 2641 | cur_custom.resize(vertex_num * num_channels); |
| 2642 | for (int32_t uv_i = 0; uv_i < texcoord_first.size() && uv_i < vertex_num; uv_i++) { |
| 2643 | cur_custom.write[uv_i * num_channels + 0] = texcoord_first[uv_i].x; |
| 2644 | cur_custom.write[uv_i * num_channels + 1] = texcoord_first[uv_i].y; |
| 2645 | } |
| 2646 | // Vector.resize seems to not zero-initialize. Ensure all unused elements are 0: |
| 2647 | for (int32_t uv_i = texcoord_first.size(); uv_i < vertex_num; uv_i++) { |
| 2648 | cur_custom.write[uv_i * num_channels + 0] = 0; |
| 2649 | cur_custom.write[uv_i * num_channels + 1] = 0; |
| 2650 | } |
| 2651 | } |
| 2652 | if (num_channels == 4) { |
| 2653 | for (int32_t uv_i = 0; uv_i < texcoord_second.size() && uv_i < vertex_num; uv_i++) { |
| 2654 | // num_channels must be 4 |
| 2655 | cur_custom.write[uv_i * num_channels + 2] = texcoord_second[uv_i].x; |
| 2656 | cur_custom.write[uv_i * num_channels + 3] = texcoord_second[uv_i].y; |
| 2657 | } |
| 2658 | // Vector.resize seems to not zero-initialize. Ensure all unused elements are 0: |
| 2659 | for (int32_t uv_i = texcoord_second.size(); uv_i < vertex_num; uv_i++) { |
| 2660 | cur_custom.write[uv_i * num_channels + 2] = 0; |
| 2661 | cur_custom.write[uv_i * num_channels + 3] = 0; |
| 2662 | } |
| 2663 | } |
| 2664 | if (cur_custom.size() > 0) { |
| 2665 | array[Mesh::ARRAY_CUSTOM0 + custom_i] = cur_custom; |
| 2666 | int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + custom_i * Mesh::ARRAY_FORMAT_CUSTOM_BITS; |
| 2667 | if (num_channels == 2) { |
| 2668 | flags |= Mesh::ARRAY_CUSTOM_RG_FLOAT << custom_shift; |
| 2669 | } else { |
| 2670 | flags |= Mesh::ARRAY_CUSTOM_RGBA_FLOAT << custom_shift; |
| 2671 | } |
| 2672 | } |
| 2673 | } |
| 2674 | if (a.has("COLOR_0" )) { |
| 2675 | array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0" ], true); |
| 2676 | has_vertex_color = true; |
| 2677 | } |
| 2678 | if (a.has("JOINTS_0" ) && !a.has("JOINTS_1" )) { |
| 2679 | array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(p_state, a["JOINTS_0" ], true); |
| 2680 | } else if (a.has("JOINTS_0" ) && a.has("JOINTS_1" )) { |
| 2681 | PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0" ], true); |
| 2682 | PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1" ], true); |
| 2683 | ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA); |
| 2684 | int32_t weight_8_count = JOINT_GROUP_SIZE * 2; |
| 2685 | Vector<int> joints; |
| 2686 | joints.resize(vertex_num * weight_8_count); |
| 2687 | for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { |
| 2688 | joints.write[vertex_i * weight_8_count + 0] = joints_0[vertex_i * JOINT_GROUP_SIZE + 0]; |
| 2689 | joints.write[vertex_i * weight_8_count + 1] = joints_0[vertex_i * JOINT_GROUP_SIZE + 1]; |
| 2690 | joints.write[vertex_i * weight_8_count + 2] = joints_0[vertex_i * JOINT_GROUP_SIZE + 2]; |
| 2691 | joints.write[vertex_i * weight_8_count + 3] = joints_0[vertex_i * JOINT_GROUP_SIZE + 3]; |
| 2692 | joints.write[vertex_i * weight_8_count + 4] = joints_1[vertex_i * JOINT_GROUP_SIZE + 0]; |
| 2693 | joints.write[vertex_i * weight_8_count + 5] = joints_1[vertex_i * JOINT_GROUP_SIZE + 1]; |
| 2694 | joints.write[vertex_i * weight_8_count + 6] = joints_1[vertex_i * JOINT_GROUP_SIZE + 2]; |
| 2695 | joints.write[vertex_i * weight_8_count + 7] = joints_1[vertex_i * JOINT_GROUP_SIZE + 3]; |
| 2696 | } |
| 2697 | array[Mesh::ARRAY_BONES] = joints; |
| 2698 | } |
| 2699 | if (a.has("WEIGHTS_0" ) && !a.has("WEIGHTS_1" )) { |
| 2700 | Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0" ], true); |
| 2701 | { //gltf does not seem to normalize the weights for some reason.. |
| 2702 | int wc = weights.size(); |
| 2703 | float *w = weights.ptrw(); |
| 2704 | |
| 2705 | for (int k = 0; k < wc; k += 4) { |
| 2706 | float total = 0.0; |
| 2707 | total += w[k + 0]; |
| 2708 | total += w[k + 1]; |
| 2709 | total += w[k + 2]; |
| 2710 | total += w[k + 3]; |
| 2711 | if (total > 0.0) { |
| 2712 | w[k + 0] /= total; |
| 2713 | w[k + 1] /= total; |
| 2714 | w[k + 2] /= total; |
| 2715 | w[k + 3] /= total; |
| 2716 | } |
| 2717 | } |
| 2718 | } |
| 2719 | array[Mesh::ARRAY_WEIGHTS] = weights; |
| 2720 | } else if (a.has("WEIGHTS_0" ) && a.has("WEIGHTS_1" )) { |
| 2721 | Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0" ], true); |
| 2722 | Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1" ], true); |
| 2723 | Vector<float> weights; |
| 2724 | ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA); |
| 2725 | int32_t weight_8_count = JOINT_GROUP_SIZE * 2; |
| 2726 | weights.resize(vertex_num * weight_8_count); |
| 2727 | for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { |
| 2728 | weights.write[vertex_i * weight_8_count + 0] = weights_0[vertex_i * JOINT_GROUP_SIZE + 0]; |
| 2729 | weights.write[vertex_i * weight_8_count + 1] = weights_0[vertex_i * JOINT_GROUP_SIZE + 1]; |
| 2730 | weights.write[vertex_i * weight_8_count + 2] = weights_0[vertex_i * JOINT_GROUP_SIZE + 2]; |
| 2731 | weights.write[vertex_i * weight_8_count + 3] = weights_0[vertex_i * JOINT_GROUP_SIZE + 3]; |
| 2732 | weights.write[vertex_i * weight_8_count + 4] = weights_1[vertex_i * JOINT_GROUP_SIZE + 0]; |
| 2733 | weights.write[vertex_i * weight_8_count + 5] = weights_1[vertex_i * JOINT_GROUP_SIZE + 1]; |
| 2734 | weights.write[vertex_i * weight_8_count + 6] = weights_1[vertex_i * JOINT_GROUP_SIZE + 2]; |
| 2735 | weights.write[vertex_i * weight_8_count + 7] = weights_1[vertex_i * JOINT_GROUP_SIZE + 3]; |
| 2736 | } |
| 2737 | { //gltf does not seem to normalize the weights for some reason.. |
| 2738 | int wc = weights.size(); |
| 2739 | float *w = weights.ptrw(); |
| 2740 | |
| 2741 | for (int k = 0; k < wc; k += weight_8_count) { |
| 2742 | float total = 0.0; |
| 2743 | total += w[k + 0]; |
| 2744 | total += w[k + 1]; |
| 2745 | total += w[k + 2]; |
| 2746 | total += w[k + 3]; |
| 2747 | total += w[k + 4]; |
| 2748 | total += w[k + 5]; |
| 2749 | total += w[k + 6]; |
| 2750 | total += w[k + 7]; |
| 2751 | if (total > 0.0) { |
| 2752 | w[k + 0] /= total; |
| 2753 | w[k + 1] /= total; |
| 2754 | w[k + 2] /= total; |
| 2755 | w[k + 3] /= total; |
| 2756 | w[k + 4] /= total; |
| 2757 | w[k + 5] /= total; |
| 2758 | w[k + 6] /= total; |
| 2759 | w[k + 7] /= total; |
| 2760 | } |
| 2761 | } |
| 2762 | } |
| 2763 | array[Mesh::ARRAY_WEIGHTS] = weights; |
| 2764 | } |
| 2765 | |
| 2766 | if (p.has("indices" )) { |
| 2767 | Vector<int> indices = _decode_accessor_as_ints(p_state, p["indices" ], false); |
| 2768 | |
| 2769 | if (primitive == Mesh::PRIMITIVE_TRIANGLES) { |
| 2770 | //swap around indices, convert ccw to cw for front face |
| 2771 | |
| 2772 | const int is = indices.size(); |
| 2773 | int *w = indices.ptrw(); |
| 2774 | for (int k = 0; k < is; k += 3) { |
| 2775 | SWAP(w[k + 1], w[k + 2]); |
| 2776 | } |
| 2777 | } |
| 2778 | array[Mesh::ARRAY_INDEX] = indices; |
| 2779 | |
| 2780 | } else if (primitive == Mesh::PRIMITIVE_TRIANGLES) { |
| 2781 | //generate indices because they need to be swapped for CW/CCW |
| 2782 | const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; |
| 2783 | ERR_FAIL_COND_V(vertices.size() == 0, ERR_PARSE_ERROR); |
| 2784 | Vector<int> indices; |
| 2785 | const int vs = vertices.size(); |
| 2786 | indices.resize(vs); |
| 2787 | { |
| 2788 | int *w = indices.ptrw(); |
| 2789 | for (int k = 0; k < vs; k += 3) { |
| 2790 | w[k] = k; |
| 2791 | w[k + 1] = k + 2; |
| 2792 | w[k + 2] = k + 1; |
| 2793 | } |
| 2794 | } |
| 2795 | array[Mesh::ARRAY_INDEX] = indices; |
| 2796 | } |
| 2797 | |
| 2798 | bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT" ) && a.has("TEXCOORD_0" ) && a.has("NORMAL" )); |
| 2799 | |
| 2800 | Ref<SurfaceTool> mesh_surface_tool; |
| 2801 | mesh_surface_tool.instantiate(); |
| 2802 | mesh_surface_tool->create_from_triangle_arrays(array); |
| 2803 | if (a.has("JOINTS_0" ) && a.has("JOINTS_1" )) { |
| 2804 | mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); |
| 2805 | } |
| 2806 | mesh_surface_tool->index(); |
| 2807 | if (generate_tangents) { |
| 2808 | //must generate mikktspace tangents.. ergh.. |
| 2809 | mesh_surface_tool->generate_tangents(); |
| 2810 | } |
| 2811 | array = mesh_surface_tool->commit_to_arrays(); |
| 2812 | |
| 2813 | Array morphs; |
| 2814 | //blend shapes |
| 2815 | if (p.has("targets" )) { |
| 2816 | print_verbose("glTF: Mesh has targets" ); |
| 2817 | const Array &targets = p["targets" ]; |
| 2818 | |
| 2819 | //ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement |
| 2820 | //but it could require a larger refactor? |
| 2821 | import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); |
| 2822 | |
| 2823 | if (j == 0) { |
| 2824 | const Array &target_names = extras.has("targetNames" ) ? (Array)extras["targetNames" ] : Array(); |
| 2825 | for (int k = 0; k < targets.size(); k++) { |
| 2826 | String bs_name; |
| 2827 | if (k < target_names.size() && ((String)target_names[k]).size() != 0) { |
| 2828 | bs_name = (String)target_names[k]; |
| 2829 | } else { |
| 2830 | bs_name = String("morph_" ) + itos(k); |
| 2831 | } |
| 2832 | import_mesh->add_blend_shape(bs_name); |
| 2833 | } |
| 2834 | } |
| 2835 | |
| 2836 | for (int k = 0; k < targets.size(); k++) { |
| 2837 | const Dictionary &t = targets[k]; |
| 2838 | |
| 2839 | Array array_copy; |
| 2840 | array_copy.resize(Mesh::ARRAY_MAX); |
| 2841 | |
| 2842 | for (int l = 0; l < Mesh::ARRAY_MAX; l++) { |
| 2843 | array_copy[l] = array[l]; |
| 2844 | } |
| 2845 | |
| 2846 | if (t.has("POSITION" )) { |
| 2847 | Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION" ], true); |
| 2848 | const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; |
| 2849 | const int size = src_varr.size(); |
| 2850 | ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); |
| 2851 | { |
| 2852 | const int max_idx = varr.size(); |
| 2853 | varr.resize(size); |
| 2854 | |
| 2855 | Vector3 *w_varr = varr.ptrw(); |
| 2856 | const Vector3 *r_varr = varr.ptr(); |
| 2857 | const Vector3 *r_src_varr = src_varr.ptr(); |
| 2858 | for (int l = 0; l < size; l++) { |
| 2859 | if (l < max_idx) { |
| 2860 | w_varr[l] = r_varr[l] + r_src_varr[l]; |
| 2861 | } else { |
| 2862 | w_varr[l] = r_src_varr[l]; |
| 2863 | } |
| 2864 | } |
| 2865 | } |
| 2866 | array_copy[Mesh::ARRAY_VERTEX] = varr; |
| 2867 | } |
| 2868 | if (t.has("NORMAL" )) { |
| 2869 | Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL" ], true); |
| 2870 | const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL]; |
| 2871 | int size = src_narr.size(); |
| 2872 | ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); |
| 2873 | { |
| 2874 | int max_idx = narr.size(); |
| 2875 | narr.resize(size); |
| 2876 | |
| 2877 | Vector3 *w_narr = narr.ptrw(); |
| 2878 | const Vector3 *r_narr = narr.ptr(); |
| 2879 | const Vector3 *r_src_narr = src_narr.ptr(); |
| 2880 | for (int l = 0; l < size; l++) { |
| 2881 | if (l < max_idx) { |
| 2882 | w_narr[l] = r_narr[l] + r_src_narr[l]; |
| 2883 | } else { |
| 2884 | w_narr[l] = r_src_narr[l]; |
| 2885 | } |
| 2886 | } |
| 2887 | } |
| 2888 | array_copy[Mesh::ARRAY_NORMAL] = narr; |
| 2889 | } |
| 2890 | if (t.has("TANGENT" )) { |
| 2891 | const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT" ], true); |
| 2892 | const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT]; |
| 2893 | ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR); |
| 2894 | |
| 2895 | Vector<float> tangents_v4; |
| 2896 | |
| 2897 | { |
| 2898 | int max_idx = tangents_v3.size(); |
| 2899 | |
| 2900 | int size4 = src_tangents.size(); |
| 2901 | tangents_v4.resize(size4); |
| 2902 | float *w4 = tangents_v4.ptrw(); |
| 2903 | |
| 2904 | const Vector3 *r3 = tangents_v3.ptr(); |
| 2905 | const float *r4 = src_tangents.ptr(); |
| 2906 | |
| 2907 | for (int l = 0; l < size4 / 4; l++) { |
| 2908 | if (l < max_idx) { |
| 2909 | w4[l * 4 + 0] = r3[l].x + r4[l * 4 + 0]; |
| 2910 | w4[l * 4 + 1] = r3[l].y + r4[l * 4 + 1]; |
| 2911 | w4[l * 4 + 2] = r3[l].z + r4[l * 4 + 2]; |
| 2912 | } else { |
| 2913 | w4[l * 4 + 0] = r4[l * 4 + 0]; |
| 2914 | w4[l * 4 + 1] = r4[l * 4 + 1]; |
| 2915 | w4[l * 4 + 2] = r4[l * 4 + 2]; |
| 2916 | } |
| 2917 | w4[l * 4 + 3] = r4[l * 4 + 3]; //copy flip value |
| 2918 | } |
| 2919 | } |
| 2920 | |
| 2921 | array_copy[Mesh::ARRAY_TANGENT] = tangents_v4; |
| 2922 | } |
| 2923 | |
| 2924 | Ref<SurfaceTool> blend_surface_tool; |
| 2925 | blend_surface_tool.instantiate(); |
| 2926 | blend_surface_tool->create_from_triangle_arrays(array_copy); |
| 2927 | if (a.has("JOINTS_0" ) && a.has("JOINTS_1" )) { |
| 2928 | blend_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); |
| 2929 | } |
| 2930 | blend_surface_tool->index(); |
| 2931 | if (generate_tangents) { |
| 2932 | blend_surface_tool->generate_tangents(); |
| 2933 | } |
| 2934 | array_copy = blend_surface_tool->commit_to_arrays(); |
| 2935 | |
| 2936 | // Enforce blend shape mask array format |
| 2937 | for (int l = 0; l < Mesh::ARRAY_MAX; l++) { |
| 2938 | if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << l))) { |
| 2939 | array_copy[l] = Variant(); |
| 2940 | } |
| 2941 | } |
| 2942 | |
| 2943 | morphs.push_back(array_copy); |
| 2944 | } |
| 2945 | } |
| 2946 | |
| 2947 | Ref<Material> mat; |
| 2948 | String mat_name; |
| 2949 | if (!p_state->discard_meshes_and_materials) { |
| 2950 | if (p.has("material" )) { |
| 2951 | const int material = p["material" ]; |
| 2952 | ERR_FAIL_INDEX_V(material, p_state->materials.size(), ERR_FILE_CORRUPT); |
| 2953 | Ref<Material> mat3d = p_state->materials[material]; |
| 2954 | ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); |
| 2955 | |
| 2956 | Ref<BaseMaterial3D> base_material = mat3d; |
| 2957 | if (has_vertex_color && base_material.is_valid()) { |
| 2958 | base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); |
| 2959 | } |
| 2960 | mat = mat3d; |
| 2961 | |
| 2962 | } else { |
| 2963 | Ref<StandardMaterial3D> mat3d; |
| 2964 | mat3d.instantiate(); |
| 2965 | if (has_vertex_color) { |
| 2966 | mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); |
| 2967 | } |
| 2968 | mat = mat3d; |
| 2969 | } |
| 2970 | ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT); |
| 2971 | mat_name = mat->get_name(); |
| 2972 | } |
| 2973 | import_mesh->add_surface(primitive, array, morphs, |
| 2974 | Dictionary(), mat, mat_name, flags); |
| 2975 | } |
| 2976 | |
| 2977 | Vector<float> blend_weights; |
| 2978 | blend_weights.resize(import_mesh->get_blend_shape_count()); |
| 2979 | for (int32_t weight_i = 0; weight_i < blend_weights.size(); weight_i++) { |
| 2980 | blend_weights.write[weight_i] = 0.0f; |
| 2981 | } |
| 2982 | |
| 2983 | if (d.has("weights" )) { |
| 2984 | const Array &weights = d["weights" ]; |
| 2985 | for (int j = 0; j < weights.size(); j++) { |
| 2986 | if (j >= blend_weights.size()) { |
| 2987 | break; |
| 2988 | } |
| 2989 | blend_weights.write[j] = weights[j]; |
| 2990 | } |
| 2991 | } |
| 2992 | mesh->set_blend_weights(blend_weights); |
| 2993 | mesh->set_mesh(import_mesh); |
| 2994 | |
| 2995 | p_state->meshes.push_back(mesh); |
| 2996 | } |
| 2997 | |
| 2998 | print_verbose("glTF: Total meshes: " + itos(p_state->meshes.size())); |
| 2999 | |
| 3000 | return OK; |
| 3001 | } |
| 3002 | |
| 3003 | void GLTFDocument::set_image_format(const String &p_image_format) { |
| 3004 | _image_format = p_image_format; |
| 3005 | } |
| 3006 | |
| 3007 | String GLTFDocument::get_image_format() const { |
| 3008 | return _image_format; |
| 3009 | } |
| 3010 | |
| 3011 | void GLTFDocument::set_lossy_quality(float p_lossy_quality) { |
| 3012 | _lossy_quality = p_lossy_quality; |
| 3013 | } |
| 3014 | |
| 3015 | float GLTFDocument::get_lossy_quality() const { |
| 3016 | return _lossy_quality; |
| 3017 | } |
| 3018 | |
| 3019 | Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) { |
| 3020 | Array images; |
| 3021 | // Check if any extension wants to be the image saver. |
| 3022 | _image_save_extension = Ref<GLTFDocumentExtension>(); |
| 3023 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 3024 | ERR_CONTINUE(ext.is_null()); |
| 3025 | Vector<String> image_formats = ext->get_saveable_image_formats(); |
| 3026 | if (image_formats.has(_image_format)) { |
| 3027 | _image_save_extension = ext; |
| 3028 | break; |
| 3029 | } |
| 3030 | } |
| 3031 | // Serialize every image in the state's images array. |
| 3032 | for (int i = 0; i < p_state->images.size(); i++) { |
| 3033 | Dictionary image_dict; |
| 3034 | |
| 3035 | ERR_CONTINUE(p_state->images[i].is_null()); |
| 3036 | |
| 3037 | Ref<Image> image = p_state->images[i]->get_image(); |
| 3038 | ERR_CONTINUE(image.is_null()); |
| 3039 | if (image->is_compressed()) { |
| 3040 | image->decompress(); |
| 3041 | ERR_FAIL_COND_V_MSG(image->is_compressed(), ERR_INVALID_DATA, "GLTF: Image was compressed, but could not be decompressed." ); |
| 3042 | } |
| 3043 | |
| 3044 | if (p_state->filename.to_lower().ends_with("gltf" )) { |
| 3045 | String img_name = p_state->images[i]->get_name(); |
| 3046 | if (img_name.is_empty()) { |
| 3047 | img_name = itos(i); |
| 3048 | } |
| 3049 | img_name = _gen_unique_name(p_state, img_name); |
| 3050 | img_name = img_name.pad_zeros(3); |
| 3051 | String relative_texture_dir = "textures" ; |
| 3052 | String full_texture_dir = p_state->base_path.path_join(relative_texture_dir); |
| 3053 | Ref<DirAccess> da = DirAccess::open(p_state->base_path); |
| 3054 | if (!da->dir_exists(full_texture_dir)) { |
| 3055 | da->make_dir(full_texture_dir); |
| 3056 | } |
| 3057 | if (_image_save_extension.is_valid()) { |
| 3058 | img_name = img_name + _image_save_extension->get_image_file_extension(); |
| 3059 | Error err = _image_save_extension->save_image_at_path(p_state, image, full_texture_dir.path_join(img_name), _image_format, _lossy_quality); |
| 3060 | ERR_FAIL_COND_V_MSG(err != OK, err, "GLTF: Failed to save image in '" + _image_format + "' format as a separate file." ); |
| 3061 | } else if (_image_format == "PNG" ) { |
| 3062 | img_name = img_name + ".png" ; |
| 3063 | image->save_png(full_texture_dir.path_join(img_name)); |
| 3064 | } else if (_image_format == "JPEG" ) { |
| 3065 | img_name = img_name + ".jpg" ; |
| 3066 | image->save_jpg(full_texture_dir.path_join(img_name), _lossy_quality); |
| 3067 | } else { |
| 3068 | ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "GLTF: Unknown image format '" + _image_format + "'." ); |
| 3069 | } |
| 3070 | image_dict["uri" ] = relative_texture_dir.path_join(img_name).uri_encode(); |
| 3071 | } else { |
| 3072 | GLTFBufferViewIndex bvi; |
| 3073 | |
| 3074 | Ref<GLTFBufferView> bv; |
| 3075 | bv.instantiate(); |
| 3076 | |
| 3077 | const GLTFBufferIndex bi = 0; |
| 3078 | bv->buffer = bi; |
| 3079 | bv->byte_offset = p_state->buffers[bi].size(); |
| 3080 | ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); |
| 3081 | |
| 3082 | Vector<uint8_t> buffer; |
| 3083 | Ref<ImageTexture> img_tex = image; |
| 3084 | if (img_tex.is_valid()) { |
| 3085 | image = img_tex->get_image(); |
| 3086 | } |
| 3087 | // Save in various image formats. Note that if the format is "None", |
| 3088 | // the state's images will be empty, so this code will not be reached. |
| 3089 | if (_image_save_extension.is_valid()) { |
| 3090 | buffer = _image_save_extension->serialize_image_to_bytes(p_state, image, image_dict, _image_format, _lossy_quality); |
| 3091 | } else if (_image_format == "PNG" ) { |
| 3092 | buffer = image->save_png_to_buffer(); |
| 3093 | image_dict["mimeType" ] = "image/png" ; |
| 3094 | } else if (_image_format == "JPEG" ) { |
| 3095 | buffer = image->save_jpg_to_buffer(_lossy_quality); |
| 3096 | image_dict["mimeType" ] = "image/jpeg" ; |
| 3097 | } else { |
| 3098 | ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "GLTF: Unknown image format '" + _image_format + "'." ); |
| 3099 | } |
| 3100 | ERR_FAIL_COND_V_MSG(buffer.is_empty(), ERR_INVALID_DATA, "GLTF: Failed to save image in '" + _image_format + "' format." ); |
| 3101 | |
| 3102 | bv->byte_length = buffer.size(); |
| 3103 | p_state->buffers.write[bi].resize(p_state->buffers[bi].size() + bv->byte_length); |
| 3104 | memcpy(&p_state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size()); |
| 3105 | ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT); |
| 3106 | |
| 3107 | p_state->buffer_views.push_back(bv); |
| 3108 | bvi = p_state->buffer_views.size() - 1; |
| 3109 | image_dict["bufferView" ] = bvi; |
| 3110 | } |
| 3111 | images.push_back(image_dict); |
| 3112 | } |
| 3113 | |
| 3114 | print_verbose("Total images: " + itos(p_state->images.size())); |
| 3115 | |
| 3116 | if (!images.size()) { |
| 3117 | return OK; |
| 3118 | } |
| 3119 | p_state->json["images" ] = images; |
| 3120 | |
| 3121 | return OK; |
| 3122 | } |
| 3123 | |
| 3124 | Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index, String &r_file_extension) { |
| 3125 | Ref<Image> r_image; |
| 3126 | r_image.instantiate(); |
| 3127 | // Check if any GLTFDocumentExtensions want to import this data as an image. |
| 3128 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 3129 | ERR_CONTINUE(ext.is_null()); |
| 3130 | Error err = ext->parse_image_data(p_state, p_bytes, p_mime_type, r_image); |
| 3131 | ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing image " + itos(p_index) + " in file " + p_state->filename + ". Continuing." ); |
| 3132 | if (!r_image->is_empty()) { |
| 3133 | r_file_extension = ext->get_image_file_extension(); |
| 3134 | return r_image; |
| 3135 | } |
| 3136 | } |
| 3137 | // If no extension wanted to import this data as an image, try to load a PNG or JPEG. |
| 3138 | // First we honor the mime types if they were defined. |
| 3139 | if (p_mime_type == "image/png" ) { // Load buffer as PNG. |
| 3140 | r_image->load_png_from_buffer(p_bytes); |
| 3141 | r_file_extension = ".png" ; |
| 3142 | } else if (p_mime_type == "image/jpeg" ) { // Loader buffer as JPEG. |
| 3143 | r_image->load_jpg_from_buffer(p_bytes); |
| 3144 | r_file_extension = ".jpg" ; |
| 3145 | } |
| 3146 | // If we didn't pass the above tests, we attempt loading as PNG and then JPEG directly. |
| 3147 | // This covers URIs with base64-encoded data with application/* type but |
| 3148 | // no optional mimeType property, or bufferViews with a bogus mimeType |
| 3149 | // (e.g. `image/jpeg` but the data is actually PNG). |
| 3150 | // That's not *exactly* what the spec mandates but this lets us be |
| 3151 | // lenient with bogus glb files which do exist in production. |
| 3152 | if (r_image->is_empty()) { // Try PNG first. |
| 3153 | r_image->load_png_from_buffer(p_bytes); |
| 3154 | } |
| 3155 | if (r_image->is_empty()) { // And then JPEG. |
| 3156 | r_image->load_jpg_from_buffer(p_bytes); |
| 3157 | } |
| 3158 | // If it still can't be loaded, give up and insert an empty image as placeholder. |
| 3159 | if (r_image->is_empty()) { |
| 3160 | ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s." , p_index, p_mime_type)); |
| 3161 | } |
| 3162 | return r_image; |
| 3163 | } |
| 3164 | |
| 3165 | void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_file_extension, int p_index, Ref<Image> p_image) { |
| 3166 | GLTFState::GLTFHandleBinary handling = GLTFState::GLTFHandleBinary(p_state->handle_binary_image); |
| 3167 | if (p_image->is_empty() || handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) { |
| 3168 | p_state->images.push_back(Ref<Texture2D>()); |
| 3169 | p_state->source_images.push_back(Ref<Image>()); |
| 3170 | return; |
| 3171 | } |
| 3172 | #ifdef TOOLS_ENABLED |
| 3173 | if (Engine::get_singleton()->is_editor_hint() && handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EXTRACT_TEXTURES) { |
| 3174 | if (p_state->base_path.is_empty()) { |
| 3175 | p_state->images.push_back(Ref<Texture2D>()); |
| 3176 | p_state->source_images.push_back(Ref<Image>()); |
| 3177 | } else if (p_image->get_name().is_empty()) { |
| 3178 | WARN_PRINT(vformat("glTF: Image index '%d' couldn't be named. Skipping it." , p_index)); |
| 3179 | p_state->images.push_back(Ref<Texture2D>()); |
| 3180 | p_state->source_images.push_back(Ref<Image>()); |
| 3181 | } else { |
| 3182 | bool must_import = true; |
| 3183 | Vector<uint8_t> img_data = p_image->get_data(); |
| 3184 | Dictionary generator_parameters; |
| 3185 | String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + p_image->get_name(); |
| 3186 | file_path += p_file_extension.is_empty() ? ".png" : p_file_extension; |
| 3187 | if (FileAccess::exists(file_path + ".import" )) { |
| 3188 | Ref<ConfigFile> config; |
| 3189 | config.instantiate(); |
| 3190 | config->load(file_path + ".import" ); |
| 3191 | if (config->has_section_key("remap" , "generator_parameters" )) { |
| 3192 | generator_parameters = (Dictionary)config->get_value("remap" , "generator_parameters" ); |
| 3193 | } |
| 3194 | if (!generator_parameters.has("md5" )) { |
| 3195 | must_import = false; // Didn't come from a gltf document; don't overwrite. |
| 3196 | } |
| 3197 | String existing_md5 = generator_parameters["md5" ]; |
| 3198 | unsigned char md5_hash[16]; |
| 3199 | CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash); |
| 3200 | String new_md5 = String::hex_encode_buffer(md5_hash, 16); |
| 3201 | generator_parameters["md5" ] = new_md5; |
| 3202 | if (new_md5 == existing_md5) { |
| 3203 | must_import = false; |
| 3204 | } |
| 3205 | } |
| 3206 | if (must_import) { |
| 3207 | Error err = OK; |
| 3208 | if (p_file_extension.is_empty()) { |
| 3209 | // If a file extension was not specified, save the image data to a PNG file. |
| 3210 | err = p_image->save_png(file_path); |
| 3211 | ERR_FAIL_COND(err != OK); |
| 3212 | } else { |
| 3213 | // If a file extension was specified, save the original bytes to a file with that extension. |
| 3214 | Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE, &err); |
| 3215 | ERR_FAIL_COND(err != OK); |
| 3216 | file->store_buffer(p_bytes); |
| 3217 | file->close(); |
| 3218 | } |
| 3219 | // ResourceLoader::import will crash if not is_editor_hint(), so this case is protected above and will fall through to uncompressed. |
| 3220 | HashMap<StringName, Variant> custom_options; |
| 3221 | custom_options[SNAME("mipmaps/generate" )] = true; |
| 3222 | // Will only use project settings defaults if custom_importer is empty. |
| 3223 | EditorFileSystem::get_singleton()->update_file(file_path); |
| 3224 | EditorFileSystem::get_singleton()->reimport_append(file_path, custom_options, String(), generator_parameters); |
| 3225 | } |
| 3226 | Ref<Texture2D> saved_image = ResourceLoader::load(file_path, "Texture2D" ); |
| 3227 | if (saved_image.is_valid()) { |
| 3228 | p_state->images.push_back(saved_image); |
| 3229 | p_state->source_images.push_back(saved_image->get_image()); |
| 3230 | } else { |
| 3231 | WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded with the name: %s. Skipping it." , p_index, p_image->get_name())); |
| 3232 | // Placeholder to keep count. |
| 3233 | p_state->images.push_back(Ref<Texture2D>()); |
| 3234 | p_state->source_images.push_back(Ref<Image>()); |
| 3235 | } |
| 3236 | } |
| 3237 | return; |
| 3238 | } |
| 3239 | #endif // TOOLS_ENABLED |
| 3240 | if (handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { |
| 3241 | Ref<PortableCompressedTexture2D> tex; |
| 3242 | tex.instantiate(); |
| 3243 | tex->set_name(p_image->get_name()); |
| 3244 | tex->set_keep_compressed_buffer(true); |
| 3245 | tex->create_from_image(p_image, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL); |
| 3246 | p_state->images.push_back(tex); |
| 3247 | p_state->source_images.push_back(p_image); |
| 3248 | return; |
| 3249 | } |
| 3250 | // This handles the case of HANDLE_BINARY_EMBED_AS_UNCOMPRESSED, and it also serves |
| 3251 | // as a fallback for HANDLE_BINARY_EXTRACT_TEXTURES when this is not the editor. |
| 3252 | Ref<ImageTexture> tex; |
| 3253 | tex.instantiate(); |
| 3254 | tex->set_name(p_image->get_name()); |
| 3255 | tex->set_image(p_image); |
| 3256 | p_state->images.push_back(tex); |
| 3257 | p_state->source_images.push_back(p_image); |
| 3258 | } |
| 3259 | |
| 3260 | Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_path) { |
| 3261 | ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); |
| 3262 | if (!p_state->json.has("images" )) { |
| 3263 | return OK; |
| 3264 | } |
| 3265 | |
| 3266 | // Ref: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#images |
| 3267 | |
| 3268 | const Array &images = p_state->json["images" ]; |
| 3269 | HashSet<String> used_names; |
| 3270 | for (int i = 0; i < images.size(); i++) { |
| 3271 | const Dictionary &dict = images[i]; |
| 3272 | |
| 3273 | // glTF 2.0 supports PNG and JPEG types, which can be specified as (from spec): |
| 3274 | // "- a URI to an external file in one of the supported images formats, or |
| 3275 | // - a URI with embedded base64-encoded data, or |
| 3276 | // - a reference to a bufferView; in that case mimeType must be defined." |
| 3277 | // Since mimeType is optional for external files and base64 data, we'll have to |
| 3278 | // fall back on letting Godot parse the data to figure out if it's PNG or JPEG. |
| 3279 | |
| 3280 | // We'll assume that we use either URI or bufferView, so let's warn the user |
| 3281 | // if their image somehow uses both. And fail if it has neither. |
| 3282 | ERR_CONTINUE_MSG(!dict.has("uri" ) && !dict.has("bufferView" ), "Invalid image definition in glTF file, it should specify an 'uri' or 'bufferView'." ); |
| 3283 | if (dict.has("uri" ) && dict.has("bufferView" )) { |
| 3284 | WARN_PRINT("Invalid image definition in glTF file using both 'uri' and 'bufferView'. 'uri' will take precedence." ); |
| 3285 | } |
| 3286 | |
| 3287 | String mime_type; |
| 3288 | if (dict.has("mimeType" )) { // Should be "image/png", "image/jpeg", or something handled by an extension. |
| 3289 | mime_type = dict["mimeType" ]; |
| 3290 | } |
| 3291 | |
| 3292 | String image_name; |
| 3293 | if (dict.has("name" )) { |
| 3294 | image_name = dict["name" ]; |
| 3295 | image_name = image_name.get_file().get_basename().validate_filename(); |
| 3296 | } |
| 3297 | if (image_name.is_empty()) { |
| 3298 | image_name = itos(i); |
| 3299 | } |
| 3300 | while (used_names.has(image_name)) { |
| 3301 | image_name += "_" + itos(i); |
| 3302 | } |
| 3303 | used_names.insert(image_name); |
| 3304 | // Load the image data. If we get a byte array, store here for later. |
| 3305 | Vector<uint8_t> data; |
| 3306 | if (dict.has("uri" )) { |
| 3307 | // Handles the first two bullet points from the spec (embedded data, or external file). |
| 3308 | String uri = dict["uri" ]; |
| 3309 | if (uri.begins_with("data:" )) { // Embedded data using base64. |
| 3310 | data = _parse_base64_uri(uri); |
| 3311 | // mimeType is optional, but if we have it defined in the URI, let's use it. |
| 3312 | if (mime_type.is_empty() && uri.contains(";" )) { |
| 3313 | // Trim "data:" prefix which is 5 characters long, and end at ";base64". |
| 3314 | mime_type = uri.substr(5, uri.find(";base64" ) - 5); |
| 3315 | } |
| 3316 | } else { // Relative path to an external image file. |
| 3317 | ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); |
| 3318 | uri = uri.uri_decode(); |
| 3319 | uri = p_base_path.path_join(uri).replace("\\" , "/" ); // Fix for Windows. |
| 3320 | // ResourceLoader will rely on the file extension to use the relevant loader. |
| 3321 | // The spec says that if mimeType is defined, it should take precedence (e.g. |
| 3322 | // there could be a `.png` image which is actually JPEG), but there's no easy |
| 3323 | // API for that in Godot, so we'd have to load as a buffer (i.e. embedded in |
| 3324 | // the material), so we only do that only as fallback. |
| 3325 | Ref<Texture2D> texture = ResourceLoader::load(uri); |
| 3326 | if (texture.is_valid()) { |
| 3327 | p_state->images.push_back(texture); |
| 3328 | p_state->source_images.push_back(texture->get_image()); |
| 3329 | continue; |
| 3330 | } |
| 3331 | // mimeType is optional, but if we have it in the file extension, let's use it. |
| 3332 | // If the mimeType does not match with the file extension, either it should be |
| 3333 | // specified in the file, or the GLTFDocumentExtension should handle it. |
| 3334 | if (mime_type.is_empty()) { |
| 3335 | mime_type = "image/" + uri.get_extension(); |
| 3336 | } |
| 3337 | // Fallback to loading as byte array. This enables us to support the |
| 3338 | // spec's requirement that we honor mimetype regardless of file URI. |
| 3339 | data = FileAccess::get_file_as_bytes(uri); |
| 3340 | if (data.size() == 0) { |
| 3341 | WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s because there was no data to load. Skipping it." , i, mime_type, uri)); |
| 3342 | p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. |
| 3343 | p_state->source_images.push_back(Ref<Image>()); |
| 3344 | continue; |
| 3345 | } |
| 3346 | } |
| 3347 | } else if (dict.has("bufferView" )) { |
| 3348 | // Handles the third bullet point from the spec (bufferView). |
| 3349 | ERR_FAIL_COND_V_MSG(mime_type.is_empty(), ERR_FILE_CORRUPT, vformat("glTF: Image index '%d' specifies 'bufferView' but no 'mimeType', which is invalid." , i)); |
| 3350 | const GLTFBufferViewIndex bvi = dict["bufferView" ]; |
| 3351 | ERR_FAIL_INDEX_V(bvi, p_state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR); |
| 3352 | Ref<GLTFBufferView> bv = p_state->buffer_views[bvi]; |
| 3353 | const GLTFBufferIndex bi = bv->buffer; |
| 3354 | ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); |
| 3355 | ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT); |
| 3356 | const PackedByteArray &buffer = p_state->buffers[bi]; |
| 3357 | data = buffer.slice(bv->byte_offset, bv->byte_offset + bv->byte_length); |
| 3358 | } |
| 3359 | // Done loading the image data bytes. Check that we actually got data to parse. |
| 3360 | // Note: There are paths above that return early, so this point might not be reached. |
| 3361 | if (data.is_empty()) { |
| 3362 | WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded, no data found. Skipping it." , i)); |
| 3363 | p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. |
| 3364 | p_state->source_images.push_back(Ref<Image>()); |
| 3365 | continue; |
| 3366 | } |
| 3367 | // Parse the image data from bytes into an Image resource and save if needed. |
| 3368 | String file_extension; |
| 3369 | Ref<Image> img = _parse_image_bytes_into_image(p_state, data, mime_type, i, file_extension); |
| 3370 | img->set_name(image_name); |
| 3371 | _parse_image_save_image(p_state, data, file_extension, i, img); |
| 3372 | } |
| 3373 | |
| 3374 | print_verbose("glTF: Total images: " + itos(p_state->images.size())); |
| 3375 | |
| 3376 | return OK; |
| 3377 | } |
| 3378 | |
| 3379 | Error GLTFDocument::_serialize_textures(Ref<GLTFState> p_state) { |
| 3380 | if (!p_state->textures.size()) { |
| 3381 | return OK; |
| 3382 | } |
| 3383 | |
| 3384 | Array textures; |
| 3385 | for (int32_t i = 0; i < p_state->textures.size(); i++) { |
| 3386 | Dictionary texture_dict; |
| 3387 | Ref<GLTFTexture> gltf_texture = p_state->textures[i]; |
| 3388 | if (_image_save_extension.is_valid()) { |
| 3389 | Error err = _image_save_extension->serialize_texture_json(p_state, texture_dict, gltf_texture, _image_format); |
| 3390 | ERR_FAIL_COND_V(err != OK, err); |
| 3391 | } else { |
| 3392 | ERR_CONTINUE(gltf_texture->get_src_image() == -1); |
| 3393 | texture_dict["source" ] = gltf_texture->get_src_image(); |
| 3394 | } |
| 3395 | GLTFTextureSamplerIndex sampler_index = gltf_texture->get_sampler(); |
| 3396 | if (sampler_index != -1) { |
| 3397 | texture_dict["sampler" ] = sampler_index; |
| 3398 | } |
| 3399 | textures.push_back(texture_dict); |
| 3400 | } |
| 3401 | p_state->json["textures" ] = textures; |
| 3402 | |
| 3403 | return OK; |
| 3404 | } |
| 3405 | |
| 3406 | Error GLTFDocument::_parse_textures(Ref<GLTFState> p_state) { |
| 3407 | if (!p_state->json.has("textures" )) { |
| 3408 | return OK; |
| 3409 | } |
| 3410 | |
| 3411 | const Array &textures = p_state->json["textures" ]; |
| 3412 | for (GLTFTextureIndex i = 0; i < textures.size(); i++) { |
| 3413 | const Dictionary &texture_dict = textures[i]; |
| 3414 | Ref<GLTFTexture> gltf_texture; |
| 3415 | gltf_texture.instantiate(); |
| 3416 | // Check if any GLTFDocumentExtensions want to handle this texture JSON. |
| 3417 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 3418 | ERR_CONTINUE(ext.is_null()); |
| 3419 | Error err = ext->parse_texture_json(p_state, texture_dict, gltf_texture); |
| 3420 | ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing texture JSON " + String(Variant(texture_dict)) + " in file " + p_state->filename + ". Continuing." ); |
| 3421 | if (gltf_texture->get_src_image() != -1) { |
| 3422 | break; |
| 3423 | } |
| 3424 | } |
| 3425 | if (gltf_texture->get_src_image() == -1) { |
| 3426 | // No extensions handled it, so use the base GLTF source. |
| 3427 | // This may be the fallback, or the only option anyway. |
| 3428 | ERR_FAIL_COND_V(!texture_dict.has("source" ), ERR_PARSE_ERROR); |
| 3429 | gltf_texture->set_src_image(texture_dict["source" ]); |
| 3430 | } |
| 3431 | if (gltf_texture->get_sampler() == -1 && texture_dict.has("sampler" )) { |
| 3432 | gltf_texture->set_sampler(texture_dict["sampler" ]); |
| 3433 | } |
| 3434 | p_state->textures.push_back(gltf_texture); |
| 3435 | } |
| 3436 | |
| 3437 | return OK; |
| 3438 | } |
| 3439 | |
| 3440 | GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> p_state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { |
| 3441 | ERR_FAIL_COND_V(p_texture.is_null(), -1); |
| 3442 | Ref<GLTFTexture> gltf_texture; |
| 3443 | gltf_texture.instantiate(); |
| 3444 | ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1); |
| 3445 | GLTFImageIndex gltf_src_image_i = p_state->images.size(); |
| 3446 | p_state->images.push_back(p_texture); |
| 3447 | p_state->source_images.push_back(p_texture->get_image()); |
| 3448 | gltf_texture->set_src_image(gltf_src_image_i); |
| 3449 | gltf_texture->set_sampler(_set_sampler_for_mode(p_state, p_filter_mode, p_repeats)); |
| 3450 | GLTFTextureIndex gltf_texture_i = p_state->textures.size(); |
| 3451 | p_state->textures.push_back(gltf_texture); |
| 3452 | return gltf_texture_i; |
| 3453 | } |
| 3454 | |
| 3455 | Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture, int p_texture_types) { |
| 3456 | ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>()); |
| 3457 | const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image(); |
| 3458 | ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref<Texture2D>()); |
| 3459 | if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { |
| 3460 | ERR_FAIL_INDEX_V(image, p_state->source_images.size(), Ref<Texture2D>()); |
| 3461 | Ref<PortableCompressedTexture2D> portable_texture; |
| 3462 | portable_texture.instantiate(); |
| 3463 | portable_texture->set_keep_compressed_buffer(true); |
| 3464 | Ref<Image> new_img = p_state->source_images[image]->duplicate(); |
| 3465 | ERR_FAIL_COND_V(new_img.is_null(), Ref<Texture2D>()); |
| 3466 | new_img->generate_mipmaps(); |
| 3467 | if (p_texture_types) { |
| 3468 | portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, true); |
| 3469 | } else { |
| 3470 | portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, false); |
| 3471 | } |
| 3472 | p_state->images.write[image] = portable_texture; |
| 3473 | p_state->source_images.write[image] = new_img; |
| 3474 | } |
| 3475 | return p_state->images[image]; |
| 3476 | } |
| 3477 | |
| 3478 | GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> p_state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { |
| 3479 | for (int i = 0; i < p_state->texture_samplers.size(); ++i) { |
| 3480 | if (p_state->texture_samplers[i]->get_filter_mode() == p_filter_mode) { |
| 3481 | return i; |
| 3482 | } |
| 3483 | } |
| 3484 | |
| 3485 | GLTFTextureSamplerIndex gltf_sampler_i = p_state->texture_samplers.size(); |
| 3486 | Ref<GLTFTextureSampler> gltf_sampler; |
| 3487 | gltf_sampler.instantiate(); |
| 3488 | gltf_sampler->set_filter_mode(p_filter_mode); |
| 3489 | gltf_sampler->set_wrap_mode(p_repeats); |
| 3490 | p_state->texture_samplers.push_back(gltf_sampler); |
| 3491 | return gltf_sampler_i; |
| 3492 | } |
| 3493 | |
| 3494 | Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) { |
| 3495 | ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>()); |
| 3496 | const GLTFTextureSamplerIndex sampler = p_state->textures[p_texture]->get_sampler(); |
| 3497 | |
| 3498 | if (sampler == -1) { |
| 3499 | return p_state->default_texture_sampler; |
| 3500 | } else { |
| 3501 | ERR_FAIL_INDEX_V(sampler, p_state->texture_samplers.size(), Ref<GLTFTextureSampler>()); |
| 3502 | |
| 3503 | return p_state->texture_samplers[sampler]; |
| 3504 | } |
| 3505 | } |
| 3506 | |
| 3507 | Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> p_state) { |
| 3508 | if (!p_state->texture_samplers.size()) { |
| 3509 | return OK; |
| 3510 | } |
| 3511 | |
| 3512 | Array samplers; |
| 3513 | for (int32_t i = 0; i < p_state->texture_samplers.size(); ++i) { |
| 3514 | Dictionary d; |
| 3515 | Ref<GLTFTextureSampler> s = p_state->texture_samplers[i]; |
| 3516 | d["magFilter" ] = s->get_mag_filter(); |
| 3517 | d["minFilter" ] = s->get_min_filter(); |
| 3518 | d["wrapS" ] = s->get_wrap_s(); |
| 3519 | d["wrapT" ] = s->get_wrap_t(); |
| 3520 | samplers.push_back(d); |
| 3521 | } |
| 3522 | p_state->json["samplers" ] = samplers; |
| 3523 | |
| 3524 | return OK; |
| 3525 | } |
| 3526 | |
| 3527 | Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> p_state) { |
| 3528 | p_state->default_texture_sampler.instantiate(); |
| 3529 | p_state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); |
| 3530 | p_state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); |
| 3531 | p_state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT); |
| 3532 | p_state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT); |
| 3533 | |
| 3534 | if (!p_state->json.has("samplers" )) { |
| 3535 | return OK; |
| 3536 | } |
| 3537 | |
| 3538 | const Array &samplers = p_state->json["samplers" ]; |
| 3539 | for (int i = 0; i < samplers.size(); ++i) { |
| 3540 | const Dictionary &d = samplers[i]; |
| 3541 | |
| 3542 | Ref<GLTFTextureSampler> sampler; |
| 3543 | sampler.instantiate(); |
| 3544 | |
| 3545 | if (d.has("minFilter" )) { |
| 3546 | sampler->set_min_filter(d["minFilter" ]); |
| 3547 | } else { |
| 3548 | sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); |
| 3549 | } |
| 3550 | if (d.has("magFilter" )) { |
| 3551 | sampler->set_mag_filter(d["magFilter" ]); |
| 3552 | } else { |
| 3553 | sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); |
| 3554 | } |
| 3555 | |
| 3556 | if (d.has("wrapS" )) { |
| 3557 | sampler->set_wrap_s(d["wrapS" ]); |
| 3558 | } else { |
| 3559 | sampler->set_wrap_s(GLTFTextureSampler::WrapMode::DEFAULT); |
| 3560 | } |
| 3561 | |
| 3562 | if (d.has("wrapT" )) { |
| 3563 | sampler->set_wrap_t(d["wrapT" ]); |
| 3564 | } else { |
| 3565 | sampler->set_wrap_t(GLTFTextureSampler::WrapMode::DEFAULT); |
| 3566 | } |
| 3567 | |
| 3568 | p_state->texture_samplers.push_back(sampler); |
| 3569 | } |
| 3570 | |
| 3571 | return OK; |
| 3572 | } |
| 3573 | |
| 3574 | Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { |
| 3575 | Array materials; |
| 3576 | for (int32_t i = 0; i < p_state->materials.size(); i++) { |
| 3577 | Dictionary d; |
| 3578 | Ref<Material> material = p_state->materials[i]; |
| 3579 | if (material.is_null()) { |
| 3580 | materials.push_back(d); |
| 3581 | continue; |
| 3582 | } |
| 3583 | if (!material->get_name().is_empty()) { |
| 3584 | d["name" ] = _gen_unique_name(p_state, material->get_name()); |
| 3585 | } |
| 3586 | |
| 3587 | Ref<BaseMaterial3D> base_material = material; |
| 3588 | if (base_material.is_null()) { |
| 3589 | materials.push_back(d); |
| 3590 | continue; |
| 3591 | } |
| 3592 | |
| 3593 | Dictionary mr; |
| 3594 | { |
| 3595 | Array arr; |
| 3596 | const Color c = base_material->get_albedo().srgb_to_linear(); |
| 3597 | arr.push_back(c.r); |
| 3598 | arr.push_back(c.g); |
| 3599 | arr.push_back(c.b); |
| 3600 | arr.push_back(c.a); |
| 3601 | mr["baseColorFactor" ] = arr; |
| 3602 | } |
| 3603 | if (_image_format != "None" ) { |
| 3604 | Dictionary bct; |
| 3605 | Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); |
| 3606 | GLTFTextureIndex gltf_texture_index = -1; |
| 3607 | |
| 3608 | if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { |
| 3609 | albedo_texture->set_name(material->get_name() + "_albedo" ); |
| 3610 | gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); |
| 3611 | } |
| 3612 | if (gltf_texture_index != -1) { |
| 3613 | bct["index" ] = gltf_texture_index; |
| 3614 | Dictionary extensions = _serialize_texture_transform_uv1(material); |
| 3615 | if (!extensions.is_empty()) { |
| 3616 | bct["extensions" ] = extensions; |
| 3617 | p_state->use_khr_texture_transform = true; |
| 3618 | } |
| 3619 | mr["baseColorTexture" ] = bct; |
| 3620 | } |
| 3621 | } |
| 3622 | |
| 3623 | mr["metallicFactor" ] = base_material->get_metallic(); |
| 3624 | mr["roughnessFactor" ] = base_material->get_roughness(); |
| 3625 | bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); |
| 3626 | bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); |
| 3627 | bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); |
| 3628 | if (has_ao || has_roughness || has_metalness) { |
| 3629 | Dictionary mrt; |
| 3630 | Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); |
| 3631 | BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); |
| 3632 | Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); |
| 3633 | BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); |
| 3634 | Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); |
| 3635 | BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); |
| 3636 | Ref<ImageTexture> orm_texture; |
| 3637 | orm_texture.instantiate(); |
| 3638 | Ref<Image> orm_image; |
| 3639 | orm_image.instantiate(); |
| 3640 | int32_t height = 0; |
| 3641 | int32_t width = 0; |
| 3642 | Ref<Image> ao_image; |
| 3643 | if (has_ao) { |
| 3644 | height = ao_texture->get_height(); |
| 3645 | width = ao_texture->get_width(); |
| 3646 | ao_image = ao_texture->get_image(); |
| 3647 | Ref<ImageTexture> img_tex = ao_image; |
| 3648 | if (img_tex.is_valid()) { |
| 3649 | ao_image = img_tex->get_image(); |
| 3650 | } |
| 3651 | if (ao_image->is_compressed()) { |
| 3652 | ao_image->decompress(); |
| 3653 | } |
| 3654 | } |
| 3655 | Ref<Image> roughness_image; |
| 3656 | if (has_roughness) { |
| 3657 | height = roughness_texture->get_height(); |
| 3658 | width = roughness_texture->get_width(); |
| 3659 | roughness_image = roughness_texture->get_image(); |
| 3660 | Ref<ImageTexture> img_tex = roughness_image; |
| 3661 | if (img_tex.is_valid()) { |
| 3662 | roughness_image = img_tex->get_image(); |
| 3663 | } |
| 3664 | if (roughness_image->is_compressed()) { |
| 3665 | roughness_image->decompress(); |
| 3666 | } |
| 3667 | } |
| 3668 | Ref<Image> metallness_image; |
| 3669 | if (has_metalness) { |
| 3670 | height = metallic_texture->get_height(); |
| 3671 | width = metallic_texture->get_width(); |
| 3672 | metallness_image = metallic_texture->get_image(); |
| 3673 | Ref<ImageTexture> img_tex = metallness_image; |
| 3674 | if (img_tex.is_valid()) { |
| 3675 | metallness_image = img_tex->get_image(); |
| 3676 | } |
| 3677 | if (metallness_image->is_compressed()) { |
| 3678 | metallness_image->decompress(); |
| 3679 | } |
| 3680 | } |
| 3681 | Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); |
| 3682 | if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { |
| 3683 | height = albedo_texture->get_height(); |
| 3684 | width = albedo_texture->get_width(); |
| 3685 | } |
| 3686 | orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); |
| 3687 | if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { |
| 3688 | ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); |
| 3689 | } |
| 3690 | if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { |
| 3691 | roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); |
| 3692 | } |
| 3693 | if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { |
| 3694 | metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); |
| 3695 | } |
| 3696 | for (int32_t h = 0; h < height; h++) { |
| 3697 | for (int32_t w = 0; w < width; w++) { |
| 3698 | Color c = Color(1.0f, 1.0f, 1.0f); |
| 3699 | if (has_ao) { |
| 3700 | if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { |
| 3701 | c.r = ao_image->get_pixel(w, h).r; |
| 3702 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { |
| 3703 | c.r = ao_image->get_pixel(w, h).g; |
| 3704 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { |
| 3705 | c.r = ao_image->get_pixel(w, h).b; |
| 3706 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { |
| 3707 | c.r = ao_image->get_pixel(w, h).a; |
| 3708 | } |
| 3709 | } |
| 3710 | if (has_roughness) { |
| 3711 | if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { |
| 3712 | c.g = roughness_image->get_pixel(w, h).r; |
| 3713 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { |
| 3714 | c.g = roughness_image->get_pixel(w, h).g; |
| 3715 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { |
| 3716 | c.g = roughness_image->get_pixel(w, h).b; |
| 3717 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { |
| 3718 | c.g = roughness_image->get_pixel(w, h).a; |
| 3719 | } |
| 3720 | } |
| 3721 | if (has_metalness) { |
| 3722 | if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { |
| 3723 | c.b = metallness_image->get_pixel(w, h).r; |
| 3724 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { |
| 3725 | c.b = metallness_image->get_pixel(w, h).g; |
| 3726 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { |
| 3727 | c.b = metallness_image->get_pixel(w, h).b; |
| 3728 | } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { |
| 3729 | c.b = metallness_image->get_pixel(w, h).a; |
| 3730 | } |
| 3731 | } |
| 3732 | orm_image->set_pixel(w, h, c); |
| 3733 | } |
| 3734 | } |
| 3735 | orm_image->generate_mipmaps(); |
| 3736 | orm_texture->set_image(orm_image); |
| 3737 | GLTFTextureIndex orm_texture_index = -1; |
| 3738 | if (has_ao || has_roughness || has_metalness) { |
| 3739 | orm_texture->set_name(material->get_name() + "_orm" ); |
| 3740 | orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); |
| 3741 | } |
| 3742 | if (has_ao) { |
| 3743 | Dictionary occt; |
| 3744 | occt["index" ] = orm_texture_index; |
| 3745 | d["occlusionTexture" ] = occt; |
| 3746 | } |
| 3747 | if (has_roughness || has_metalness) { |
| 3748 | mrt["index" ] = orm_texture_index; |
| 3749 | Dictionary extensions = _serialize_texture_transform_uv1(material); |
| 3750 | if (!extensions.is_empty()) { |
| 3751 | mrt["extensions" ] = extensions; |
| 3752 | p_state->use_khr_texture_transform = true; |
| 3753 | } |
| 3754 | mr["metallicRoughnessTexture" ] = mrt; |
| 3755 | } |
| 3756 | } |
| 3757 | |
| 3758 | d["pbrMetallicRoughness" ] = mr; |
| 3759 | if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { |
| 3760 | Dictionary nt; |
| 3761 | Ref<ImageTexture> tex; |
| 3762 | tex.instantiate(); |
| 3763 | { |
| 3764 | Ref<Texture2D> normal_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); |
| 3765 | if (normal_texture.is_valid()) { |
| 3766 | // Code for uncompressing RG normal maps |
| 3767 | Ref<Image> img = normal_texture->get_image(); |
| 3768 | if (img.is_valid()) { |
| 3769 | Ref<ImageTexture> img_tex = img; |
| 3770 | if (img_tex.is_valid()) { |
| 3771 | img = img_tex->get_image(); |
| 3772 | } |
| 3773 | img->decompress(); |
| 3774 | img->convert(Image::FORMAT_RGBA8); |
| 3775 | img->convert_ra_rgba8_to_rg(); |
| 3776 | for (int32_t y = 0; y < img->get_height(); y++) { |
| 3777 | for (int32_t x = 0; x < img->get_width(); x++) { |
| 3778 | Color c = img->get_pixel(x, y); |
| 3779 | Vector2 red_green = Vector2(c.r, c.g); |
| 3780 | red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); |
| 3781 | float blue = 1.0f - red_green.dot(red_green); |
| 3782 | blue = MAX(0.0f, blue); |
| 3783 | c.b = Math::sqrt(blue); |
| 3784 | img->set_pixel(x, y, c); |
| 3785 | } |
| 3786 | } |
| 3787 | tex->set_image(img); |
| 3788 | } |
| 3789 | } |
| 3790 | } |
| 3791 | GLTFTextureIndex gltf_texture_index = -1; |
| 3792 | if (tex.is_valid() && tex->get_image().is_valid()) { |
| 3793 | tex->set_name(material->get_name() + "_normal" ); |
| 3794 | gltf_texture_index = _set_texture(p_state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); |
| 3795 | } |
| 3796 | nt["scale" ] = base_material->get_normal_scale(); |
| 3797 | if (gltf_texture_index != -1) { |
| 3798 | nt["index" ] = gltf_texture_index; |
| 3799 | d["normalTexture" ] = nt; |
| 3800 | } |
| 3801 | } |
| 3802 | |
| 3803 | if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { |
| 3804 | const Color c = base_material->get_emission().linear_to_srgb(); |
| 3805 | Array arr; |
| 3806 | arr.push_back(c.r); |
| 3807 | arr.push_back(c.g); |
| 3808 | arr.push_back(c.b); |
| 3809 | d["emissiveFactor" ] = arr; |
| 3810 | } |
| 3811 | |
| 3812 | if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { |
| 3813 | Dictionary et; |
| 3814 | Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); |
| 3815 | GLTFTextureIndex gltf_texture_index = -1; |
| 3816 | if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { |
| 3817 | emission_texture->set_name(material->get_name() + "_emission" ); |
| 3818 | gltf_texture_index = _set_texture(p_state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); |
| 3819 | } |
| 3820 | |
| 3821 | if (gltf_texture_index != -1) { |
| 3822 | et["index" ] = gltf_texture_index; |
| 3823 | d["emissiveTexture" ] = et; |
| 3824 | } |
| 3825 | } |
| 3826 | |
| 3827 | const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; |
| 3828 | if (ds) { |
| 3829 | d["doubleSided" ] = ds; |
| 3830 | } |
| 3831 | |
| 3832 | if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { |
| 3833 | d["alphaMode" ] = "MASK" ; |
| 3834 | d["alphaCutoff" ] = base_material->get_alpha_scissor_threshold(); |
| 3835 | } else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { |
| 3836 | d["alphaMode" ] = "BLEND" ; |
| 3837 | } |
| 3838 | |
| 3839 | Dictionary extensions; |
| 3840 | if (base_material->get_shading_mode() == BaseMaterial3D::SHADING_MODE_UNSHADED) { |
| 3841 | Dictionary mat_unlit; |
| 3842 | extensions["KHR_materials_unlit" ] = mat_unlit; |
| 3843 | p_state->add_used_extension("KHR_materials_unlit" ); |
| 3844 | } |
| 3845 | if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && !Math::is_equal_approx(base_material->get_emission_energy_multiplier(), 1.0f)) { |
| 3846 | Dictionary mat_emissive_strength; |
| 3847 | mat_emissive_strength["emissiveStrength" ] = base_material->get_emission_energy_multiplier(); |
| 3848 | extensions["KHR_materials_emissive_strength" ] = mat_emissive_strength; |
| 3849 | p_state->add_used_extension("KHR_materials_emissive_strength" ); |
| 3850 | } |
| 3851 | d["extensions" ] = extensions; |
| 3852 | |
| 3853 | materials.push_back(d); |
| 3854 | } |
| 3855 | if (!materials.size()) { |
| 3856 | return OK; |
| 3857 | } |
| 3858 | p_state->json["materials" ] = materials; |
| 3859 | print_verbose("Total materials: " + itos(p_state->materials.size())); |
| 3860 | |
| 3861 | return OK; |
| 3862 | } |
| 3863 | |
| 3864 | Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { |
| 3865 | if (!p_state->json.has("materials" )) { |
| 3866 | return OK; |
| 3867 | } |
| 3868 | |
| 3869 | const Array &materials = p_state->json["materials" ]; |
| 3870 | for (GLTFMaterialIndex i = 0; i < materials.size(); i++) { |
| 3871 | const Dictionary &material_dict = materials[i]; |
| 3872 | |
| 3873 | Ref<StandardMaterial3D> material; |
| 3874 | material.instantiate(); |
| 3875 | if (material_dict.has("name" ) && !String(material_dict["name" ]).is_empty()) { |
| 3876 | material->set_name(material_dict["name" ]); |
| 3877 | } else { |
| 3878 | material->set_name(vformat("material_%s" , itos(i))); |
| 3879 | } |
| 3880 | material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); |
| 3881 | Dictionary material_extensions; |
| 3882 | if (material_dict.has("extensions" )) { |
| 3883 | material_extensions = material_dict["extensions" ]; |
| 3884 | } |
| 3885 | |
| 3886 | if (material_extensions.has("KHR_materials_unlit" )) { |
| 3887 | material->set_shading_mode(BaseMaterial3D::SHADING_MODE_UNSHADED); |
| 3888 | } |
| 3889 | |
| 3890 | if (material_extensions.has("KHR_materials_emissive_strength" )) { |
| 3891 | Dictionary emissive_strength = material_extensions["KHR_materials_emissive_strength" ]; |
| 3892 | if (emissive_strength.has("emissiveStrength" )) { |
| 3893 | material->set_emission_energy_multiplier(emissive_strength["emissiveStrength" ]); |
| 3894 | } |
| 3895 | } |
| 3896 | |
| 3897 | if (material_extensions.has("KHR_materials_pbrSpecularGlossiness" )) { |
| 3898 | WARN_PRINT("Material uses a specular and glossiness workflow. Textures will be converted to roughness and metallic workflow, which may not be 100% accurate." ); |
| 3899 | Dictionary sgm = material_extensions["KHR_materials_pbrSpecularGlossiness" ]; |
| 3900 | |
| 3901 | Ref<GLTFSpecGloss> spec_gloss; |
| 3902 | spec_gloss.instantiate(); |
| 3903 | if (sgm.has("diffuseTexture" )) { |
| 3904 | const Dictionary &diffuse_texture_dict = sgm["diffuseTexture" ]; |
| 3905 | if (diffuse_texture_dict.has("index" )) { |
| 3906 | Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(p_state, diffuse_texture_dict["index" ]); |
| 3907 | if (diffuse_sampler.is_valid()) { |
| 3908 | material->set_texture_filter(diffuse_sampler->get_filter_mode()); |
| 3909 | material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode()); |
| 3910 | } |
| 3911 | Ref<Texture2D> diffuse_texture = _get_texture(p_state, diffuse_texture_dict["index" ], TEXTURE_TYPE_GENERIC); |
| 3912 | if (diffuse_texture.is_valid()) { |
| 3913 | spec_gloss->diffuse_img = diffuse_texture->get_image(); |
| 3914 | material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture); |
| 3915 | } |
| 3916 | } |
| 3917 | } |
| 3918 | if (sgm.has("diffuseFactor" )) { |
| 3919 | const Array &arr = sgm["diffuseFactor" ]; |
| 3920 | ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); |
| 3921 | const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb(); |
| 3922 | spec_gloss->diffuse_factor = c; |
| 3923 | material->set_albedo(spec_gloss->diffuse_factor); |
| 3924 | } |
| 3925 | |
| 3926 | if (sgm.has("specularFactor" )) { |
| 3927 | const Array &arr = sgm["specularFactor" ]; |
| 3928 | ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); |
| 3929 | spec_gloss->specular_factor = Color(arr[0], arr[1], arr[2]); |
| 3930 | } |
| 3931 | |
| 3932 | if (sgm.has("glossinessFactor" )) { |
| 3933 | spec_gloss->gloss_factor = sgm["glossinessFactor" ]; |
| 3934 | material->set_roughness(1.0f - CLAMP(spec_gloss->gloss_factor, 0.0f, 1.0f)); |
| 3935 | } |
| 3936 | if (sgm.has("specularGlossinessTexture" )) { |
| 3937 | const Dictionary &spec_gloss_texture = sgm["specularGlossinessTexture" ]; |
| 3938 | if (spec_gloss_texture.has("index" )) { |
| 3939 | const Ref<Texture2D> orig_texture = _get_texture(p_state, spec_gloss_texture["index" ], TEXTURE_TYPE_GENERIC); |
| 3940 | if (orig_texture.is_valid()) { |
| 3941 | spec_gloss->spec_gloss_img = orig_texture->get_image(); |
| 3942 | } |
| 3943 | } |
| 3944 | } |
| 3945 | spec_gloss_to_rough_metal(spec_gloss, material); |
| 3946 | |
| 3947 | } else if (material_dict.has("pbrMetallicRoughness" )) { |
| 3948 | const Dictionary &mr = material_dict["pbrMetallicRoughness" ]; |
| 3949 | if (mr.has("baseColorFactor" )) { |
| 3950 | const Array &arr = mr["baseColorFactor" ]; |
| 3951 | ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); |
| 3952 | const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb(); |
| 3953 | material->set_albedo(c); |
| 3954 | } |
| 3955 | |
| 3956 | if (mr.has("baseColorTexture" )) { |
| 3957 | const Dictionary &bct = mr["baseColorTexture" ]; |
| 3958 | if (bct.has("index" )) { |
| 3959 | Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(p_state, bct["index" ]); |
| 3960 | material->set_texture_filter(bct_sampler->get_filter_mode()); |
| 3961 | material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode()); |
| 3962 | material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC)); |
| 3963 | } |
| 3964 | if (!mr.has("baseColorFactor" )) { |
| 3965 | material->set_albedo(Color(1, 1, 1)); |
| 3966 | } |
| 3967 | _set_texture_transform_uv1(bct, material); |
| 3968 | } |
| 3969 | |
| 3970 | if (mr.has("metallicFactor" )) { |
| 3971 | material->set_metallic(mr["metallicFactor" ]); |
| 3972 | } else { |
| 3973 | material->set_metallic(1.0); |
| 3974 | } |
| 3975 | |
| 3976 | if (mr.has("roughnessFactor" )) { |
| 3977 | material->set_roughness(mr["roughnessFactor" ]); |
| 3978 | } else { |
| 3979 | material->set_roughness(1.0); |
| 3980 | } |
| 3981 | |
| 3982 | if (mr.has("metallicRoughnessTexture" )) { |
| 3983 | const Dictionary &bct = mr["metallicRoughnessTexture" ]; |
| 3984 | if (bct.has("index" )) { |
| 3985 | const Ref<Texture2D> t = _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC); |
| 3986 | material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, t); |
| 3987 | material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE); |
| 3988 | material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, t); |
| 3989 | material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN); |
| 3990 | if (!mr.has("metallicFactor" )) { |
| 3991 | material->set_metallic(1); |
| 3992 | } |
| 3993 | if (!mr.has("roughnessFactor" )) { |
| 3994 | material->set_roughness(1); |
| 3995 | } |
| 3996 | } |
| 3997 | } |
| 3998 | } |
| 3999 | |
| 4000 | if (material_dict.has("normalTexture" )) { |
| 4001 | const Dictionary &bct = material_dict["normalTexture" ]; |
| 4002 | if (bct.has("index" )) { |
| 4003 | material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_NORMAL)); |
| 4004 | material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true); |
| 4005 | } |
| 4006 | if (bct.has("scale" )) { |
| 4007 | material->set_normal_scale(bct["scale" ]); |
| 4008 | } |
| 4009 | } |
| 4010 | if (material_dict.has("occlusionTexture" )) { |
| 4011 | const Dictionary &bct = material_dict["occlusionTexture" ]; |
| 4012 | if (bct.has("index" )) { |
| 4013 | material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC)); |
| 4014 | material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED); |
| 4015 | material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true); |
| 4016 | } |
| 4017 | } |
| 4018 | |
| 4019 | if (material_dict.has("emissiveFactor" )) { |
| 4020 | const Array &arr = material_dict["emissiveFactor" ]; |
| 4021 | ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); |
| 4022 | const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); |
| 4023 | material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); |
| 4024 | |
| 4025 | material->set_emission(c); |
| 4026 | } |
| 4027 | |
| 4028 | if (material_dict.has("emissiveTexture" )) { |
| 4029 | const Dictionary &bct = material_dict["emissiveTexture" ]; |
| 4030 | if (bct.has("index" )) { |
| 4031 | material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC)); |
| 4032 | material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); |
| 4033 | material->set_emission(Color(0, 0, 0)); |
| 4034 | } |
| 4035 | } |
| 4036 | |
| 4037 | if (material_dict.has("doubleSided" )) { |
| 4038 | const bool ds = material_dict["doubleSided" ]; |
| 4039 | if (ds) { |
| 4040 | material->set_cull_mode(BaseMaterial3D::CULL_DISABLED); |
| 4041 | } |
| 4042 | } |
| 4043 | if (material_dict.has("alphaMode" )) { |
| 4044 | const String &am = material_dict["alphaMode" ]; |
| 4045 | if (am == "BLEND" ) { |
| 4046 | material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); |
| 4047 | } else if (am == "MASK" ) { |
| 4048 | material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR); |
| 4049 | if (material_dict.has("alphaCutoff" )) { |
| 4050 | material->set_alpha_scissor_threshold(material_dict["alphaCutoff" ]); |
| 4051 | } else { |
| 4052 | material->set_alpha_scissor_threshold(0.5f); |
| 4053 | } |
| 4054 | } |
| 4055 | } |
| 4056 | p_state->materials.push_back(material); |
| 4057 | } |
| 4058 | |
| 4059 | print_verbose("Total materials: " + itos(p_state->materials.size())); |
| 4060 | |
| 4061 | return OK; |
| 4062 | } |
| 4063 | |
| 4064 | void GLTFDocument::_set_texture_transform_uv1(const Dictionary &p_dict, Ref<BaseMaterial3D> p_material) { |
| 4065 | if (p_dict.has("extensions" )) { |
| 4066 | const Dictionary &extensions = p_dict["extensions" ]; |
| 4067 | if (extensions.has("KHR_texture_transform" )) { |
| 4068 | if (p_material.is_valid()) { |
| 4069 | const Dictionary &texture_transform = extensions["KHR_texture_transform" ]; |
| 4070 | const Array &offset_arr = texture_transform["offset" ]; |
| 4071 | if (offset_arr.size() == 2) { |
| 4072 | const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); |
| 4073 | p_material->set_uv1_offset(offset_vector3); |
| 4074 | } |
| 4075 | |
| 4076 | const Array &scale_arr = texture_transform["scale" ]; |
| 4077 | if (scale_arr.size() == 2) { |
| 4078 | const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); |
| 4079 | p_material->set_uv1_scale(scale_vector3); |
| 4080 | } |
| 4081 | } |
| 4082 | } |
| 4083 | } |
| 4084 | } |
| 4085 | |
| 4086 | void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) { |
| 4087 | if (r_spec_gloss.is_null()) { |
| 4088 | return; |
| 4089 | } |
| 4090 | if (r_spec_gloss->spec_gloss_img.is_null()) { |
| 4091 | return; |
| 4092 | } |
| 4093 | if (r_spec_gloss->diffuse_img.is_null()) { |
| 4094 | return; |
| 4095 | } |
| 4096 | if (p_material.is_null()) { |
| 4097 | return; |
| 4098 | } |
| 4099 | bool has_roughness = false; |
| 4100 | bool has_metal = false; |
| 4101 | p_material->set_roughness(1.0f); |
| 4102 | p_material->set_metallic(1.0f); |
| 4103 | Ref<Image> rm_img = Image::create_empty(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8); |
| 4104 | r_spec_gloss->spec_gloss_img->decompress(); |
| 4105 | if (r_spec_gloss->diffuse_img.is_valid()) { |
| 4106 | r_spec_gloss->diffuse_img->decompress(); |
| 4107 | r_spec_gloss->diffuse_img->resize(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), Image::INTERPOLATE_LANCZOS); |
| 4108 | r_spec_gloss->spec_gloss_img->resize(r_spec_gloss->diffuse_img->get_width(), r_spec_gloss->diffuse_img->get_height(), Image::INTERPOLATE_LANCZOS); |
| 4109 | } |
| 4110 | for (int32_t y = 0; y < r_spec_gloss->spec_gloss_img->get_height(); y++) { |
| 4111 | for (int32_t x = 0; x < r_spec_gloss->spec_gloss_img->get_width(); x++) { |
| 4112 | const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).srgb_to_linear(); |
| 4113 | Color specular = Color(specular_pixel.r, specular_pixel.g, specular_pixel.b); |
| 4114 | specular *= r_spec_gloss->specular_factor; |
| 4115 | Color diffuse = Color(1.0f, 1.0f, 1.0f); |
| 4116 | diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).srgb_to_linear(); |
| 4117 | float metallic = 0.0f; |
| 4118 | Color base_color; |
| 4119 | spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic); |
| 4120 | Color mr = Color(1.0f, 1.0f, 1.0f); |
| 4121 | mr.g = specular_pixel.a; |
| 4122 | mr.b = metallic; |
| 4123 | if (!Math::is_equal_approx(mr.g, 1.0f)) { |
| 4124 | has_roughness = true; |
| 4125 | } |
| 4126 | if (!Math::is_zero_approx(mr.b)) { |
| 4127 | has_metal = true; |
| 4128 | } |
| 4129 | mr.g *= r_spec_gloss->gloss_factor; |
| 4130 | mr.g = 1.0f - mr.g; |
| 4131 | rm_img->set_pixel(x, y, mr); |
| 4132 | if (r_spec_gloss->diffuse_img.is_valid()) { |
| 4133 | r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.linear_to_srgb()); |
| 4134 | } |
| 4135 | } |
| 4136 | } |
| 4137 | rm_img->generate_mipmaps(); |
| 4138 | r_spec_gloss->diffuse_img->generate_mipmaps(); |
| 4139 | p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, ImageTexture::create_from_image(r_spec_gloss->diffuse_img)); |
| 4140 | Ref<ImageTexture> rm_image_texture = ImageTexture::create_from_image(rm_img); |
| 4141 | if (has_roughness) { |
| 4142 | p_material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, rm_image_texture); |
| 4143 | p_material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN); |
| 4144 | } |
| 4145 | |
| 4146 | if (has_metal) { |
| 4147 | p_material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, rm_image_texture); |
| 4148 | p_material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE); |
| 4149 | } |
| 4150 | } |
| 4151 | |
| 4152 | void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor, const Color &p_diffuse, Color &r_base_color, float &r_metallic) { |
| 4153 | const Color DIELECTRIC_SPECULAR = Color(0.04f, 0.04f, 0.04f); |
| 4154 | Color specular = Color(p_specular_factor.r, p_specular_factor.g, p_specular_factor.b); |
| 4155 | const float one_minus_specular_strength = 1.0f - get_max_component(specular); |
| 4156 | const float dielectric_specular_red = DIELECTRIC_SPECULAR.r; |
| 4157 | float brightness_diffuse = get_perceived_brightness(p_diffuse); |
| 4158 | const float brightness_specular = get_perceived_brightness(specular); |
| 4159 | r_metallic = solve_metallic(dielectric_specular_red, brightness_diffuse, brightness_specular, one_minus_specular_strength); |
| 4160 | const float one_minus_metallic = 1.0f - r_metallic; |
| 4161 | const Color base_color_from_diffuse = p_diffuse * (one_minus_specular_strength / (1.0f - dielectric_specular_red) / MAX(one_minus_metallic, CMP_EPSILON)); |
| 4162 | const Color base_color_from_specular = (specular - (DIELECTRIC_SPECULAR * (one_minus_metallic))) * (1.0f / MAX(r_metallic, CMP_EPSILON)); |
| 4163 | r_base_color.r = Math::lerp(base_color_from_diffuse.r, base_color_from_specular.r, r_metallic * r_metallic); |
| 4164 | r_base_color.g = Math::lerp(base_color_from_diffuse.g, base_color_from_specular.g, r_metallic * r_metallic); |
| 4165 | r_base_color.b = Math::lerp(base_color_from_diffuse.b, base_color_from_specular.b, r_metallic * r_metallic); |
| 4166 | r_base_color.a = p_diffuse.a; |
| 4167 | r_base_color = r_base_color.clamp(); |
| 4168 | } |
| 4169 | |
| 4170 | GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> p_state, const Vector<GLTFNodeIndex> &p_subset) { |
| 4171 | int highest = -1; |
| 4172 | GLTFNodeIndex best_node = -1; |
| 4173 | |
| 4174 | for (int i = 0; i < p_subset.size(); ++i) { |
| 4175 | const GLTFNodeIndex node_i = p_subset[i]; |
| 4176 | const Ref<GLTFNode> node = p_state->nodes[node_i]; |
| 4177 | |
| 4178 | if (highest == -1 || node->height < highest) { |
| 4179 | highest = node->height; |
| 4180 | best_node = node_i; |
| 4181 | } |
| 4182 | } |
| 4183 | |
| 4184 | return best_node; |
| 4185 | } |
| 4186 | |
| 4187 | bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin, const GLTFNodeIndex p_node_index) { |
| 4188 | bool found_joint = false; |
| 4189 | |
| 4190 | for (int i = 0; i < p_state->nodes[p_node_index]->children.size(); ++i) { |
| 4191 | found_joint |= _capture_nodes_in_skin(p_state, p_skin, p_state->nodes[p_node_index]->children[i]); |
| 4192 | } |
| 4193 | |
| 4194 | if (found_joint) { |
| 4195 | // Mark it if we happen to find another skins joint... |
| 4196 | if (p_state->nodes[p_node_index]->joint && p_skin->joints.find(p_node_index) < 0) { |
| 4197 | p_skin->joints.push_back(p_node_index); |
| 4198 | } else if (p_skin->non_joints.find(p_node_index) < 0) { |
| 4199 | p_skin->non_joints.push_back(p_node_index); |
| 4200 | } |
| 4201 | } |
| 4202 | |
| 4203 | if (p_skin->joints.find(p_node_index) > 0) { |
| 4204 | return true; |
| 4205 | } |
| 4206 | |
| 4207 | return false; |
| 4208 | } |
| 4209 | |
| 4210 | void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { |
| 4211 | DisjointSet<GLTFNodeIndex> disjoint_set; |
| 4212 | |
| 4213 | for (int i = 0; i < p_skin->joints.size(); ++i) { |
| 4214 | const GLTFNodeIndex node_index = p_skin->joints[i]; |
| 4215 | const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; |
| 4216 | disjoint_set.insert(node_index); |
| 4217 | |
| 4218 | if (p_skin->joints.find(parent) >= 0) { |
| 4219 | disjoint_set.create_union(parent, node_index); |
| 4220 | } |
| 4221 | } |
| 4222 | |
| 4223 | Vector<GLTFNodeIndex> roots; |
| 4224 | disjoint_set.get_representatives(roots); |
| 4225 | |
| 4226 | if (roots.size() <= 1) { |
| 4227 | return; |
| 4228 | } |
| 4229 | |
| 4230 | int maxHeight = -1; |
| 4231 | |
| 4232 | // Determine the max height rooted tree |
| 4233 | for (int i = 0; i < roots.size(); ++i) { |
| 4234 | const GLTFNodeIndex root = roots[i]; |
| 4235 | |
| 4236 | if (maxHeight == -1 || p_state->nodes[root]->height < maxHeight) { |
| 4237 | maxHeight = p_state->nodes[root]->height; |
| 4238 | } |
| 4239 | } |
| 4240 | |
| 4241 | // Go up the tree till all of the multiple roots of the skin are at the same hierarchy level. |
| 4242 | // This sucks, but 99% of all game engines (not just Godot) would have this same issue. |
| 4243 | for (int i = 0; i < roots.size(); ++i) { |
| 4244 | GLTFNodeIndex current_node = roots[i]; |
| 4245 | while (p_state->nodes[current_node]->height > maxHeight) { |
| 4246 | GLTFNodeIndex parent = p_state->nodes[current_node]->parent; |
| 4247 | |
| 4248 | if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) { |
| 4249 | p_skin->joints.push_back(parent); |
| 4250 | } else if (p_skin->non_joints.find(parent) < 0) { |
| 4251 | p_skin->non_joints.push_back(parent); |
| 4252 | } |
| 4253 | |
| 4254 | current_node = parent; |
| 4255 | } |
| 4256 | |
| 4257 | // replace the roots |
| 4258 | roots.write[i] = current_node; |
| 4259 | } |
| 4260 | |
| 4261 | // Climb up the tree until they all have the same parent |
| 4262 | bool all_same; |
| 4263 | |
| 4264 | do { |
| 4265 | all_same = true; |
| 4266 | const GLTFNodeIndex first_parent = p_state->nodes[roots[0]]->parent; |
| 4267 | |
| 4268 | for (int i = 1; i < roots.size(); ++i) { |
| 4269 | all_same &= (first_parent == p_state->nodes[roots[i]]->parent); |
| 4270 | } |
| 4271 | |
| 4272 | if (!all_same) { |
| 4273 | for (int i = 0; i < roots.size(); ++i) { |
| 4274 | const GLTFNodeIndex current_node = roots[i]; |
| 4275 | const GLTFNodeIndex parent = p_state->nodes[current_node]->parent; |
| 4276 | |
| 4277 | if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) { |
| 4278 | p_skin->joints.push_back(parent); |
| 4279 | } else if (p_skin->non_joints.find(parent) < 0) { |
| 4280 | p_skin->non_joints.push_back(parent); |
| 4281 | } |
| 4282 | |
| 4283 | roots.write[i] = parent; |
| 4284 | } |
| 4285 | } |
| 4286 | |
| 4287 | } while (!all_same); |
| 4288 | } |
| 4289 | |
| 4290 | Error GLTFDocument::_expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { |
| 4291 | _capture_nodes_for_multirooted_skin(p_state, p_skin); |
| 4292 | |
| 4293 | // Grab all nodes that lay in between skin joints/nodes |
| 4294 | DisjointSet<GLTFNodeIndex> disjoint_set; |
| 4295 | |
| 4296 | Vector<GLTFNodeIndex> all_skin_nodes; |
| 4297 | all_skin_nodes.append_array(p_skin->joints); |
| 4298 | all_skin_nodes.append_array(p_skin->non_joints); |
| 4299 | |
| 4300 | for (int i = 0; i < all_skin_nodes.size(); ++i) { |
| 4301 | const GLTFNodeIndex node_index = all_skin_nodes[i]; |
| 4302 | const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; |
| 4303 | disjoint_set.insert(node_index); |
| 4304 | |
| 4305 | if (all_skin_nodes.find(parent) >= 0) { |
| 4306 | disjoint_set.create_union(parent, node_index); |
| 4307 | } |
| 4308 | } |
| 4309 | |
| 4310 | Vector<GLTFNodeIndex> out_owners; |
| 4311 | disjoint_set.get_representatives(out_owners); |
| 4312 | |
| 4313 | Vector<GLTFNodeIndex> out_roots; |
| 4314 | |
| 4315 | for (int i = 0; i < out_owners.size(); ++i) { |
| 4316 | Vector<GLTFNodeIndex> set; |
| 4317 | disjoint_set.get_members(set, out_owners[i]); |
| 4318 | |
| 4319 | const GLTFNodeIndex root = _find_highest_node(p_state, set); |
| 4320 | ERR_FAIL_COND_V(root < 0, FAILED); |
| 4321 | out_roots.push_back(root); |
| 4322 | } |
| 4323 | |
| 4324 | out_roots.sort(); |
| 4325 | |
| 4326 | for (int i = 0; i < out_roots.size(); ++i) { |
| 4327 | _capture_nodes_in_skin(p_state, p_skin, out_roots[i]); |
| 4328 | } |
| 4329 | |
| 4330 | p_skin->roots = out_roots; |
| 4331 | |
| 4332 | return OK; |
| 4333 | } |
| 4334 | |
| 4335 | Error GLTFDocument::_verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { |
| 4336 | // This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is) |
| 4337 | // In case additional interpolating logic is added to the skins, this will help ensure that you |
| 4338 | // do not cause it to self implode into a fiery blaze |
| 4339 | |
| 4340 | // We are going to re-calculate the root nodes and compare them to the ones saved in the skin, |
| 4341 | // then ensure the multiple trees (if they exist) are on the same sublevel |
| 4342 | |
| 4343 | // Grab all nodes that lay in between skin joints/nodes |
| 4344 | DisjointSet<GLTFNodeIndex> disjoint_set; |
| 4345 | |
| 4346 | Vector<GLTFNodeIndex> all_skin_nodes; |
| 4347 | all_skin_nodes.append_array(p_skin->joints); |
| 4348 | all_skin_nodes.append_array(p_skin->non_joints); |
| 4349 | |
| 4350 | for (int i = 0; i < all_skin_nodes.size(); ++i) { |
| 4351 | const GLTFNodeIndex node_index = all_skin_nodes[i]; |
| 4352 | const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; |
| 4353 | disjoint_set.insert(node_index); |
| 4354 | |
| 4355 | if (all_skin_nodes.find(parent) >= 0) { |
| 4356 | disjoint_set.create_union(parent, node_index); |
| 4357 | } |
| 4358 | } |
| 4359 | |
| 4360 | Vector<GLTFNodeIndex> out_owners; |
| 4361 | disjoint_set.get_representatives(out_owners); |
| 4362 | |
| 4363 | Vector<GLTFNodeIndex> out_roots; |
| 4364 | |
| 4365 | for (int i = 0; i < out_owners.size(); ++i) { |
| 4366 | Vector<GLTFNodeIndex> set; |
| 4367 | disjoint_set.get_members(set, out_owners[i]); |
| 4368 | |
| 4369 | const GLTFNodeIndex root = _find_highest_node(p_state, set); |
| 4370 | ERR_FAIL_COND_V(root < 0, FAILED); |
| 4371 | out_roots.push_back(root); |
| 4372 | } |
| 4373 | |
| 4374 | out_roots.sort(); |
| 4375 | |
| 4376 | ERR_FAIL_COND_V(out_roots.size() == 0, FAILED); |
| 4377 | |
| 4378 | // Make sure the roots are the exact same (they better be) |
| 4379 | ERR_FAIL_COND_V(out_roots.size() != p_skin->roots.size(), FAILED); |
| 4380 | for (int i = 0; i < out_roots.size(); ++i) { |
| 4381 | ERR_FAIL_COND_V(out_roots[i] != p_skin->roots[i], FAILED); |
| 4382 | } |
| 4383 | |
| 4384 | // Single rooted skin? Perfectly ok! |
| 4385 | if (out_roots.size() == 1) { |
| 4386 | return OK; |
| 4387 | } |
| 4388 | |
| 4389 | // Make sure all parents of a multi-rooted skin are the SAME |
| 4390 | const GLTFNodeIndex parent = p_state->nodes[out_roots[0]]->parent; |
| 4391 | for (int i = 1; i < out_roots.size(); ++i) { |
| 4392 | if (p_state->nodes[out_roots[i]]->parent != parent) { |
| 4393 | return FAILED; |
| 4394 | } |
| 4395 | } |
| 4396 | |
| 4397 | return OK; |
| 4398 | } |
| 4399 | |
| 4400 | Error GLTFDocument::_parse_skins(Ref<GLTFState> p_state) { |
| 4401 | if (!p_state->json.has("skins" )) { |
| 4402 | return OK; |
| 4403 | } |
| 4404 | |
| 4405 | const Array &skins = p_state->json["skins" ]; |
| 4406 | |
| 4407 | // Create the base skins, and mark nodes that are joints |
| 4408 | for (int i = 0; i < skins.size(); i++) { |
| 4409 | const Dictionary &d = skins[i]; |
| 4410 | |
| 4411 | Ref<GLTFSkin> skin; |
| 4412 | skin.instantiate(); |
| 4413 | |
| 4414 | ERR_FAIL_COND_V(!d.has("joints" ), ERR_PARSE_ERROR); |
| 4415 | |
| 4416 | const Array &joints = d["joints" ]; |
| 4417 | |
| 4418 | if (d.has("inverseBindMatrices" )) { |
| 4419 | skin->inverse_binds = _decode_accessor_as_xform(p_state, d["inverseBindMatrices" ], false); |
| 4420 | ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR); |
| 4421 | } |
| 4422 | |
| 4423 | for (int j = 0; j < joints.size(); j++) { |
| 4424 | const GLTFNodeIndex node = joints[j]; |
| 4425 | ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR); |
| 4426 | |
| 4427 | skin->joints.push_back(node); |
| 4428 | skin->joints_original.push_back(node); |
| 4429 | |
| 4430 | p_state->nodes.write[node]->joint = true; |
| 4431 | } |
| 4432 | |
| 4433 | if (d.has("name" ) && !String(d["name" ]).is_empty()) { |
| 4434 | skin->set_name(d["name" ]); |
| 4435 | } else { |
| 4436 | skin->set_name(vformat("skin_%s" , itos(i))); |
| 4437 | } |
| 4438 | |
| 4439 | if (d.has("skeleton" )) { |
| 4440 | skin->skin_root = d["skeleton" ]; |
| 4441 | } |
| 4442 | |
| 4443 | p_state->skins.push_back(skin); |
| 4444 | } |
| 4445 | |
| 4446 | for (GLTFSkinIndex i = 0; i < p_state->skins.size(); ++i) { |
| 4447 | Ref<GLTFSkin> skin = p_state->skins.write[i]; |
| 4448 | |
| 4449 | // Expand the skin to capture all the extra non-joints that lie in between the actual joints, |
| 4450 | // and expand the hierarchy to ensure multi-rooted trees lie on the same height level |
| 4451 | ERR_FAIL_COND_V(_expand_skin(p_state, skin), ERR_PARSE_ERROR); |
| 4452 | ERR_FAIL_COND_V(_verify_skin(p_state, skin), ERR_PARSE_ERROR); |
| 4453 | } |
| 4454 | |
| 4455 | print_verbose("glTF: Total skins: " + itos(p_state->skins.size())); |
| 4456 | |
| 4457 | return OK; |
| 4458 | } |
| 4459 | |
| 4460 | void GLTFDocument::_recurse_children(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, |
| 4461 | RBSet<GLTFNodeIndex> &p_all_skin_nodes, HashSet<GLTFNodeIndex> &p_child_visited_set) { |
| 4462 | if (p_child_visited_set.has(p_node_index)) { |
| 4463 | return; |
| 4464 | } |
| 4465 | p_child_visited_set.insert(p_node_index); |
| 4466 | for (int i = 0; i < p_state->nodes[p_node_index]->children.size(); ++i) { |
| 4467 | _recurse_children(p_state, p_state->nodes[p_node_index]->children[i], p_all_skin_nodes, p_child_visited_set); |
| 4468 | } |
| 4469 | |
| 4470 | if (p_state->nodes[p_node_index]->skin < 0 || p_state->nodes[p_node_index]->mesh < 0 || !p_state->nodes[p_node_index]->children.is_empty()) { |
| 4471 | p_all_skin_nodes.insert(p_node_index); |
| 4472 | } |
| 4473 | } |
| 4474 | |
| 4475 | Error GLTFDocument::_determine_skeletons(Ref<GLTFState> p_state) { |
| 4476 | // Using a disjoint set, we are going to potentially combine all skins that are actually branches |
| 4477 | // of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton. |
| 4478 | // This is another unclear issue caused by the current glTF specification. |
| 4479 | |
| 4480 | DisjointSet<GLTFNodeIndex> skeleton_sets; |
| 4481 | |
| 4482 | for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { |
| 4483 | const Ref<GLTFSkin> skin = p_state->skins[skin_i]; |
| 4484 | |
| 4485 | HashSet<GLTFNodeIndex> child_visited_set; |
| 4486 | RBSet<GLTFNodeIndex> all_skin_nodes; |
| 4487 | for (int i = 0; i < skin->joints.size(); ++i) { |
| 4488 | all_skin_nodes.insert(skin->joints[i]); |
| 4489 | _recurse_children(p_state, skin->joints[i], all_skin_nodes, child_visited_set); |
| 4490 | } |
| 4491 | for (int i = 0; i < skin->non_joints.size(); ++i) { |
| 4492 | all_skin_nodes.insert(skin->non_joints[i]); |
| 4493 | _recurse_children(p_state, skin->non_joints[i], all_skin_nodes, child_visited_set); |
| 4494 | } |
| 4495 | for (GLTFNodeIndex node_index : all_skin_nodes) { |
| 4496 | const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; |
| 4497 | skeleton_sets.insert(node_index); |
| 4498 | |
| 4499 | if (all_skin_nodes.has(parent)) { |
| 4500 | skeleton_sets.create_union(parent, node_index); |
| 4501 | } |
| 4502 | } |
| 4503 | |
| 4504 | // We are going to connect the separate skin subtrees in each skin together |
| 4505 | // so that the final roots are entire sets of valid skin trees |
| 4506 | for (int i = 1; i < skin->roots.size(); ++i) { |
| 4507 | skeleton_sets.create_union(skin->roots[0], skin->roots[i]); |
| 4508 | } |
| 4509 | } |
| 4510 | |
| 4511 | { // attempt to joint all touching subsets (siblings/parent are part of another skin) |
| 4512 | Vector<GLTFNodeIndex> groups_representatives; |
| 4513 | skeleton_sets.get_representatives(groups_representatives); |
| 4514 | |
| 4515 | Vector<GLTFNodeIndex> highest_group_members; |
| 4516 | Vector<Vector<GLTFNodeIndex>> groups; |
| 4517 | for (int i = 0; i < groups_representatives.size(); ++i) { |
| 4518 | Vector<GLTFNodeIndex> group; |
| 4519 | skeleton_sets.get_members(group, groups_representatives[i]); |
| 4520 | highest_group_members.push_back(_find_highest_node(p_state, group)); |
| 4521 | groups.push_back(group); |
| 4522 | } |
| 4523 | |
| 4524 | for (int i = 0; i < highest_group_members.size(); ++i) { |
| 4525 | const GLTFNodeIndex node_i = highest_group_members[i]; |
| 4526 | |
| 4527 | // Attach any siblings together (this needs to be done n^2/2 times) |
| 4528 | for (int j = i + 1; j < highest_group_members.size(); ++j) { |
| 4529 | const GLTFNodeIndex node_j = highest_group_members[j]; |
| 4530 | |
| 4531 | // Even if they are siblings under the root! :) |
| 4532 | if (p_state->nodes[node_i]->parent == p_state->nodes[node_j]->parent) { |
| 4533 | skeleton_sets.create_union(node_i, node_j); |
| 4534 | } |
| 4535 | } |
| 4536 | |
| 4537 | // Attach any parenting going on together (we need to do this n^2 times) |
| 4538 | const GLTFNodeIndex node_i_parent = p_state->nodes[node_i]->parent; |
| 4539 | if (node_i_parent >= 0) { |
| 4540 | for (int j = 0; j < groups.size() && i != j; ++j) { |
| 4541 | const Vector<GLTFNodeIndex> &group = groups[j]; |
| 4542 | |
| 4543 | if (group.find(node_i_parent) >= 0) { |
| 4544 | const GLTFNodeIndex node_j = highest_group_members[j]; |
| 4545 | skeleton_sets.create_union(node_i, node_j); |
| 4546 | } |
| 4547 | } |
| 4548 | } |
| 4549 | } |
| 4550 | } |
| 4551 | |
| 4552 | // At this point, the skeleton groups should be finalized |
| 4553 | Vector<GLTFNodeIndex> skeleton_owners; |
| 4554 | skeleton_sets.get_representatives(skeleton_owners); |
| 4555 | |
| 4556 | // Mark all the skins actual skeletons, after we have merged them |
| 4557 | for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) { |
| 4558 | const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i]; |
| 4559 | Ref<GLTFSkeleton> skeleton; |
| 4560 | skeleton.instantiate(); |
| 4561 | |
| 4562 | Vector<GLTFNodeIndex> skeleton_nodes; |
| 4563 | skeleton_sets.get_members(skeleton_nodes, skeleton_owner); |
| 4564 | |
| 4565 | for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { |
| 4566 | Ref<GLTFSkin> skin = p_state->skins.write[skin_i]; |
| 4567 | |
| 4568 | // If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton |
| 4569 | for (int i = 0; i < skeleton_nodes.size(); ++i) { |
| 4570 | GLTFNodeIndex skel_node_i = skeleton_nodes[i]; |
| 4571 | if (skin->joints.find(skel_node_i) >= 0 || skin->non_joints.find(skel_node_i) >= 0) { |
| 4572 | skin->skeleton = skel_i; |
| 4573 | continue; |
| 4574 | } |
| 4575 | } |
| 4576 | } |
| 4577 | |
| 4578 | Vector<GLTFNodeIndex> non_joints; |
| 4579 | for (int i = 0; i < skeleton_nodes.size(); ++i) { |
| 4580 | const GLTFNodeIndex node_i = skeleton_nodes[i]; |
| 4581 | |
| 4582 | if (p_state->nodes[node_i]->joint) { |
| 4583 | skeleton->joints.push_back(node_i); |
| 4584 | } else { |
| 4585 | non_joints.push_back(node_i); |
| 4586 | } |
| 4587 | } |
| 4588 | |
| 4589 | p_state->skeletons.push_back(skeleton); |
| 4590 | |
| 4591 | _reparent_non_joint_skeleton_subtrees(p_state, p_state->skeletons.write[skel_i], non_joints); |
| 4592 | } |
| 4593 | |
| 4594 | for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) { |
| 4595 | Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[skel_i]; |
| 4596 | |
| 4597 | for (int i = 0; i < skeleton->joints.size(); ++i) { |
| 4598 | const GLTFNodeIndex node_i = skeleton->joints[i]; |
| 4599 | Ref<GLTFNode> node = p_state->nodes[node_i]; |
| 4600 | |
| 4601 | ERR_FAIL_COND_V(!node->joint, ERR_PARSE_ERROR); |
| 4602 | ERR_FAIL_COND_V(node->skeleton >= 0, ERR_PARSE_ERROR); |
| 4603 | node->skeleton = skel_i; |
| 4604 | } |
| 4605 | |
| 4606 | ERR_FAIL_COND_V(_determine_skeleton_roots(p_state, skel_i), ERR_PARSE_ERROR); |
| 4607 | } |
| 4608 | |
| 4609 | return OK; |
| 4610 | } |
| 4611 | |
| 4612 | Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> p_state, Ref<GLTFSkeleton> p_skeleton, const Vector<GLTFNodeIndex> &p_non_joints) { |
| 4613 | DisjointSet<GLTFNodeIndex> subtree_set; |
| 4614 | |
| 4615 | // Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector) |
| 4616 | // This way we can find any joints that lie in between joints, as the current glTF specification |
| 4617 | // mentions nothing about non-joints being in between joints of the same skin. Hopefully one day we |
| 4618 | // can remove this code. |
| 4619 | |
| 4620 | // skinD depicted here explains this issue: |
| 4621 | // https://github.com/KhronosGroup/glTF-Asset-Generator/blob/master/Output/Positive/Animation_Skin |
| 4622 | |
| 4623 | for (int i = 0; i < p_non_joints.size(); ++i) { |
| 4624 | const GLTFNodeIndex node_i = p_non_joints[i]; |
| 4625 | |
| 4626 | subtree_set.insert(node_i); |
| 4627 | |
| 4628 | const GLTFNodeIndex parent_i = p_state->nodes[node_i]->parent; |
| 4629 | if (parent_i >= 0 && p_non_joints.find(parent_i) >= 0 && !p_state->nodes[parent_i]->joint) { |
| 4630 | subtree_set.create_union(parent_i, node_i); |
| 4631 | } |
| 4632 | } |
| 4633 | |
| 4634 | // Find all the non joint subtrees and re-parent them to a new "fake" joint |
| 4635 | |
| 4636 | Vector<GLTFNodeIndex> non_joint_subtree_roots; |
| 4637 | subtree_set.get_representatives(non_joint_subtree_roots); |
| 4638 | |
| 4639 | for (int root_i = 0; root_i < non_joint_subtree_roots.size(); ++root_i) { |
| 4640 | const GLTFNodeIndex subtree_root = non_joint_subtree_roots[root_i]; |
| 4641 | |
| 4642 | Vector<GLTFNodeIndex> subtree_nodes; |
| 4643 | subtree_set.get_members(subtree_nodes, subtree_root); |
| 4644 | |
| 4645 | for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) { |
| 4646 | Ref<GLTFNode> node = p_state->nodes[subtree_nodes[subtree_i]]; |
| 4647 | node->joint = true; |
| 4648 | // Add the joint to the skeletons joints |
| 4649 | p_skeleton->joints.push_back(subtree_nodes[subtree_i]); |
| 4650 | } |
| 4651 | } |
| 4652 | |
| 4653 | return OK; |
| 4654 | } |
| 4655 | |
| 4656 | Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i) { |
| 4657 | DisjointSet<GLTFNodeIndex> disjoint_set; |
| 4658 | |
| 4659 | for (GLTFNodeIndex i = 0; i < p_state->nodes.size(); ++i) { |
| 4660 | const Ref<GLTFNode> node = p_state->nodes[i]; |
| 4661 | |
| 4662 | if (node->skeleton != p_skel_i) { |
| 4663 | continue; |
| 4664 | } |
| 4665 | |
| 4666 | disjoint_set.insert(i); |
| 4667 | |
| 4668 | if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == p_skel_i) { |
| 4669 | disjoint_set.create_union(node->parent, i); |
| 4670 | } |
| 4671 | } |
| 4672 | |
| 4673 | Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[p_skel_i]; |
| 4674 | |
| 4675 | Vector<GLTFNodeIndex> representatives; |
| 4676 | disjoint_set.get_representatives(representatives); |
| 4677 | |
| 4678 | Vector<GLTFNodeIndex> roots; |
| 4679 | |
| 4680 | for (int i = 0; i < representatives.size(); ++i) { |
| 4681 | Vector<GLTFNodeIndex> set; |
| 4682 | disjoint_set.get_members(set, representatives[i]); |
| 4683 | const GLTFNodeIndex root = _find_highest_node(p_state, set); |
| 4684 | ERR_FAIL_COND_V(root < 0, FAILED); |
| 4685 | roots.push_back(root); |
| 4686 | } |
| 4687 | |
| 4688 | roots.sort(); |
| 4689 | |
| 4690 | skeleton->roots = roots; |
| 4691 | |
| 4692 | if (roots.size() == 0) { |
| 4693 | return FAILED; |
| 4694 | } else if (roots.size() == 1) { |
| 4695 | return OK; |
| 4696 | } |
| 4697 | |
| 4698 | // Check that the subtrees have the same parent root |
| 4699 | const GLTFNodeIndex parent = p_state->nodes[roots[0]]->parent; |
| 4700 | for (int i = 1; i < roots.size(); ++i) { |
| 4701 | if (p_state->nodes[roots[i]]->parent != parent) { |
| 4702 | return FAILED; |
| 4703 | } |
| 4704 | } |
| 4705 | |
| 4706 | return OK; |
| 4707 | } |
| 4708 | |
| 4709 | Error GLTFDocument::_create_skeletons(Ref<GLTFState> p_state) { |
| 4710 | for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) { |
| 4711 | Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i]; |
| 4712 | |
| 4713 | Skeleton3D *skeleton = memnew(Skeleton3D); |
| 4714 | gltf_skeleton->godot_skeleton = skeleton; |
| 4715 | p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i; |
| 4716 | |
| 4717 | // Make a unique name, no gltf node represents this skeleton |
| 4718 | skeleton->set_name("Skeleton3D" ); |
| 4719 | |
| 4720 | List<GLTFNodeIndex> bones; |
| 4721 | |
| 4722 | for (int i = 0; i < gltf_skeleton->roots.size(); ++i) { |
| 4723 | bones.push_back(gltf_skeleton->roots[i]); |
| 4724 | } |
| 4725 | |
| 4726 | // Make the skeleton creation deterministic by going through the roots in |
| 4727 | // a sorted order, and DEPTH FIRST |
| 4728 | bones.sort(); |
| 4729 | |
| 4730 | while (!bones.is_empty()) { |
| 4731 | const GLTFNodeIndex node_i = bones.front()->get(); |
| 4732 | bones.pop_front(); |
| 4733 | |
| 4734 | Ref<GLTFNode> node = p_state->nodes[node_i]; |
| 4735 | ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED); |
| 4736 | |
| 4737 | { // Add all child nodes to the stack (deterministically) |
| 4738 | Vector<GLTFNodeIndex> child_nodes; |
| 4739 | for (int i = 0; i < node->children.size(); ++i) { |
| 4740 | const GLTFNodeIndex child_i = node->children[i]; |
| 4741 | if (p_state->nodes[child_i]->skeleton == skel_i) { |
| 4742 | child_nodes.push_back(child_i); |
| 4743 | } |
| 4744 | } |
| 4745 | |
| 4746 | // Depth first insertion |
| 4747 | child_nodes.sort(); |
| 4748 | for (int i = child_nodes.size() - 1; i >= 0; --i) { |
| 4749 | bones.push_front(child_nodes[i]); |
| 4750 | } |
| 4751 | } |
| 4752 | |
| 4753 | const int bone_index = skeleton->get_bone_count(); |
| 4754 | |
| 4755 | if (node->get_name().is_empty()) { |
| 4756 | node->set_name("bone" ); |
| 4757 | } |
| 4758 | |
| 4759 | node->set_name(_gen_unique_bone_name(p_state, skel_i, node->get_name())); |
| 4760 | |
| 4761 | skeleton->add_bone(node->get_name()); |
| 4762 | skeleton->set_bone_rest(bone_index, node->xform); |
| 4763 | skeleton->set_bone_pose_position(bone_index, node->position); |
| 4764 | skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized()); |
| 4765 | skeleton->set_bone_pose_scale(bone_index, node->scale); |
| 4766 | |
| 4767 | if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == skel_i) { |
| 4768 | const int bone_parent = skeleton->find_bone(p_state->nodes[node->parent]->get_name()); |
| 4769 | ERR_FAIL_COND_V(bone_parent < 0, FAILED); |
| 4770 | skeleton->set_bone_parent(bone_index, skeleton->find_bone(p_state->nodes[node->parent]->get_name())); |
| 4771 | } |
| 4772 | |
| 4773 | p_state->scene_nodes.insert(node_i, skeleton); |
| 4774 | } |
| 4775 | } |
| 4776 | |
| 4777 | ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(p_state), ERR_PARSE_ERROR); |
| 4778 | |
| 4779 | return OK; |
| 4780 | } |
| 4781 | |
| 4782 | Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> p_state) { |
| 4783 | for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { |
| 4784 | Ref<GLTFSkin> skin = p_state->skins.write[skin_i]; |
| 4785 | |
| 4786 | Ref<GLTFSkeleton> skeleton = p_state->skeletons[skin->skeleton]; |
| 4787 | |
| 4788 | for (int joint_index = 0; joint_index < skin->joints_original.size(); ++joint_index) { |
| 4789 | const GLTFNodeIndex node_i = skin->joints_original[joint_index]; |
| 4790 | const Ref<GLTFNode> node = p_state->nodes[node_i]; |
| 4791 | |
| 4792 | const int bone_index = skeleton->godot_skeleton->find_bone(node->get_name()); |
| 4793 | ERR_FAIL_COND_V(bone_index < 0, FAILED); |
| 4794 | |
| 4795 | skin->joint_i_to_bone_i.insert(joint_index, bone_index); |
| 4796 | } |
| 4797 | } |
| 4798 | |
| 4799 | return OK; |
| 4800 | } |
| 4801 | |
| 4802 | Error GLTFDocument::_serialize_skins(Ref<GLTFState> p_state) { |
| 4803 | _remove_duplicate_skins(p_state); |
| 4804 | Array json_skins; |
| 4805 | for (int skin_i = 0; skin_i < p_state->skins.size(); skin_i++) { |
| 4806 | Ref<GLTFSkin> gltf_skin = p_state->skins[skin_i]; |
| 4807 | Dictionary json_skin; |
| 4808 | json_skin["inverseBindMatrices" ] = _encode_accessor_as_xform(p_state, gltf_skin->inverse_binds, false); |
| 4809 | json_skin["joints" ] = gltf_skin->get_joints(); |
| 4810 | json_skin["name" ] = gltf_skin->get_name(); |
| 4811 | json_skins.push_back(json_skin); |
| 4812 | } |
| 4813 | if (!p_state->skins.size()) { |
| 4814 | return OK; |
| 4815 | } |
| 4816 | |
| 4817 | p_state->json["skins" ] = json_skins; |
| 4818 | return OK; |
| 4819 | } |
| 4820 | |
| 4821 | Error GLTFDocument::_create_skins(Ref<GLTFState> p_state) { |
| 4822 | for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { |
| 4823 | Ref<GLTFSkin> gltf_skin = p_state->skins.write[skin_i]; |
| 4824 | |
| 4825 | Ref<Skin> skin; |
| 4826 | skin.instantiate(); |
| 4827 | |
| 4828 | // Some skins don't have IBM's! What absolute monsters! |
| 4829 | const bool has_ibms = !gltf_skin->inverse_binds.is_empty(); |
| 4830 | |
| 4831 | for (int joint_i = 0; joint_i < gltf_skin->joints_original.size(); ++joint_i) { |
| 4832 | GLTFNodeIndex node = gltf_skin->joints_original[joint_i]; |
| 4833 | String bone_name = p_state->nodes[node]->get_name(); |
| 4834 | |
| 4835 | Transform3D xform; |
| 4836 | if (has_ibms) { |
| 4837 | xform = gltf_skin->inverse_binds[joint_i]; |
| 4838 | } |
| 4839 | |
| 4840 | if (p_state->use_named_skin_binds) { |
| 4841 | skin->add_named_bind(bone_name, xform); |
| 4842 | } else { |
| 4843 | int32_t bone_i = gltf_skin->joint_i_to_bone_i[joint_i]; |
| 4844 | skin->add_bind(bone_i, xform); |
| 4845 | } |
| 4846 | } |
| 4847 | |
| 4848 | gltf_skin->godot_skin = skin; |
| 4849 | } |
| 4850 | |
| 4851 | // Purge the duplicates! |
| 4852 | _remove_duplicate_skins(p_state); |
| 4853 | |
| 4854 | // Create unique names now, after removing duplicates |
| 4855 | for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { |
| 4856 | Ref<Skin> skin = p_state->skins.write[skin_i]->godot_skin; |
| 4857 | if (skin->get_name().is_empty()) { |
| 4858 | // Make a unique name, no gltf node represents this skin |
| 4859 | skin->set_name(_gen_unique_name(p_state, "Skin" )); |
| 4860 | } |
| 4861 | } |
| 4862 | |
| 4863 | return OK; |
| 4864 | } |
| 4865 | |
| 4866 | bool GLTFDocument::_skins_are_same(const Ref<Skin> p_skin_a, const Ref<Skin> p_skin_b) { |
| 4867 | if (p_skin_a->get_bind_count() != p_skin_b->get_bind_count()) { |
| 4868 | return false; |
| 4869 | } |
| 4870 | |
| 4871 | for (int i = 0; i < p_skin_a->get_bind_count(); ++i) { |
| 4872 | if (p_skin_a->get_bind_bone(i) != p_skin_b->get_bind_bone(i)) { |
| 4873 | return false; |
| 4874 | } |
| 4875 | if (p_skin_a->get_bind_name(i) != p_skin_b->get_bind_name(i)) { |
| 4876 | return false; |
| 4877 | } |
| 4878 | |
| 4879 | Transform3D a_xform = p_skin_a->get_bind_pose(i); |
| 4880 | Transform3D b_xform = p_skin_b->get_bind_pose(i); |
| 4881 | |
| 4882 | if (a_xform != b_xform) { |
| 4883 | return false; |
| 4884 | } |
| 4885 | } |
| 4886 | |
| 4887 | return true; |
| 4888 | } |
| 4889 | |
| 4890 | void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> p_state) { |
| 4891 | for (int i = 0; i < p_state->skins.size(); ++i) { |
| 4892 | for (int j = i + 1; j < p_state->skins.size(); ++j) { |
| 4893 | const Ref<Skin> skin_i = p_state->skins[i]->godot_skin; |
| 4894 | const Ref<Skin> skin_j = p_state->skins[j]->godot_skin; |
| 4895 | |
| 4896 | if (_skins_are_same(skin_i, skin_j)) { |
| 4897 | // replace it and delete the old |
| 4898 | p_state->skins.write[j]->godot_skin = skin_i; |
| 4899 | } |
| 4900 | } |
| 4901 | } |
| 4902 | } |
| 4903 | |
| 4904 | Error GLTFDocument::_serialize_lights(Ref<GLTFState> p_state) { |
| 4905 | if (p_state->lights.is_empty()) { |
| 4906 | return OK; |
| 4907 | } |
| 4908 | Array lights; |
| 4909 | for (GLTFLightIndex i = 0; i < p_state->lights.size(); i++) { |
| 4910 | lights.push_back(p_state->lights[i]->to_dictionary()); |
| 4911 | } |
| 4912 | |
| 4913 | Dictionary extensions; |
| 4914 | if (p_state->json.has("extensions" )) { |
| 4915 | extensions = p_state->json["extensions" ]; |
| 4916 | } else { |
| 4917 | p_state->json["extensions" ] = extensions; |
| 4918 | } |
| 4919 | Dictionary lights_punctual; |
| 4920 | extensions["KHR_lights_punctual" ] = lights_punctual; |
| 4921 | lights_punctual["lights" ] = lights; |
| 4922 | |
| 4923 | print_verbose("glTF: Total lights: " + itos(p_state->lights.size())); |
| 4924 | |
| 4925 | return OK; |
| 4926 | } |
| 4927 | |
| 4928 | Error GLTFDocument::_serialize_cameras(Ref<GLTFState> p_state) { |
| 4929 | Array cameras; |
| 4930 | cameras.resize(p_state->cameras.size()); |
| 4931 | for (GLTFCameraIndex i = 0; i < p_state->cameras.size(); i++) { |
| 4932 | cameras[i] = p_state->cameras[i]->to_dictionary(); |
| 4933 | } |
| 4934 | |
| 4935 | if (!p_state->cameras.size()) { |
| 4936 | return OK; |
| 4937 | } |
| 4938 | |
| 4939 | p_state->json["cameras" ] = cameras; |
| 4940 | |
| 4941 | print_verbose("glTF: Total cameras: " + itos(p_state->cameras.size())); |
| 4942 | |
| 4943 | return OK; |
| 4944 | } |
| 4945 | |
| 4946 | Error GLTFDocument::_parse_lights(Ref<GLTFState> p_state) { |
| 4947 | if (!p_state->json.has("extensions" )) { |
| 4948 | return OK; |
| 4949 | } |
| 4950 | Dictionary extensions = p_state->json["extensions" ]; |
| 4951 | if (!extensions.has("KHR_lights_punctual" )) { |
| 4952 | return OK; |
| 4953 | } |
| 4954 | Dictionary lights_punctual = extensions["KHR_lights_punctual" ]; |
| 4955 | if (!lights_punctual.has("lights" )) { |
| 4956 | return OK; |
| 4957 | } |
| 4958 | |
| 4959 | const Array &lights = lights_punctual["lights" ]; |
| 4960 | |
| 4961 | for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) { |
| 4962 | Ref<GLTFLight> light = GLTFLight::from_dictionary(lights[light_i]); |
| 4963 | if (light.is_null()) { |
| 4964 | return Error::ERR_PARSE_ERROR; |
| 4965 | } |
| 4966 | p_state->lights.push_back(light); |
| 4967 | } |
| 4968 | |
| 4969 | print_verbose("glTF: Total lights: " + itos(p_state->lights.size())); |
| 4970 | |
| 4971 | return OK; |
| 4972 | } |
| 4973 | |
| 4974 | Error GLTFDocument::_parse_cameras(Ref<GLTFState> p_state) { |
| 4975 | if (!p_state->json.has("cameras" )) { |
| 4976 | return OK; |
| 4977 | } |
| 4978 | |
| 4979 | const Array cameras = p_state->json["cameras" ]; |
| 4980 | |
| 4981 | for (GLTFCameraIndex i = 0; i < cameras.size(); i++) { |
| 4982 | p_state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i])); |
| 4983 | } |
| 4984 | |
| 4985 | print_verbose("glTF: Total cameras: " + itos(p_state->cameras.size())); |
| 4986 | |
| 4987 | return OK; |
| 4988 | } |
| 4989 | |
| 4990 | String GLTFDocument::interpolation_to_string(const GLTFAnimation::Interpolation p_interp) { |
| 4991 | String interp = "LINEAR" ; |
| 4992 | if (p_interp == GLTFAnimation::INTERP_STEP) { |
| 4993 | interp = "STEP" ; |
| 4994 | } else if (p_interp == GLTFAnimation::INTERP_LINEAR) { |
| 4995 | interp = "LINEAR" ; |
| 4996 | } else if (p_interp == GLTFAnimation::INTERP_CATMULLROMSPLINE) { |
| 4997 | interp = "CATMULLROMSPLINE" ; |
| 4998 | } else if (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 4999 | interp = "CUBICSPLINE" ; |
| 5000 | } |
| 5001 | |
| 5002 | return interp; |
| 5003 | } |
| 5004 | |
| 5005 | Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) { |
| 5006 | if (!p_state->animation_players.size()) { |
| 5007 | return OK; |
| 5008 | } |
| 5009 | for (int32_t player_i = 0; player_i < p_state->animation_players.size(); player_i++) { |
| 5010 | AnimationPlayer *animation_player = p_state->animation_players[player_i]; |
| 5011 | List<StringName> animations; |
| 5012 | animation_player->get_animation_list(&animations); |
| 5013 | for (StringName animation_name : animations) { |
| 5014 | _convert_animation(p_state, animation_player, animation_name); |
| 5015 | } |
| 5016 | } |
| 5017 | Array animations; |
| 5018 | for (GLTFAnimationIndex animation_i = 0; animation_i < p_state->animations.size(); animation_i++) { |
| 5019 | Dictionary d; |
| 5020 | Ref<GLTFAnimation> gltf_animation = p_state->animations[animation_i]; |
| 5021 | if (!gltf_animation->get_tracks().size()) { |
| 5022 | continue; |
| 5023 | } |
| 5024 | |
| 5025 | if (!gltf_animation->get_name().is_empty()) { |
| 5026 | d["name" ] = gltf_animation->get_name(); |
| 5027 | } |
| 5028 | Array channels; |
| 5029 | Array samplers; |
| 5030 | |
| 5031 | for (KeyValue<int, GLTFAnimation::Track> &track_i : gltf_animation->get_tracks()) { |
| 5032 | GLTFAnimation::Track track = track_i.value; |
| 5033 | if (track.position_track.times.size()) { |
| 5034 | Dictionary t; |
| 5035 | t["sampler" ] = samplers.size(); |
| 5036 | Dictionary s; |
| 5037 | |
| 5038 | s["interpolation" ] = interpolation_to_string(track.position_track.interpolation); |
| 5039 | Vector<real_t> times = Variant(track.position_track.times); |
| 5040 | s["input" ] = _encode_accessor_as_floats(p_state, times, false); |
| 5041 | Vector<Vector3> values = Variant(track.position_track.values); |
| 5042 | s["output" ] = _encode_accessor_as_vec3(p_state, values, false); |
| 5043 | |
| 5044 | samplers.push_back(s); |
| 5045 | |
| 5046 | Dictionary target; |
| 5047 | target["path" ] = "translation" ; |
| 5048 | target["node" ] = track_i.key; |
| 5049 | |
| 5050 | t["target" ] = target; |
| 5051 | channels.push_back(t); |
| 5052 | } |
| 5053 | if (track.rotation_track.times.size()) { |
| 5054 | Dictionary t; |
| 5055 | t["sampler" ] = samplers.size(); |
| 5056 | Dictionary s; |
| 5057 | |
| 5058 | s["interpolation" ] = interpolation_to_string(track.rotation_track.interpolation); |
| 5059 | Vector<real_t> times = Variant(track.rotation_track.times); |
| 5060 | s["input" ] = _encode_accessor_as_floats(p_state, times, false); |
| 5061 | Vector<Quaternion> values = track.rotation_track.values; |
| 5062 | s["output" ] = _encode_accessor_as_quaternions(p_state, values, false); |
| 5063 | |
| 5064 | samplers.push_back(s); |
| 5065 | |
| 5066 | Dictionary target; |
| 5067 | target["path" ] = "rotation" ; |
| 5068 | target["node" ] = track_i.key; |
| 5069 | |
| 5070 | t["target" ] = target; |
| 5071 | channels.push_back(t); |
| 5072 | } |
| 5073 | if (track.scale_track.times.size()) { |
| 5074 | Dictionary t; |
| 5075 | t["sampler" ] = samplers.size(); |
| 5076 | Dictionary s; |
| 5077 | |
| 5078 | s["interpolation" ] = interpolation_to_string(track.scale_track.interpolation); |
| 5079 | Vector<real_t> times = Variant(track.scale_track.times); |
| 5080 | s["input" ] = _encode_accessor_as_floats(p_state, times, false); |
| 5081 | Vector<Vector3> values = Variant(track.scale_track.values); |
| 5082 | s["output" ] = _encode_accessor_as_vec3(p_state, values, false); |
| 5083 | |
| 5084 | samplers.push_back(s); |
| 5085 | |
| 5086 | Dictionary target; |
| 5087 | target["path" ] = "scale" ; |
| 5088 | target["node" ] = track_i.key; |
| 5089 | |
| 5090 | t["target" ] = target; |
| 5091 | channels.push_back(t); |
| 5092 | } |
| 5093 | if (track.weight_tracks.size()) { |
| 5094 | double length = 0.0f; |
| 5095 | |
| 5096 | for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) { |
| 5097 | int32_t last_time_index = track.weight_tracks[track_idx].times.size() - 1; |
| 5098 | length = MAX(length, track.weight_tracks[track_idx].times[last_time_index]); |
| 5099 | } |
| 5100 | |
| 5101 | Dictionary t; |
| 5102 | t["sampler" ] = samplers.size(); |
| 5103 | Dictionary s; |
| 5104 | Vector<real_t> times; |
| 5105 | const double increment = 1.0 / BAKE_FPS; |
| 5106 | { |
| 5107 | double time = 0.0; |
| 5108 | bool last = false; |
| 5109 | while (true) { |
| 5110 | times.push_back(time); |
| 5111 | if (last) { |
| 5112 | break; |
| 5113 | } |
| 5114 | time += increment; |
| 5115 | if (time >= length) { |
| 5116 | last = true; |
| 5117 | time = length; |
| 5118 | } |
| 5119 | } |
| 5120 | } |
| 5121 | |
| 5122 | for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) { |
| 5123 | double time = 0.0; |
| 5124 | bool last = false; |
| 5125 | Vector<real_t> weight_track; |
| 5126 | while (true) { |
| 5127 | float weight = _interpolate_track<real_t>(track.weight_tracks[track_idx].times, |
| 5128 | track.weight_tracks[track_idx].values, |
| 5129 | time, |
| 5130 | track.weight_tracks[track_idx].interpolation); |
| 5131 | weight_track.push_back(weight); |
| 5132 | if (last) { |
| 5133 | break; |
| 5134 | } |
| 5135 | time += increment; |
| 5136 | if (time >= length) { |
| 5137 | last = true; |
| 5138 | time = length; |
| 5139 | } |
| 5140 | } |
| 5141 | track.weight_tracks.write[track_idx].times = times; |
| 5142 | track.weight_tracks.write[track_idx].values = weight_track; |
| 5143 | } |
| 5144 | |
| 5145 | Vector<real_t> all_track_times = times; |
| 5146 | Vector<real_t> all_track_values; |
| 5147 | int32_t values_size = track.weight_tracks[0].values.size(); |
| 5148 | int32_t weight_tracks_size = track.weight_tracks.size(); |
| 5149 | all_track_values.resize(weight_tracks_size * values_size); |
| 5150 | for (int k = 0; k < track.weight_tracks.size(); k++) { |
| 5151 | Vector<real_t> wdata = track.weight_tracks[k].values; |
| 5152 | for (int l = 0; l < wdata.size(); l++) { |
| 5153 | int32_t index = l * weight_tracks_size + k; |
| 5154 | ERR_BREAK(index >= all_track_values.size()); |
| 5155 | all_track_values.write[index] = wdata.write[l]; |
| 5156 | } |
| 5157 | } |
| 5158 | |
| 5159 | s["interpolation" ] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation); |
| 5160 | s["input" ] = _encode_accessor_as_floats(p_state, all_track_times, false); |
| 5161 | s["output" ] = _encode_accessor_as_floats(p_state, all_track_values, false); |
| 5162 | |
| 5163 | samplers.push_back(s); |
| 5164 | |
| 5165 | Dictionary target; |
| 5166 | target["path" ] = "weights" ; |
| 5167 | target["node" ] = track_i.key; |
| 5168 | |
| 5169 | t["target" ] = target; |
| 5170 | channels.push_back(t); |
| 5171 | } |
| 5172 | } |
| 5173 | if (channels.size() && samplers.size()) { |
| 5174 | d["channels" ] = channels; |
| 5175 | d["samplers" ] = samplers; |
| 5176 | animations.push_back(d); |
| 5177 | } |
| 5178 | } |
| 5179 | |
| 5180 | if (!animations.size()) { |
| 5181 | return OK; |
| 5182 | } |
| 5183 | p_state->json["animations" ] = animations; |
| 5184 | |
| 5185 | print_verbose("glTF: Total animations '" + itos(p_state->animations.size()) + "'." ); |
| 5186 | |
| 5187 | return OK; |
| 5188 | } |
| 5189 | |
| 5190 | Error GLTFDocument::_parse_animations(Ref<GLTFState> p_state) { |
| 5191 | if (!p_state->json.has("animations" )) { |
| 5192 | return OK; |
| 5193 | } |
| 5194 | |
| 5195 | const Array &animations = p_state->json["animations" ]; |
| 5196 | |
| 5197 | for (GLTFAnimationIndex i = 0; i < animations.size(); i++) { |
| 5198 | const Dictionary &d = animations[i]; |
| 5199 | |
| 5200 | Ref<GLTFAnimation> animation; |
| 5201 | animation.instantiate(); |
| 5202 | |
| 5203 | if (!d.has("channels" ) || !d.has("samplers" )) { |
| 5204 | continue; |
| 5205 | } |
| 5206 | |
| 5207 | Array channels = d["channels" ]; |
| 5208 | Array samplers = d["samplers" ]; |
| 5209 | |
| 5210 | if (d.has("name" )) { |
| 5211 | const String anim_name = d["name" ]; |
| 5212 | const String anim_name_lower = anim_name.to_lower(); |
| 5213 | if (anim_name_lower.begins_with("loop" ) || anim_name_lower.ends_with("loop" ) || anim_name_lower.begins_with("cycle" ) || anim_name_lower.ends_with("cycle" )) { |
| 5214 | animation->set_loop(true); |
| 5215 | } |
| 5216 | animation->set_name(_gen_unique_animation_name(p_state, anim_name)); |
| 5217 | } |
| 5218 | |
| 5219 | for (int j = 0; j < channels.size(); j++) { |
| 5220 | const Dictionary &c = channels[j]; |
| 5221 | if (!c.has("target" )) { |
| 5222 | continue; |
| 5223 | } |
| 5224 | |
| 5225 | const Dictionary &t = c["target" ]; |
| 5226 | if (!t.has("node" ) || !t.has("path" )) { |
| 5227 | continue; |
| 5228 | } |
| 5229 | |
| 5230 | ERR_FAIL_COND_V(!c.has("sampler" ), ERR_PARSE_ERROR); |
| 5231 | const int sampler = c["sampler" ]; |
| 5232 | ERR_FAIL_INDEX_V(sampler, samplers.size(), ERR_PARSE_ERROR); |
| 5233 | |
| 5234 | GLTFNodeIndex node = t["node" ]; |
| 5235 | String path = t["path" ]; |
| 5236 | |
| 5237 | ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR); |
| 5238 | |
| 5239 | GLTFAnimation::Track *track = nullptr; |
| 5240 | |
| 5241 | if (!animation->get_tracks().has(node)) { |
| 5242 | animation->get_tracks()[node] = GLTFAnimation::Track(); |
| 5243 | } |
| 5244 | |
| 5245 | track = &animation->get_tracks()[node]; |
| 5246 | |
| 5247 | const Dictionary &s = samplers[sampler]; |
| 5248 | |
| 5249 | ERR_FAIL_COND_V(!s.has("input" ), ERR_PARSE_ERROR); |
| 5250 | ERR_FAIL_COND_V(!s.has("output" ), ERR_PARSE_ERROR); |
| 5251 | |
| 5252 | const int input = s["input" ]; |
| 5253 | const int output = s["output" ]; |
| 5254 | |
| 5255 | GLTFAnimation::Interpolation interp = GLTFAnimation::INTERP_LINEAR; |
| 5256 | int output_count = 1; |
| 5257 | if (s.has("interpolation" )) { |
| 5258 | const String &in = s["interpolation" ]; |
| 5259 | if (in == "STEP" ) { |
| 5260 | interp = GLTFAnimation::INTERP_STEP; |
| 5261 | } else if (in == "LINEAR" ) { |
| 5262 | interp = GLTFAnimation::INTERP_LINEAR; |
| 5263 | } else if (in == "CATMULLROMSPLINE" ) { |
| 5264 | interp = GLTFAnimation::INTERP_CATMULLROMSPLINE; |
| 5265 | output_count = 3; |
| 5266 | } else if (in == "CUBICSPLINE" ) { |
| 5267 | interp = GLTFAnimation::INTERP_CUBIC_SPLINE; |
| 5268 | output_count = 3; |
| 5269 | } |
| 5270 | } |
| 5271 | |
| 5272 | const Vector<float> times = _decode_accessor_as_floats(p_state, input, false); |
| 5273 | if (path == "translation" ) { |
| 5274 | const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, output, false); |
| 5275 | track->position_track.interpolation = interp; |
| 5276 | track->position_track.times = Variant(times); //convert via variant |
| 5277 | track->position_track.values = Variant(positions); //convert via variant |
| 5278 | } else if (path == "rotation" ) { |
| 5279 | const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, output, false); |
| 5280 | track->rotation_track.interpolation = interp; |
| 5281 | track->rotation_track.times = Variant(times); //convert via variant |
| 5282 | track->rotation_track.values = rotations; |
| 5283 | } else if (path == "scale" ) { |
| 5284 | const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, output, false); |
| 5285 | track->scale_track.interpolation = interp; |
| 5286 | track->scale_track.times = Variant(times); //convert via variant |
| 5287 | track->scale_track.values = Variant(scales); //convert via variant |
| 5288 | } else if (path == "weights" ) { |
| 5289 | const Vector<float> weights = _decode_accessor_as_floats(p_state, output, false); |
| 5290 | |
| 5291 | ERR_FAIL_INDEX_V(p_state->nodes[node]->mesh, p_state->meshes.size(), ERR_PARSE_ERROR); |
| 5292 | Ref<GLTFMesh> mesh = p_state->meshes[p_state->nodes[node]->mesh]; |
| 5293 | ERR_CONTINUE(!mesh->get_blend_weights().size()); |
| 5294 | const int wc = mesh->get_blend_weights().size(); |
| 5295 | |
| 5296 | track->weight_tracks.resize(wc); |
| 5297 | |
| 5298 | const int expected_value_count = times.size() * output_count * wc; |
| 5299 | ERR_CONTINUE_MSG(weights.size() != expected_value_count, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead." ); |
| 5300 | |
| 5301 | const int wlen = weights.size() / wc; |
| 5302 | for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea |
| 5303 | GLTFAnimation::Channel<real_t> cf; |
| 5304 | cf.interpolation = interp; |
| 5305 | cf.times = Variant(times); |
| 5306 | Vector<real_t> wdata; |
| 5307 | wdata.resize(wlen); |
| 5308 | for (int l = 0; l < wlen; l++) { |
| 5309 | wdata.write[l] = weights[l * wc + k]; |
| 5310 | } |
| 5311 | |
| 5312 | cf.values = wdata; |
| 5313 | track->weight_tracks.write[k] = cf; |
| 5314 | } |
| 5315 | } else { |
| 5316 | WARN_PRINT("Invalid path '" + path + "'." ); |
| 5317 | } |
| 5318 | } |
| 5319 | |
| 5320 | p_state->animations.push_back(animation); |
| 5321 | } |
| 5322 | |
| 5323 | print_verbose("glTF: Total animations '" + itos(p_state->animations.size()) + "'." ); |
| 5324 | |
| 5325 | return OK; |
| 5326 | } |
| 5327 | |
| 5328 | void GLTFDocument::_assign_node_names(Ref<GLTFState> p_state) { |
| 5329 | for (int i = 0; i < p_state->nodes.size(); i++) { |
| 5330 | Ref<GLTFNode> gltf_node = p_state->nodes[i]; |
| 5331 | // Any joints get unique names generated when the skeleton is made, unique to the skeleton |
| 5332 | if (gltf_node->skeleton >= 0) { |
| 5333 | continue; |
| 5334 | } |
| 5335 | String gltf_node_name = gltf_node->get_name(); |
| 5336 | if (gltf_node_name.is_empty()) { |
| 5337 | if (gltf_node->mesh >= 0) { |
| 5338 | gltf_node_name = "Mesh" ; |
| 5339 | } else if (gltf_node->camera >= 0) { |
| 5340 | gltf_node_name = "Camera" ; |
| 5341 | } else { |
| 5342 | gltf_node_name = "Node" ; |
| 5343 | } |
| 5344 | } |
| 5345 | gltf_node->set_name(_gen_unique_name(p_state, gltf_node_name)); |
| 5346 | } |
| 5347 | } |
| 5348 | |
| 5349 | BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> p_state, Skeleton3D *p_skeleton, const GLTFNodeIndex p_node_index, const GLTFNodeIndex p_bone_index) { |
| 5350 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5351 | Ref<GLTFNode> bone_node = p_state->nodes[p_bone_index]; |
| 5352 | BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D); |
| 5353 | print_verbose("glTF: Creating bone attachment for: " + gltf_node->get_name()); |
| 5354 | |
| 5355 | ERR_FAIL_COND_V(!bone_node->joint, nullptr); |
| 5356 | |
| 5357 | bone_attachment->set_bone_name(bone_node->get_name()); |
| 5358 | |
| 5359 | return bone_attachment; |
| 5360 | } |
| 5361 | |
| 5362 | GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshInstance3D *p_mesh_instance) { |
| 5363 | ERR_FAIL_NULL_V(p_mesh_instance, -1); |
| 5364 | if (p_mesh_instance->get_mesh().is_null()) { |
| 5365 | return -1; |
| 5366 | } |
| 5367 | |
| 5368 | Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); |
| 5369 | Ref<ImporterMesh> current_mesh = _mesh_to_importer_mesh(import_mesh); |
| 5370 | Vector<float> blend_weights; |
| 5371 | int32_t blend_count = import_mesh->get_blend_shape_count(); |
| 5372 | blend_weights.resize(blend_count); |
| 5373 | for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { |
| 5374 | blend_weights.write[blend_i] = 0.0f; |
| 5375 | } |
| 5376 | |
| 5377 | Ref<GLTFMesh> gltf_mesh; |
| 5378 | gltf_mesh.instantiate(); |
| 5379 | TypedArray<Material> instance_materials; |
| 5380 | for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) { |
| 5381 | Ref<Material> mat = current_mesh->get_surface_material(surface_i); |
| 5382 | if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) { |
| 5383 | mat = p_mesh_instance->get_surface_override_material(surface_i); |
| 5384 | } |
| 5385 | if (p_mesh_instance->get_material_override().is_valid()) { |
| 5386 | mat = p_mesh_instance->get_material_override(); |
| 5387 | } |
| 5388 | instance_materials.append(mat); |
| 5389 | } |
| 5390 | gltf_mesh->set_instance_materials(instance_materials); |
| 5391 | gltf_mesh->set_mesh(current_mesh); |
| 5392 | gltf_mesh->set_blend_weights(blend_weights); |
| 5393 | GLTFMeshIndex mesh_i = p_state->meshes.size(); |
| 5394 | p_state->meshes.push_back(gltf_mesh); |
| 5395 | return mesh_i; |
| 5396 | } |
| 5397 | |
| 5398 | ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { |
| 5399 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5400 | |
| 5401 | ERR_FAIL_INDEX_V(gltf_node->mesh, p_state->meshes.size(), nullptr); |
| 5402 | |
| 5403 | ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D); |
| 5404 | print_verbose("glTF: Creating mesh for: " + gltf_node->get_name()); |
| 5405 | |
| 5406 | p_state->scene_mesh_instances.insert(p_node_index, mi); |
| 5407 | Ref<GLTFMesh> mesh = p_state->meshes.write[gltf_node->mesh]; |
| 5408 | if (mesh.is_null()) { |
| 5409 | return mi; |
| 5410 | } |
| 5411 | Ref<ImporterMesh> import_mesh = mesh->get_mesh(); |
| 5412 | if (import_mesh.is_null()) { |
| 5413 | return mi; |
| 5414 | } |
| 5415 | mi->set_mesh(import_mesh); |
| 5416 | return mi; |
| 5417 | } |
| 5418 | |
| 5419 | Light3D *GLTFDocument::_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { |
| 5420 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5421 | |
| 5422 | ERR_FAIL_INDEX_V(gltf_node->light, p_state->lights.size(), nullptr); |
| 5423 | |
| 5424 | print_verbose("glTF: Creating light for: " + gltf_node->get_name()); |
| 5425 | |
| 5426 | Ref<GLTFLight> l = p_state->lights[gltf_node->light]; |
| 5427 | return l->to_node(); |
| 5428 | } |
| 5429 | |
| 5430 | Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { |
| 5431 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5432 | |
| 5433 | ERR_FAIL_INDEX_V(gltf_node->camera, p_state->cameras.size(), nullptr); |
| 5434 | |
| 5435 | print_verbose("glTF: Creating camera for: " + gltf_node->get_name()); |
| 5436 | |
| 5437 | Ref<GLTFCamera> c = p_state->cameras[gltf_node->camera]; |
| 5438 | return c->to_node(); |
| 5439 | } |
| 5440 | |
| 5441 | GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> p_state, Camera3D *p_camera) { |
| 5442 | print_verbose("glTF: Converting camera: " + p_camera->get_name()); |
| 5443 | |
| 5444 | Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera); |
| 5445 | GLTFCameraIndex camera_index = p_state->cameras.size(); |
| 5446 | p_state->cameras.push_back(c); |
| 5447 | return camera_index; |
| 5448 | } |
| 5449 | |
| 5450 | GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> p_state, Light3D *p_light) { |
| 5451 | print_verbose("glTF: Converting light: " + p_light->get_name()); |
| 5452 | |
| 5453 | Ref<GLTFLight> l = GLTFLight::from_node(p_light); |
| 5454 | |
| 5455 | GLTFLightIndex light_index = p_state->lights.size(); |
| 5456 | p_state->lights.push_back(l); |
| 5457 | return light_index; |
| 5458 | } |
| 5459 | |
| 5460 | void GLTFDocument::_convert_spatial(Ref<GLTFState> p_state, Node3D *p_spatial, Ref<GLTFNode> p_node) { |
| 5461 | Transform3D xform = p_spatial->get_transform(); |
| 5462 | p_node->scale = xform.basis.get_scale(); |
| 5463 | p_node->rotation = xform.basis.get_rotation_quaternion(); |
| 5464 | p_node->position = xform.origin; |
| 5465 | } |
| 5466 | |
| 5467 | Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { |
| 5468 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5469 | |
| 5470 | Node3D *spatial = memnew(Node3D); |
| 5471 | print_verbose("glTF: Converting spatial: " + gltf_node->get_name()); |
| 5472 | |
| 5473 | return spatial; |
| 5474 | } |
| 5475 | |
| 5476 | void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { |
| 5477 | bool retflag = true; |
| 5478 | _check_visibility(p_current, retflag); |
| 5479 | if (retflag) { |
| 5480 | return; |
| 5481 | } |
| 5482 | Ref<GLTFNode> gltf_node; |
| 5483 | gltf_node.instantiate(); |
| 5484 | gltf_node->set_name(_gen_unique_name(p_state, p_current->get_name())); |
| 5485 | if (cast_to<Node3D>(p_current)) { |
| 5486 | Node3D *spatial = cast_to<Node3D>(p_current); |
| 5487 | _convert_spatial(p_state, spatial, gltf_node); |
| 5488 | } |
| 5489 | if (cast_to<MeshInstance3D>(p_current)) { |
| 5490 | MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current); |
| 5491 | _convert_mesh_instance_to_gltf(mi, p_state, gltf_node); |
| 5492 | } else if (cast_to<BoneAttachment3D>(p_current)) { |
| 5493 | BoneAttachment3D *bone = cast_to<BoneAttachment3D>(p_current); |
| 5494 | _convert_bone_attachment_to_gltf(bone, p_state, p_gltf_parent, p_gltf_root, gltf_node); |
| 5495 | return; |
| 5496 | } else if (cast_to<Skeleton3D>(p_current)) { |
| 5497 | Skeleton3D *skel = cast_to<Skeleton3D>(p_current); |
| 5498 | _convert_skeleton_to_gltf(skel, p_state, p_gltf_parent, p_gltf_root, gltf_node); |
| 5499 | // We ignore the Godot Engine node that is the skeleton. |
| 5500 | return; |
| 5501 | } else if (cast_to<MultiMeshInstance3D>(p_current)) { |
| 5502 | MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current); |
| 5503 | _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, p_state); |
| 5504 | #ifdef MODULE_CSG_ENABLED |
| 5505 | } else if (cast_to<CSGShape3D>(p_current)) { |
| 5506 | CSGShape3D *shape = cast_to<CSGShape3D>(p_current); |
| 5507 | if (shape->get_parent() && shape->is_root_shape()) { |
| 5508 | _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, p_state); |
| 5509 | } |
| 5510 | #endif // MODULE_CSG_ENABLED |
| 5511 | #ifdef MODULE_GRIDMAP_ENABLED |
| 5512 | } else if (cast_to<GridMap>(p_current)) { |
| 5513 | GridMap *gridmap = Object::cast_to<GridMap>(p_current); |
| 5514 | _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, p_state); |
| 5515 | #endif // MODULE_GRIDMAP_ENABLED |
| 5516 | } else if (cast_to<Camera3D>(p_current)) { |
| 5517 | Camera3D *camera = Object::cast_to<Camera3D>(p_current); |
| 5518 | _convert_camera_to_gltf(camera, p_state, gltf_node); |
| 5519 | } else if (cast_to<Light3D>(p_current)) { |
| 5520 | Light3D *light = Object::cast_to<Light3D>(p_current); |
| 5521 | _convert_light_to_gltf(light, p_state, gltf_node); |
| 5522 | } else if (cast_to<AnimationPlayer>(p_current)) { |
| 5523 | AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current); |
| 5524 | _convert_animation_player_to_gltf(animation_player, p_state, p_gltf_parent, p_gltf_root, gltf_node, p_current); |
| 5525 | } |
| 5526 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 5527 | ERR_CONTINUE(ext.is_null()); |
| 5528 | ext->convert_scene_node(p_state, gltf_node, p_current); |
| 5529 | } |
| 5530 | GLTFNodeIndex current_node_i = p_state->nodes.size(); |
| 5531 | GLTFNodeIndex gltf_root = p_gltf_root; |
| 5532 | if (gltf_root == -1) { |
| 5533 | gltf_root = current_node_i; |
| 5534 | p_state->root_nodes.push_back(gltf_root); |
| 5535 | } |
| 5536 | _create_gltf_node(p_state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node); |
| 5537 | for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) { |
| 5538 | _convert_scene_node(p_state, p_current->get_child(node_i), current_node_i, gltf_root); |
| 5539 | } |
| 5540 | } |
| 5541 | |
| 5542 | #ifdef MODULE_CSG_ENABLED |
| 5543 | void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { |
| 5544 | CSGShape3D *csg = p_current; |
| 5545 | csg->call("_update_shape" ); |
| 5546 | Array meshes = csg->get_meshes(); |
| 5547 | if (meshes.size() != 2) { |
| 5548 | return; |
| 5549 | } |
| 5550 | |
| 5551 | Ref<ImporterMesh> mesh; |
| 5552 | mesh.instantiate(); |
| 5553 | { |
| 5554 | Ref<Mesh> csg_mesh = csg->get_meshes()[1]; |
| 5555 | |
| 5556 | for (int32_t surface_i = 0; surface_i < csg_mesh->get_surface_count(); surface_i++) { |
| 5557 | Array array = csg_mesh->surface_get_arrays(surface_i); |
| 5558 | Ref<Material> mat = csg_mesh->surface_get_material(surface_i); |
| 5559 | String mat_name; |
| 5560 | if (mat.is_valid()) { |
| 5561 | mat_name = mat->get_name(); |
| 5562 | } else { |
| 5563 | // Assign default material when no material is assigned. |
| 5564 | mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); |
| 5565 | } |
| 5566 | mesh->add_surface(csg_mesh->surface_get_primitive_type(surface_i), |
| 5567 | array, csg_mesh->surface_get_blend_shape_arrays(surface_i), csg_mesh->surface_get_lods(surface_i), mat, |
| 5568 | mat_name, csg_mesh->surface_get_format(surface_i)); |
| 5569 | } |
| 5570 | } |
| 5571 | |
| 5572 | Ref<GLTFMesh> gltf_mesh; |
| 5573 | gltf_mesh.instantiate(); |
| 5574 | gltf_mesh->set_mesh(mesh); |
| 5575 | GLTFMeshIndex mesh_i = p_state->meshes.size(); |
| 5576 | p_state->meshes.push_back(gltf_mesh); |
| 5577 | p_gltf_node->mesh = mesh_i; |
| 5578 | p_gltf_node->xform = csg->get_meshes()[0]; |
| 5579 | p_gltf_node->set_name(_gen_unique_name(p_state, csg->get_name())); |
| 5580 | } |
| 5581 | #endif // MODULE_CSG_ENABLED |
| 5582 | |
| 5583 | void GLTFDocument::_create_gltf_node(Ref<GLTFState> p_state, Node *p_scene_parent, GLTFNodeIndex p_current_node_i, |
| 5584 | GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> p_gltf_node) { |
| 5585 | p_state->scene_nodes.insert(p_current_node_i, p_scene_parent); |
| 5586 | p_state->nodes.push_back(p_gltf_node); |
| 5587 | ERR_FAIL_COND(p_current_node_i == p_parent_node_index); |
| 5588 | p_state->nodes.write[p_current_node_i]->parent = p_parent_node_index; |
| 5589 | if (p_parent_node_index == -1) { |
| 5590 | return; |
| 5591 | } |
| 5592 | p_state->nodes.write[p_parent_node_index]->children.push_back(p_current_node_i); |
| 5593 | } |
| 5594 | |
| 5595 | void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *p_animation_player, Ref<GLTFState> p_state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { |
| 5596 | ERR_FAIL_COND(!p_animation_player); |
| 5597 | p_state->animation_players.push_back(p_animation_player); |
| 5598 | print_verbose(String("glTF: Converting animation player: " ) + p_animation_player->get_name()); |
| 5599 | } |
| 5600 | |
| 5601 | void GLTFDocument::_check_visibility(Node *p_node, bool &r_retflag) { |
| 5602 | r_retflag = true; |
| 5603 | Node3D *spatial = Object::cast_to<Node3D>(p_node); |
| 5604 | Node2D *node_2d = Object::cast_to<Node2D>(p_node); |
| 5605 | if (node_2d && !node_2d->is_visible()) { |
| 5606 | return; |
| 5607 | } |
| 5608 | if (spatial && !spatial->is_visible()) { |
| 5609 | return; |
| 5610 | } |
| 5611 | r_retflag = false; |
| 5612 | } |
| 5613 | |
| 5614 | void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { |
| 5615 | ERR_FAIL_COND(!camera); |
| 5616 | GLTFCameraIndex camera_index = _convert_camera(p_state, camera); |
| 5617 | if (camera_index != -1) { |
| 5618 | p_gltf_node->camera = camera_index; |
| 5619 | } |
| 5620 | } |
| 5621 | |
| 5622 | void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { |
| 5623 | ERR_FAIL_COND(!light); |
| 5624 | GLTFLightIndex light_index = _convert_light(p_state, light); |
| 5625 | if (light_index != -1) { |
| 5626 | p_gltf_node->light = light_index; |
| 5627 | } |
| 5628 | } |
| 5629 | |
| 5630 | #ifdef MODULE_GRIDMAP_ENABLED |
| 5631 | void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { |
| 5632 | Array cells = p_grid_map->get_used_cells(); |
| 5633 | for (int32_t k = 0; k < cells.size(); k++) { |
| 5634 | GLTFNode *new_gltf_node = memnew(GLTFNode); |
| 5635 | p_gltf_node->children.push_back(p_state->nodes.size()); |
| 5636 | p_state->nodes.push_back(new_gltf_node); |
| 5637 | Vector3 cell_location = cells[k]; |
| 5638 | int32_t cell = p_grid_map->get_cell_item( |
| 5639 | Vector3(cell_location.x, cell_location.y, cell_location.z)); |
| 5640 | Transform3D cell_xform; |
| 5641 | cell_xform.basis = p_grid_map->get_basis_with_orthogonal_index( |
| 5642 | p_grid_map->get_cell_item_orientation( |
| 5643 | Vector3(cell_location.x, cell_location.y, cell_location.z))); |
| 5644 | cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(), |
| 5645 | p_grid_map->get_cell_scale(), |
| 5646 | p_grid_map->get_cell_scale())); |
| 5647 | cell_xform.set_origin(p_grid_map->map_to_local( |
| 5648 | Vector3(cell_location.x, cell_location.y, cell_location.z))); |
| 5649 | Ref<GLTFMesh> gltf_mesh; |
| 5650 | gltf_mesh.instantiate(); |
| 5651 | gltf_mesh->set_mesh(_mesh_to_importer_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell))); |
| 5652 | new_gltf_node->mesh = p_state->meshes.size(); |
| 5653 | p_state->meshes.push_back(gltf_mesh); |
| 5654 | new_gltf_node->xform = cell_xform * p_grid_map->get_transform(); |
| 5655 | new_gltf_node->set_name(_gen_unique_name(p_state, p_grid_map->get_mesh_library()->get_item_name(cell))); |
| 5656 | } |
| 5657 | } |
| 5658 | #endif // MODULE_GRIDMAP_ENABLED |
| 5659 | |
| 5660 | void GLTFDocument::_convert_multi_mesh_instance_to_gltf( |
| 5661 | MultiMeshInstance3D *p_multi_mesh_instance, |
| 5662 | GLTFNodeIndex p_parent_node_index, |
| 5663 | GLTFNodeIndex p_root_node_index, |
| 5664 | Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { |
| 5665 | ERR_FAIL_COND(!p_multi_mesh_instance); |
| 5666 | Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh(); |
| 5667 | if (multi_mesh.is_null()) { |
| 5668 | return; |
| 5669 | } |
| 5670 | Ref<GLTFMesh> gltf_mesh; |
| 5671 | gltf_mesh.instantiate(); |
| 5672 | Ref<Mesh> mesh = multi_mesh->get_mesh(); |
| 5673 | if (mesh.is_null()) { |
| 5674 | return; |
| 5675 | } |
| 5676 | gltf_mesh->set_name(multi_mesh->get_name()); |
| 5677 | Ref<ImporterMesh> importer_mesh; |
| 5678 | importer_mesh.instantiate(); |
| 5679 | Ref<ArrayMesh> array_mesh = multi_mesh->get_mesh(); |
| 5680 | if (array_mesh.is_valid()) { |
| 5681 | importer_mesh->set_blend_shape_mode(array_mesh->get_blend_shape_mode()); |
| 5682 | for (int32_t blend_i = 0; blend_i < array_mesh->get_blend_shape_count(); blend_i++) { |
| 5683 | importer_mesh->add_blend_shape(array_mesh->get_blend_shape_name(blend_i)); |
| 5684 | } |
| 5685 | } |
| 5686 | for (int32_t surface_i = 0; surface_i < mesh->get_surface_count(); surface_i++) { |
| 5687 | Ref<Material> mat = mesh->surface_get_material(surface_i); |
| 5688 | String material_name; |
| 5689 | if (mat.is_valid()) { |
| 5690 | material_name = mat->get_name(); |
| 5691 | } |
| 5692 | Array blend_arrays; |
| 5693 | if (array_mesh.is_valid()) { |
| 5694 | blend_arrays = array_mesh->surface_get_blend_shape_arrays(surface_i); |
| 5695 | } |
| 5696 | importer_mesh->add_surface(mesh->surface_get_primitive_type(surface_i), mesh->surface_get_arrays(surface_i), |
| 5697 | blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i)); |
| 5698 | } |
| 5699 | gltf_mesh->set_mesh(importer_mesh); |
| 5700 | GLTFMeshIndex mesh_index = p_state->meshes.size(); |
| 5701 | p_state->meshes.push_back(gltf_mesh); |
| 5702 | for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); |
| 5703 | instance_i++) { |
| 5704 | Transform3D transform; |
| 5705 | if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) { |
| 5706 | Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i); |
| 5707 | transform.origin = |
| 5708 | Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y); |
| 5709 | real_t rotation = xform_2d.get_rotation(); |
| 5710 | Quaternion quaternion(Vector3(0, 1, 0), rotation); |
| 5711 | Size2 scale = xform_2d.get_scale(); |
| 5712 | transform.basis.set_quaternion_scale(quaternion, |
| 5713 | Vector3(scale.x, 0, scale.y)); |
| 5714 | transform = p_multi_mesh_instance->get_transform() * transform; |
| 5715 | } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) { |
| 5716 | transform = p_multi_mesh_instance->get_transform() * |
| 5717 | multi_mesh->get_instance_transform(instance_i); |
| 5718 | } |
| 5719 | Ref<GLTFNode> new_gltf_node; |
| 5720 | new_gltf_node.instantiate(); |
| 5721 | new_gltf_node->mesh = mesh_index; |
| 5722 | new_gltf_node->xform = transform; |
| 5723 | new_gltf_node->set_name(_gen_unique_name(p_state, p_multi_mesh_instance->get_name())); |
| 5724 | p_gltf_node->children.push_back(p_state->nodes.size()); |
| 5725 | p_state->nodes.push_back(new_gltf_node); |
| 5726 | } |
| 5727 | } |
| 5728 | |
| 5729 | void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) { |
| 5730 | Skeleton3D *skeleton = p_skeleton3d; |
| 5731 | Ref<GLTFSkeleton> gltf_skeleton; |
| 5732 | gltf_skeleton.instantiate(); |
| 5733 | // GLTFSkeleton is only used to hold internal p_state data. It will not be written to the document. |
| 5734 | // |
| 5735 | gltf_skeleton->godot_skeleton = skeleton; |
| 5736 | GLTFSkeletonIndex skeleton_i = p_state->skeletons.size(); |
| 5737 | p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i; |
| 5738 | p_state->skeletons.push_back(gltf_skeleton); |
| 5739 | |
| 5740 | BoneId bone_count = skeleton->get_bone_count(); |
| 5741 | for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { |
| 5742 | Ref<GLTFNode> joint_node; |
| 5743 | joint_node.instantiate(); |
| 5744 | // Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node |
| 5745 | // names to be unique regardless of whether or not they are used as joints. |
| 5746 | joint_node->set_name(_gen_unique_name(p_state, skeleton->get_bone_name(bone_i))); |
| 5747 | Transform3D xform = skeleton->get_bone_pose(bone_i); |
| 5748 | joint_node->scale = xform.basis.get_scale(); |
| 5749 | joint_node->rotation = xform.basis.get_rotation_quaternion(); |
| 5750 | joint_node->position = xform.origin; |
| 5751 | joint_node->joint = true; |
| 5752 | GLTFNodeIndex current_node_i = p_state->nodes.size(); |
| 5753 | p_state->scene_nodes.insert(current_node_i, skeleton); |
| 5754 | p_state->nodes.push_back(joint_node); |
| 5755 | |
| 5756 | gltf_skeleton->joints.push_back(current_node_i); |
| 5757 | if (skeleton->get_bone_parent(bone_i) == -1) { |
| 5758 | gltf_skeleton->roots.push_back(current_node_i); |
| 5759 | } |
| 5760 | gltf_skeleton->godot_bone_node.insert(bone_i, current_node_i); |
| 5761 | } |
| 5762 | for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { |
| 5763 | GLTFNodeIndex current_node_i = gltf_skeleton->godot_bone_node[bone_i]; |
| 5764 | BoneId parent_bone_id = skeleton->get_bone_parent(bone_i); |
| 5765 | if (parent_bone_id == -1) { |
| 5766 | if (p_parent_node_index != -1) { |
| 5767 | p_state->nodes.write[current_node_i]->parent = p_parent_node_index; |
| 5768 | p_state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); |
| 5769 | } |
| 5770 | } else { |
| 5771 | GLTFNodeIndex parent_node_i = gltf_skeleton->godot_bone_node[parent_bone_id]; |
| 5772 | p_state->nodes.write[current_node_i]->parent = parent_node_i; |
| 5773 | p_state->nodes.write[parent_node_i]->children.push_back(current_node_i); |
| 5774 | } |
| 5775 | } |
| 5776 | // Remove placeholder skeleton3d node by not creating the gltf node |
| 5777 | // Skins are per mesh |
| 5778 | for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) { |
| 5779 | _convert_scene_node(p_state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index); |
| 5780 | } |
| 5781 | } |
| 5782 | |
| 5783 | void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) { |
| 5784 | Skeleton3D *skeleton; |
| 5785 | // Note that relative transforms to external skeletons and pose overrides are not supported. |
| 5786 | if (p_bone_attachment->get_use_external_skeleton()) { |
| 5787 | skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton())); |
| 5788 | } else { |
| 5789 | skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_parent()); |
| 5790 | } |
| 5791 | GLTFSkeletonIndex skel_gltf_i = -1; |
| 5792 | if (skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) { |
| 5793 | skel_gltf_i = p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()]; |
| 5794 | } |
| 5795 | int bone_idx = -1; |
| 5796 | if (skeleton != nullptr) { |
| 5797 | bone_idx = p_bone_attachment->get_bone_idx(); |
| 5798 | if (bone_idx == -1) { |
| 5799 | bone_idx = skeleton->find_bone(p_bone_attachment->get_bone_name()); |
| 5800 | } |
| 5801 | } |
| 5802 | GLTFNodeIndex par_node_index = p_parent_node_index; |
| 5803 | if (skeleton != nullptr && bone_idx != -1 && skel_gltf_i != -1) { |
| 5804 | Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_gltf_i]; |
| 5805 | gltf_skeleton->bone_attachments.push_back(p_bone_attachment); |
| 5806 | par_node_index = gltf_skeleton->joints[bone_idx]; |
| 5807 | } |
| 5808 | |
| 5809 | for (int node_i = 0; node_i < p_bone_attachment->get_child_count(); node_i++) { |
| 5810 | _convert_scene_node(p_state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index); |
| 5811 | } |
| 5812 | } |
| 5813 | |
| 5814 | void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { |
| 5815 | GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(p_state, p_scene_parent); |
| 5816 | if (gltf_mesh_index != -1) { |
| 5817 | p_gltf_node->mesh = gltf_mesh_index; |
| 5818 | } |
| 5819 | } |
| 5820 | |
| 5821 | void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root) { |
| 5822 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5823 | |
| 5824 | if (gltf_node->skeleton >= 0) { |
| 5825 | _generate_skeleton_bone_node(p_state, p_node_index, p_scene_parent, p_scene_root); |
| 5826 | return; |
| 5827 | } |
| 5828 | |
| 5829 | Node3D *current_node = nullptr; |
| 5830 | |
| 5831 | // Is our parent a skeleton |
| 5832 | Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent); |
| 5833 | |
| 5834 | const bool non_bone_parented_to_skeleton = active_skeleton; |
| 5835 | |
| 5836 | // skinned meshes must not be placed in a bone attachment. |
| 5837 | if (non_bone_parented_to_skeleton && gltf_node->skin < 0) { |
| 5838 | // Bone Attachment - Parent Case |
| 5839 | BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent); |
| 5840 | |
| 5841 | p_scene_parent->add_child(bone_attachment, true); |
| 5842 | bone_attachment->set_owner(p_scene_root); |
| 5843 | |
| 5844 | // There is no gltf_node that represent this, so just directly create a unique name |
| 5845 | bone_attachment->set_name(gltf_node->get_name()); |
| 5846 | |
| 5847 | // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node |
| 5848 | // and attach it to the bone_attachment |
| 5849 | p_scene_parent = bone_attachment; |
| 5850 | } |
| 5851 | // Check if any GLTFDocumentExtension classes want to generate a node for us. |
| 5852 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 5853 | ERR_CONTINUE(ext.is_null()); |
| 5854 | current_node = ext->generate_scene_node(p_state, gltf_node, p_scene_parent); |
| 5855 | if (current_node) { |
| 5856 | break; |
| 5857 | } |
| 5858 | } |
| 5859 | // If none of our GLTFDocumentExtension classes generated us a node, we generate one. |
| 5860 | if (!current_node) { |
| 5861 | if (gltf_node->skin >= 0 && gltf_node->mesh >= 0 && !gltf_node->children.is_empty()) { |
| 5862 | // GLTF specifies that skinned meshes should ignore their node transforms, |
| 5863 | // only being controlled by the skeleton, so Godot will reparent a skinned |
| 5864 | // mesh to its skeleton. However, we still need to ensure any child nodes |
| 5865 | // keep their place in the tree, so if there are any child nodes, the skinned |
| 5866 | // mesh must not be the base node, so generate an empty spatial base. |
| 5867 | current_node = _generate_spatial(p_state, p_node_index); |
| 5868 | Node3D *mesh_inst = _generate_mesh_instance(p_state, p_node_index); |
| 5869 | mesh_inst->set_name(gltf_node->get_name()); |
| 5870 | current_node->add_child(mesh_inst, true); |
| 5871 | } else if (gltf_node->mesh >= 0) { |
| 5872 | current_node = _generate_mesh_instance(p_state, p_node_index); |
| 5873 | } else if (gltf_node->camera >= 0) { |
| 5874 | current_node = _generate_camera(p_state, p_node_index); |
| 5875 | } else if (gltf_node->light >= 0) { |
| 5876 | current_node = _generate_light(p_state, p_node_index); |
| 5877 | } else { |
| 5878 | current_node = _generate_spatial(p_state, p_node_index); |
| 5879 | } |
| 5880 | } |
| 5881 | String gltf_node_name = gltf_node->get_name(); |
| 5882 | if (!gltf_node_name.is_empty()) { |
| 5883 | current_node->set_name(gltf_node_name); |
| 5884 | } |
| 5885 | // Add the node we generated and set the owner to the scene root. |
| 5886 | p_scene_parent->add_child(current_node, true); |
| 5887 | if (current_node != p_scene_root) { |
| 5888 | Array args; |
| 5889 | args.append(p_scene_root); |
| 5890 | current_node->propagate_call(StringName("set_owner" ), args); |
| 5891 | } |
| 5892 | current_node->set_transform(gltf_node->xform); |
| 5893 | |
| 5894 | p_state->scene_nodes.insert(p_node_index, current_node); |
| 5895 | for (int i = 0; i < gltf_node->children.size(); ++i) { |
| 5896 | _generate_scene_node(p_state, gltf_node->children[i], current_node, p_scene_root); |
| 5897 | } |
| 5898 | } |
| 5899 | |
| 5900 | void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root) { |
| 5901 | Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; |
| 5902 | |
| 5903 | Node3D *current_node = nullptr; |
| 5904 | |
| 5905 | Skeleton3D *skeleton = p_state->skeletons[gltf_node->skeleton]->godot_skeleton; |
| 5906 | // In this case, this node is already a bone in skeleton. |
| 5907 | const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0); |
| 5908 | const bool = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0); |
| 5909 | |
| 5910 | Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent); |
| 5911 | if (active_skeleton != skeleton) { |
| 5912 | if (active_skeleton) { |
| 5913 | // Should no longer be possible. |
| 5914 | ERR_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d" , p_node_index)); |
| 5915 | BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent); |
| 5916 | p_scene_parent->add_child(bone_attachment, true); |
| 5917 | bone_attachment->set_owner(p_scene_root); |
| 5918 | // There is no gltf_node that represent this, so just directly create a unique name |
| 5919 | bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D" )); |
| 5920 | // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node |
| 5921 | // and attach it to the bone_attachment |
| 5922 | p_scene_parent = bone_attachment; |
| 5923 | } |
| 5924 | if (skeleton->get_parent() == nullptr) { |
| 5925 | p_scene_parent->add_child(skeleton, true); |
| 5926 | skeleton->set_owner(p_scene_root); |
| 5927 | } |
| 5928 | } |
| 5929 | |
| 5930 | active_skeleton = skeleton; |
| 5931 | current_node = active_skeleton; |
| 5932 | |
| 5933 | if (requires_extra_node) { |
| 5934 | current_node = nullptr; |
| 5935 | // skinned meshes must not be placed in a bone attachment. |
| 5936 | if (!is_skinned_mesh) { |
| 5937 | // Bone Attachment - Same Node Case |
| 5938 | BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index); |
| 5939 | |
| 5940 | p_scene_parent->add_child(bone_attachment, true); |
| 5941 | bone_attachment->set_owner(p_scene_root); |
| 5942 | |
| 5943 | // There is no gltf_node that represent this, so just directly create a unique name |
| 5944 | bone_attachment->set_name(gltf_node->get_name()); |
| 5945 | |
| 5946 | // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node |
| 5947 | // and attach it to the bone_attachment |
| 5948 | p_scene_parent = bone_attachment; |
| 5949 | } |
| 5950 | // Check if any GLTFDocumentExtension classes want to generate a node for us. |
| 5951 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 5952 | ERR_CONTINUE(ext.is_null()); |
| 5953 | current_node = ext->generate_scene_node(p_state, gltf_node, p_scene_parent); |
| 5954 | if (current_node) { |
| 5955 | break; |
| 5956 | } |
| 5957 | } |
| 5958 | // If none of our GLTFDocumentExtension classes generated us a node, we generate one. |
| 5959 | if (!current_node) { |
| 5960 | if (gltf_node->mesh >= 0) { |
| 5961 | current_node = _generate_mesh_instance(p_state, p_node_index); |
| 5962 | } else if (gltf_node->camera >= 0) { |
| 5963 | current_node = _generate_camera(p_state, p_node_index); |
| 5964 | } else if (gltf_node->light >= 0) { |
| 5965 | current_node = _generate_light(p_state, p_node_index); |
| 5966 | } else { |
| 5967 | current_node = _generate_spatial(p_state, p_node_index); |
| 5968 | } |
| 5969 | } |
| 5970 | // Add the node we generated and set the owner to the scene root. |
| 5971 | p_scene_parent->add_child(current_node, true); |
| 5972 | if (current_node != p_scene_root) { |
| 5973 | Array args; |
| 5974 | args.append(p_scene_root); |
| 5975 | current_node->propagate_call(StringName("set_owner" ), args); |
| 5976 | } |
| 5977 | // Do not set transform here. Transform is already applied to our bone. |
| 5978 | current_node->set_name(gltf_node->get_name()); |
| 5979 | } |
| 5980 | |
| 5981 | p_state->scene_nodes.insert(p_node_index, current_node); |
| 5982 | |
| 5983 | for (int i = 0; i < gltf_node->children.size(); ++i) { |
| 5984 | _generate_scene_node(p_state, gltf_node->children[i], active_skeleton, p_scene_root); |
| 5985 | } |
| 5986 | } |
| 5987 | |
| 5988 | template <class T> |
| 5989 | struct SceneFormatImporterGLTFInterpolate { |
| 5990 | T lerp(const T &a, const T &b, float c) const { |
| 5991 | return a + (b - a) * c; |
| 5992 | } |
| 5993 | |
| 5994 | T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) { |
| 5995 | const float t2 = t * t; |
| 5996 | const float t3 = t2 * t; |
| 5997 | |
| 5998 | return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); |
| 5999 | } |
| 6000 | |
| 6001 | T bezier(T start, T control_1, T control_2, T end, float t) { |
| 6002 | /* Formula from Wikipedia article on Bezier curves. */ |
| 6003 | const real_t omt = (1.0 - t); |
| 6004 | const real_t omt2 = omt * omt; |
| 6005 | const real_t omt3 = omt2 * omt; |
| 6006 | const real_t t2 = t * t; |
| 6007 | const real_t t3 = t2 * t; |
| 6008 | |
| 6009 | return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; |
| 6010 | } |
| 6011 | }; |
| 6012 | |
| 6013 | // thank you for existing, partial specialization |
| 6014 | template <> |
| 6015 | struct SceneFormatImporterGLTFInterpolate<Quaternion> { |
| 6016 | Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const { |
| 6017 | ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized." ); |
| 6018 | ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized." ); |
| 6019 | |
| 6020 | return a.slerp(b, c).normalized(); |
| 6021 | } |
| 6022 | |
| 6023 | Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, const float c) { |
| 6024 | ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), "The quaternion \"p1\" must be normalized." ); |
| 6025 | ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), "The quaternion \"p2\" must be normalized." ); |
| 6026 | |
| 6027 | return p1.slerp(p2, c).normalized(); |
| 6028 | } |
| 6029 | |
| 6030 | Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) { |
| 6031 | ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), "The start quaternion must be normalized." ); |
| 6032 | ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), "The end quaternion must be normalized." ); |
| 6033 | |
| 6034 | return start.slerp(end, t).normalized(); |
| 6035 | } |
| 6036 | }; |
| 6037 | |
| 6038 | template <class T> |
| 6039 | T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) { |
| 6040 | ERR_FAIL_COND_V(!p_values.size(), T()); |
| 6041 | if (p_times.size() != (p_values.size() / (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE ? 3 : 1))) { |
| 6042 | ERR_PRINT_ONCE("The interpolated values are not corresponding to its times." ); |
| 6043 | return p_values[0]; |
| 6044 | } |
| 6045 | //could use binary search, worth it? |
| 6046 | int idx = -1; |
| 6047 | for (int i = 0; i < p_times.size(); i++) { |
| 6048 | if (p_times[i] > p_time) { |
| 6049 | break; |
| 6050 | } |
| 6051 | idx++; |
| 6052 | } |
| 6053 | |
| 6054 | SceneFormatImporterGLTFInterpolate<T> interp; |
| 6055 | |
| 6056 | switch (p_interp) { |
| 6057 | case GLTFAnimation::INTERP_LINEAR: { |
| 6058 | if (idx == -1) { |
| 6059 | return p_values[0]; |
| 6060 | } else if (idx >= p_times.size() - 1) { |
| 6061 | return p_values[p_times.size() - 1]; |
| 6062 | } |
| 6063 | |
| 6064 | const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); |
| 6065 | |
| 6066 | return interp.lerp(p_values[idx], p_values[idx + 1], c); |
| 6067 | } break; |
| 6068 | case GLTFAnimation::INTERP_STEP: { |
| 6069 | if (idx == -1) { |
| 6070 | return p_values[0]; |
| 6071 | } else if (idx >= p_times.size() - 1) { |
| 6072 | return p_values[p_times.size() - 1]; |
| 6073 | } |
| 6074 | |
| 6075 | return p_values[idx]; |
| 6076 | } break; |
| 6077 | case GLTFAnimation::INTERP_CATMULLROMSPLINE: { |
| 6078 | if (idx == -1) { |
| 6079 | return p_values[1]; |
| 6080 | } else if (idx >= p_times.size() - 1) { |
| 6081 | return p_values[1 + p_times.size() - 1]; |
| 6082 | } |
| 6083 | |
| 6084 | const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); |
| 6085 | |
| 6086 | return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c); |
| 6087 | } break; |
| 6088 | case GLTFAnimation::INTERP_CUBIC_SPLINE: { |
| 6089 | if (idx == -1) { |
| 6090 | return p_values[1]; |
| 6091 | } else if (idx >= p_times.size() - 1) { |
| 6092 | return p_values[(p_times.size() - 1) * 3 + 1]; |
| 6093 | } |
| 6094 | |
| 6095 | const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); |
| 6096 | |
| 6097 | const T from = p_values[idx * 3 + 1]; |
| 6098 | const T c1 = from + p_values[idx * 3 + 2]; |
| 6099 | const T to = p_values[idx * 3 + 4]; |
| 6100 | const T c2 = to + p_values[idx * 3 + 3]; |
| 6101 | |
| 6102 | return interp.bezier(from, c1, c2, to, c); |
| 6103 | } break; |
| 6104 | } |
| 6105 | |
| 6106 | ERR_FAIL_V(p_values[0]); |
| 6107 | } |
| 6108 | |
| 6109 | void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, const GLTFAnimationIndex p_index, const float p_bake_fps, const bool p_trimming, const bool p_remove_immutable_tracks) { |
| 6110 | Ref<GLTFAnimation> anim = p_state->animations[p_index]; |
| 6111 | |
| 6112 | String anim_name = anim->get_name(); |
| 6113 | if (anim_name.is_empty()) { |
| 6114 | // No node represent these, and they are not in the hierarchy, so just make a unique name |
| 6115 | anim_name = _gen_unique_name(p_state, "Animation" ); |
| 6116 | } |
| 6117 | |
| 6118 | Ref<Animation> animation; |
| 6119 | animation.instantiate(); |
| 6120 | animation->set_name(anim_name); |
| 6121 | |
| 6122 | if (anim->get_loop()) { |
| 6123 | animation->set_loop_mode(Animation::LOOP_LINEAR); |
| 6124 | } |
| 6125 | |
| 6126 | double anim_start = p_trimming ? INFINITY : 0.0; |
| 6127 | double anim_end = 0.0; |
| 6128 | |
| 6129 | for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) { |
| 6130 | const GLTFAnimation::Track &track = track_i.value; |
| 6131 | //need to find the path: for skeletons, weight tracks will affect the mesh |
| 6132 | NodePath node_path; |
| 6133 | //for skeletons, transform tracks always affect bones |
| 6134 | NodePath transform_node_path; |
| 6135 | //for meshes, especially skinned meshes, there are cases where it will be added as a child |
| 6136 | NodePath mesh_instance_node_path; |
| 6137 | |
| 6138 | GLTFNodeIndex node_index = track_i.key; |
| 6139 | |
| 6140 | const Ref<GLTFNode> gltf_node = p_state->nodes[track_i.key]; |
| 6141 | |
| 6142 | Node *root = p_animation_player->get_parent(); |
| 6143 | ERR_FAIL_COND(root == nullptr); |
| 6144 | HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index); |
| 6145 | ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation." , node_index)); |
| 6146 | node_path = root->get_path_to(node_element->value); |
| 6147 | HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mesh_instance_element = p_state->scene_mesh_instances.find(node_index); |
| 6148 | if (mesh_instance_element) { |
| 6149 | mesh_instance_node_path = root->get_path_to(mesh_instance_element->value); |
| 6150 | } else { |
| 6151 | mesh_instance_node_path = node_path; |
| 6152 | } |
| 6153 | |
| 6154 | if (gltf_node->skeleton >= 0) { |
| 6155 | const Skeleton3D *sk = p_state->skeletons[gltf_node->skeleton]->godot_skeleton; |
| 6156 | ERR_FAIL_COND(sk == nullptr); |
| 6157 | |
| 6158 | const String path = p_animation_player->get_parent()->get_path_to(sk); |
| 6159 | const String bone = gltf_node->get_name(); |
| 6160 | transform_node_path = path + ":" + bone; |
| 6161 | } else { |
| 6162 | transform_node_path = node_path; |
| 6163 | } |
| 6164 | |
| 6165 | if (p_trimming) { |
| 6166 | for (int i = 0; i < track.rotation_track.times.size(); i++) { |
| 6167 | anim_start = MIN(anim_start, track.rotation_track.times[i]); |
| 6168 | anim_end = MAX(anim_end, track.rotation_track.times[i]); |
| 6169 | } |
| 6170 | for (int i = 0; i < track.position_track.times.size(); i++) { |
| 6171 | anim_start = MIN(anim_start, track.position_track.times[i]); |
| 6172 | anim_end = MAX(anim_end, track.position_track.times[i]); |
| 6173 | } |
| 6174 | for (int i = 0; i < track.scale_track.times.size(); i++) { |
| 6175 | anim_start = MIN(anim_start, track.scale_track.times[i]); |
| 6176 | anim_end = MAX(anim_end, track.scale_track.times[i]); |
| 6177 | } |
| 6178 | for (int i = 0; i < track.weight_tracks.size(); i++) { |
| 6179 | for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { |
| 6180 | anim_start = MIN(anim_start, track.weight_tracks[i].times[j]); |
| 6181 | anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); |
| 6182 | } |
| 6183 | } |
| 6184 | } else { |
| 6185 | // If you don't use trimming and the first key time is not at 0.0, fake keys will be inserted. |
| 6186 | for (int i = 0; i < track.rotation_track.times.size(); i++) { |
| 6187 | anim_end = MAX(anim_end, track.rotation_track.times[i]); |
| 6188 | } |
| 6189 | for (int i = 0; i < track.position_track.times.size(); i++) { |
| 6190 | anim_end = MAX(anim_end, track.position_track.times[i]); |
| 6191 | } |
| 6192 | for (int i = 0; i < track.scale_track.times.size(); i++) { |
| 6193 | anim_end = MAX(anim_end, track.scale_track.times[i]); |
| 6194 | } |
| 6195 | for (int i = 0; i < track.weight_tracks.size(); i++) { |
| 6196 | for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { |
| 6197 | anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); |
| 6198 | } |
| 6199 | } |
| 6200 | } |
| 6201 | |
| 6202 | // Animated TRS properties will not affect a skinned mesh. |
| 6203 | const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0; |
| 6204 | if ((track.rotation_track.values.size() || track.position_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) { |
| 6205 | //make transform track |
| 6206 | int base_idx = animation->get_track_count(); |
| 6207 | int position_idx = -1; |
| 6208 | int rotation_idx = -1; |
| 6209 | int scale_idx = -1; |
| 6210 | |
| 6211 | if (track.position_track.values.size()) { |
| 6212 | bool is_default = true; //discard the track if all it contains is default values |
| 6213 | if (p_remove_immutable_tracks) { |
| 6214 | Vector3 base_pos = p_state->nodes[track_i.key]->position; |
| 6215 | for (int i = 0; i < track.position_track.times.size(); i++) { |
| 6216 | Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; |
| 6217 | if (!value.is_equal_approx(base_pos)) { |
| 6218 | is_default = false; |
| 6219 | break; |
| 6220 | } |
| 6221 | } |
| 6222 | } |
| 6223 | if (!p_remove_immutable_tracks || !is_default) { |
| 6224 | position_idx = base_idx; |
| 6225 | animation->add_track(Animation::TYPE_POSITION_3D); |
| 6226 | animation->track_set_path(position_idx, transform_node_path); |
| 6227 | animation->track_set_imported(position_idx, true); //helps merging later |
| 6228 | base_idx++; |
| 6229 | } |
| 6230 | } |
| 6231 | if (track.rotation_track.values.size()) { |
| 6232 | bool is_default = true; //discard the track if all it contains is default values |
| 6233 | if (p_remove_immutable_tracks) { |
| 6234 | Quaternion base_rot = p_state->nodes[track_i.key]->rotation.normalized(); |
| 6235 | for (int i = 0; i < track.rotation_track.times.size(); i++) { |
| 6236 | Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized(); |
| 6237 | if (!value.is_equal_approx(base_rot)) { |
| 6238 | is_default = false; |
| 6239 | break; |
| 6240 | } |
| 6241 | } |
| 6242 | } |
| 6243 | if (!p_remove_immutable_tracks || !is_default) { |
| 6244 | rotation_idx = base_idx; |
| 6245 | animation->add_track(Animation::TYPE_ROTATION_3D); |
| 6246 | animation->track_set_path(rotation_idx, transform_node_path); |
| 6247 | animation->track_set_imported(rotation_idx, true); //helps merging later |
| 6248 | base_idx++; |
| 6249 | } |
| 6250 | } |
| 6251 | if (track.scale_track.values.size()) { |
| 6252 | bool is_default = true; //discard the track if all it contains is default values |
| 6253 | if (p_remove_immutable_tracks) { |
| 6254 | Vector3 base_scale = p_state->nodes[track_i.key]->scale; |
| 6255 | for (int i = 0; i < track.scale_track.times.size(); i++) { |
| 6256 | Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; |
| 6257 | if (!value.is_equal_approx(base_scale)) { |
| 6258 | is_default = false; |
| 6259 | break; |
| 6260 | } |
| 6261 | } |
| 6262 | } |
| 6263 | if (!p_remove_immutable_tracks || !is_default) { |
| 6264 | scale_idx = base_idx; |
| 6265 | animation->add_track(Animation::TYPE_SCALE_3D); |
| 6266 | animation->track_set_path(scale_idx, transform_node_path); |
| 6267 | animation->track_set_imported(scale_idx, true); //helps merging later |
| 6268 | base_idx++; |
| 6269 | } |
| 6270 | } |
| 6271 | |
| 6272 | const double increment = 1.0 / p_bake_fps; |
| 6273 | double time = anim_start; |
| 6274 | |
| 6275 | Vector3 base_pos; |
| 6276 | Quaternion base_rot; |
| 6277 | Vector3 base_scale = Vector3(1, 1, 1); |
| 6278 | |
| 6279 | if (rotation_idx == -1) { |
| 6280 | base_rot = p_state->nodes[track_i.key]->rotation.normalized(); |
| 6281 | } |
| 6282 | |
| 6283 | if (position_idx == -1) { |
| 6284 | base_pos = p_state->nodes[track_i.key]->position; |
| 6285 | } |
| 6286 | |
| 6287 | if (scale_idx == -1) { |
| 6288 | base_scale = p_state->nodes[track_i.key]->scale; |
| 6289 | } |
| 6290 | |
| 6291 | bool last = false; |
| 6292 | while (true) { |
| 6293 | Vector3 pos = base_pos; |
| 6294 | Quaternion rot = base_rot; |
| 6295 | Vector3 scale = base_scale; |
| 6296 | |
| 6297 | if (position_idx >= 0) { |
| 6298 | pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation); |
| 6299 | animation->position_track_insert_key(position_idx, time - anim_start, pos); |
| 6300 | } |
| 6301 | |
| 6302 | if (rotation_idx >= 0) { |
| 6303 | rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); |
| 6304 | animation->rotation_track_insert_key(rotation_idx, time - anim_start, rot); |
| 6305 | } |
| 6306 | |
| 6307 | if (scale_idx >= 0) { |
| 6308 | scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); |
| 6309 | animation->scale_track_insert_key(scale_idx, time - anim_start, scale); |
| 6310 | } |
| 6311 | |
| 6312 | if (last) { |
| 6313 | break; |
| 6314 | } |
| 6315 | time += increment; |
| 6316 | if (time >= anim_end) { |
| 6317 | last = true; |
| 6318 | time = anim_end; |
| 6319 | } |
| 6320 | } |
| 6321 | } |
| 6322 | |
| 6323 | for (int i = 0; i < track.weight_tracks.size(); i++) { |
| 6324 | ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= p_state->meshes.size()); |
| 6325 | Ref<GLTFMesh> mesh = p_state->meshes[gltf_node->mesh]; |
| 6326 | ERR_CONTINUE(mesh.is_null()); |
| 6327 | ERR_CONTINUE(mesh->get_mesh().is_null()); |
| 6328 | ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null()); |
| 6329 | |
| 6330 | const String blend_path = String(mesh_instance_node_path) + ":" + String(mesh->get_mesh()->get_blend_shape_name(i)); |
| 6331 | |
| 6332 | const int track_idx = animation->get_track_count(); |
| 6333 | animation->add_track(Animation::TYPE_BLEND_SHAPE); |
| 6334 | animation->track_set_path(track_idx, blend_path); |
| 6335 | animation->track_set_imported(track_idx, true); //helps merging later |
| 6336 | |
| 6337 | // Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation, |
| 6338 | // the other modes have to be baked. |
| 6339 | GLTFAnimation::Interpolation gltf_interp = track.weight_tracks[i].interpolation; |
| 6340 | if (gltf_interp == GLTFAnimation::INTERP_LINEAR || gltf_interp == GLTFAnimation::INTERP_STEP) { |
| 6341 | animation->track_set_interpolation_type(track_idx, gltf_interp == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_LINEAR); |
| 6342 | for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { |
| 6343 | const float t = track.weight_tracks[i].times[j]; |
| 6344 | const float attribs = track.weight_tracks[i].values[j]; |
| 6345 | animation->blend_shape_track_insert_key(track_idx, t, attribs); |
| 6346 | } |
| 6347 | } else { |
| 6348 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6349 | const double increment = 1.0 / p_bake_fps; |
| 6350 | double time = 0.0; |
| 6351 | bool last = false; |
| 6352 | while (true) { |
| 6353 | real_t blend = _interpolate_track<real_t>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp); |
| 6354 | animation->blend_shape_track_insert_key(track_idx, time - anim_start, blend); |
| 6355 | if (last) { |
| 6356 | break; |
| 6357 | } |
| 6358 | time += increment; |
| 6359 | if (time >= anim_end) { |
| 6360 | last = true; |
| 6361 | time = anim_end; |
| 6362 | } |
| 6363 | } |
| 6364 | } |
| 6365 | } |
| 6366 | } |
| 6367 | |
| 6368 | animation->set_length(anim_end - anim_start); |
| 6369 | |
| 6370 | Ref<AnimationLibrary> library; |
| 6371 | if (!p_animation_player->has_animation_library("" )) { |
| 6372 | library.instantiate(); |
| 6373 | p_animation_player->add_animation_library("" , library); |
| 6374 | } else { |
| 6375 | library = p_animation_player->get_animation_library("" ); |
| 6376 | } |
| 6377 | library->add_animation(anim_name, animation); |
| 6378 | } |
| 6379 | |
| 6380 | void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> p_state) { |
| 6381 | for (GLTFNodeIndex mi_node_i = 0; mi_node_i < p_state->nodes.size(); ++mi_node_i) { |
| 6382 | Ref<GLTFNode> node = p_state->nodes[mi_node_i]; |
| 6383 | |
| 6384 | if (node->mesh < 0) { |
| 6385 | continue; |
| 6386 | } |
| 6387 | HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = p_state->scene_nodes.find(mi_node_i); |
| 6388 | if (!mi_element) { |
| 6389 | continue; |
| 6390 | } |
| 6391 | MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->value); |
| 6392 | if (!mi) { |
| 6393 | continue; |
| 6394 | } |
| 6395 | Transform3D mi_xform = mi->get_transform(); |
| 6396 | node->scale = mi_xform.basis.get_scale(); |
| 6397 | node->rotation = mi_xform.basis.get_rotation_quaternion(); |
| 6398 | node->position = mi_xform.origin; |
| 6399 | |
| 6400 | Node *skel_node = mi->get_node_or_null(mi->get_skeleton_path()); |
| 6401 | Skeleton3D *godot_skeleton = Object::cast_to<Skeleton3D>(skel_node); |
| 6402 | if (!godot_skeleton || godot_skeleton->get_bone_count() == 0) { |
| 6403 | continue; |
| 6404 | } |
| 6405 | // At this point in the code, we know we have a Skeleton3D with at least one bone. |
| 6406 | Ref<Skin> skin = mi->get_skin(); |
| 6407 | Ref<GLTFSkin> gltf_skin; |
| 6408 | gltf_skin.instantiate(); |
| 6409 | Array json_joints; |
| 6410 | if (p_state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) { |
| 6411 | // This is a skinned mesh. If the mesh has no ARRAY_WEIGHTS or ARRAY_BONES, it will be invisible. |
| 6412 | const GLTFSkeletonIndex skeleton_gltf_i = p_state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()]; |
| 6413 | Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons[skeleton_gltf_i]; |
| 6414 | int bone_cnt = godot_skeleton->get_bone_count(); |
| 6415 | ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size()); |
| 6416 | |
| 6417 | ObjectID gltf_skin_key; |
| 6418 | if (skin.is_valid()) { |
| 6419 | gltf_skin_key = skin->get_instance_id(); |
| 6420 | } |
| 6421 | ObjectID gltf_skel_key = godot_skeleton->get_instance_id(); |
| 6422 | GLTFSkinIndex skin_gltf_i = -1; |
| 6423 | GLTFNodeIndex root_gltf_i = -1; |
| 6424 | if (!gltf_skeleton->roots.is_empty()) { |
| 6425 | root_gltf_i = gltf_skeleton->roots[0]; |
| 6426 | } |
| 6427 | if (p_state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) { |
| 6428 | skin_gltf_i = p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key]; |
| 6429 | } else { |
| 6430 | if (skin.is_null()) { |
| 6431 | // Note that gltf_skin_key should remain null, so these can share a reference. |
| 6432 | skin = godot_skeleton->create_skin_from_rest_transforms(); |
| 6433 | } |
| 6434 | gltf_skin.instantiate(); |
| 6435 | gltf_skin->godot_skin = skin; |
| 6436 | gltf_skin->set_name(skin->get_name()); |
| 6437 | gltf_skin->skeleton = skeleton_gltf_i; |
| 6438 | gltf_skin->skin_root = root_gltf_i; |
| 6439 | //gltf_state->godot_to_gltf_node[skel_node] |
| 6440 | HashMap<StringName, int> bone_name_to_idx; |
| 6441 | for (int bone_i = 0; bone_i < bone_cnt; bone_i++) { |
| 6442 | bone_name_to_idx[godot_skeleton->get_bone_name(bone_i)] = bone_i; |
| 6443 | } |
| 6444 | for (int bind_i = 0, cnt = skin->get_bind_count(); bind_i < cnt; bind_i++) { |
| 6445 | int bone_i = skin->get_bind_bone(bind_i); |
| 6446 | Transform3D bind_pose = skin->get_bind_pose(bind_i); |
| 6447 | StringName bind_name = skin->get_bind_name(bind_i); |
| 6448 | if (bind_name != StringName()) { |
| 6449 | bone_i = bone_name_to_idx[bind_name]; |
| 6450 | } |
| 6451 | ERR_CONTINUE(bone_i < 0 || bone_i >= bone_cnt); |
| 6452 | if (bind_name == StringName()) { |
| 6453 | bind_name = godot_skeleton->get_bone_name(bone_i); |
| 6454 | } |
| 6455 | GLTFNodeIndex skeleton_bone_i = gltf_skeleton->joints[bone_i]; |
| 6456 | gltf_skin->joints_original.push_back(skeleton_bone_i); |
| 6457 | gltf_skin->joints.push_back(skeleton_bone_i); |
| 6458 | gltf_skin->inverse_binds.push_back(bind_pose); |
| 6459 | if (godot_skeleton->get_bone_parent(bone_i) == -1) { |
| 6460 | gltf_skin->roots.push_back(skeleton_bone_i); |
| 6461 | } |
| 6462 | gltf_skin->joint_i_to_bone_i[bind_i] = bone_i; |
| 6463 | gltf_skin->joint_i_to_name[bind_i] = bind_name; |
| 6464 | } |
| 6465 | skin_gltf_i = p_state->skins.size(); |
| 6466 | p_state->skins.push_back(gltf_skin); |
| 6467 | p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i; |
| 6468 | } |
| 6469 | node->skin = skin_gltf_i; |
| 6470 | node->skeleton = skeleton_gltf_i; |
| 6471 | } |
| 6472 | } |
| 6473 | } |
| 6474 | |
| 6475 | float GLTFDocument::solve_metallic(float p_dielectric_specular, float p_diffuse, float p_specular, float p_one_minus_specular_strength) { |
| 6476 | if (p_specular <= p_dielectric_specular) { |
| 6477 | return 0.0f; |
| 6478 | } |
| 6479 | |
| 6480 | const float a = p_dielectric_specular; |
| 6481 | const float b = p_diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + p_specular - 2.0f * p_dielectric_specular; |
| 6482 | const float c = p_dielectric_specular - p_specular; |
| 6483 | const float D = b * b - 4.0f * a * c; |
| 6484 | return CLAMP((-b + Math::sqrt(D)) / (2.0f * a), 0.0f, 1.0f); |
| 6485 | } |
| 6486 | |
| 6487 | float GLTFDocument::get_perceived_brightness(const Color p_color) { |
| 6488 | const Color coeff = Color(R_BRIGHTNESS_COEFF, G_BRIGHTNESS_COEFF, B_BRIGHTNESS_COEFF); |
| 6489 | const Color value = coeff * (p_color * p_color); |
| 6490 | |
| 6491 | const float r = value.r; |
| 6492 | const float g = value.g; |
| 6493 | const float b = value.b; |
| 6494 | |
| 6495 | return Math::sqrt(r + g + b); |
| 6496 | } |
| 6497 | |
| 6498 | float GLTFDocument::get_max_component(const Color &p_color) { |
| 6499 | const float r = p_color.r; |
| 6500 | const float g = p_color.g; |
| 6501 | const float b = p_color.b; |
| 6502 | |
| 6503 | return MAX(MAX(r, g), b); |
| 6504 | } |
| 6505 | |
| 6506 | void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state) { |
| 6507 | for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { |
| 6508 | Ref<GLTFNode> node = p_state->nodes[node_i]; |
| 6509 | |
| 6510 | if (node->skin >= 0 && node->mesh >= 0) { |
| 6511 | const GLTFSkinIndex skin_i = node->skin; |
| 6512 | |
| 6513 | ImporterMeshInstance3D *mi = nullptr; |
| 6514 | HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mi_element = p_state->scene_mesh_instances.find(node_i); |
| 6515 | if (mi_element) { |
| 6516 | mi = mi_element->value; |
| 6517 | } else { |
| 6518 | HashMap<GLTFNodeIndex, Node *>::Iterator si_element = p_state->scene_nodes.find(node_i); |
| 6519 | ERR_CONTINUE_MSG(!si_element, vformat("Unable to find node %d" , node_i)); |
| 6520 | mi = Object::cast_to<ImporterMeshInstance3D>(si_element->value); |
| 6521 | ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D" , node_i, si_element->value->get_class_name())); |
| 6522 | } |
| 6523 | |
| 6524 | const GLTFSkeletonIndex skel_i = p_state->skins.write[node->skin]->skeleton; |
| 6525 | Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i]; |
| 6526 | Skeleton3D *skeleton = gltf_skeleton->godot_skeleton; |
| 6527 | ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d" , node_i, skin_i)); |
| 6528 | |
| 6529 | mi->get_parent()->remove_child(mi); |
| 6530 | skeleton->add_child(mi, true); |
| 6531 | mi->set_owner(skeleton->get_owner()); |
| 6532 | |
| 6533 | mi->set_skin(p_state->skins.write[skin_i]->godot_skin); |
| 6534 | mi->set_skeleton_path(mi->get_path_to(skeleton)); |
| 6535 | mi->set_transform(Transform3D()); |
| 6536 | } |
| 6537 | } |
| 6538 | } |
| 6539 | |
| 6540 | GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> p_state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) { |
| 6541 | Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i); |
| 6542 | |
| 6543 | GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6544 | if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) { |
| 6545 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6546 | } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) { |
| 6547 | gltf_interpolation = GLTFAnimation::INTERP_STEP; |
| 6548 | } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) { |
| 6549 | gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE; |
| 6550 | } |
| 6551 | Animation::TrackType track_type = p_animation->track_get_type(p_track_i); |
| 6552 | int32_t key_count = p_animation->track_get_key_count(p_track_i); |
| 6553 | Vector<real_t> times; |
| 6554 | times.resize(key_count); |
| 6555 | String path = p_animation->track_get_path(p_track_i); |
| 6556 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6557 | times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i); |
| 6558 | } |
| 6559 | double anim_end = p_animation->get_length(); |
| 6560 | if (track_type == Animation::TYPE_SCALE_3D) { |
| 6561 | if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 6562 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6563 | p_track.scale_track.times.clear(); |
| 6564 | p_track.scale_track.values.clear(); |
| 6565 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6566 | const double increment = 1.0 / BAKE_FPS; |
| 6567 | double time = 0.0; |
| 6568 | bool last = false; |
| 6569 | while (true) { |
| 6570 | Vector3 scale; |
| 6571 | Error err = p_animation->try_scale_track_interpolate(p_track_i, time, &scale); |
| 6572 | ERR_CONTINUE(err != OK); |
| 6573 | p_track.scale_track.values.push_back(scale); |
| 6574 | p_track.scale_track.times.push_back(time); |
| 6575 | if (last) { |
| 6576 | break; |
| 6577 | } |
| 6578 | time += increment; |
| 6579 | if (time >= anim_end) { |
| 6580 | last = true; |
| 6581 | time = anim_end; |
| 6582 | } |
| 6583 | } |
| 6584 | } else { |
| 6585 | p_track.scale_track.times = times; |
| 6586 | p_track.scale_track.interpolation = gltf_interpolation; |
| 6587 | p_track.scale_track.values.resize(key_count); |
| 6588 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6589 | Vector3 scale; |
| 6590 | Error err = p_animation->scale_track_get_key(p_track_i, key_i, &scale); |
| 6591 | ERR_CONTINUE(err != OK); |
| 6592 | p_track.scale_track.values.write[key_i] = scale; |
| 6593 | } |
| 6594 | } |
| 6595 | } else if (track_type == Animation::TYPE_POSITION_3D) { |
| 6596 | if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 6597 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6598 | p_track.position_track.times.clear(); |
| 6599 | p_track.position_track.values.clear(); |
| 6600 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6601 | const double increment = 1.0 / BAKE_FPS; |
| 6602 | double time = 0.0; |
| 6603 | bool last = false; |
| 6604 | while (true) { |
| 6605 | Vector3 scale; |
| 6606 | Error err = p_animation->try_position_track_interpolate(p_track_i, time, &scale); |
| 6607 | ERR_CONTINUE(err != OK); |
| 6608 | p_track.position_track.values.push_back(scale); |
| 6609 | p_track.position_track.times.push_back(time); |
| 6610 | if (last) { |
| 6611 | break; |
| 6612 | } |
| 6613 | time += increment; |
| 6614 | if (time >= anim_end) { |
| 6615 | last = true; |
| 6616 | time = anim_end; |
| 6617 | } |
| 6618 | } |
| 6619 | } else { |
| 6620 | p_track.position_track.times = times; |
| 6621 | p_track.position_track.values.resize(key_count); |
| 6622 | p_track.position_track.interpolation = gltf_interpolation; |
| 6623 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6624 | Vector3 position; |
| 6625 | Error err = p_animation->position_track_get_key(p_track_i, key_i, &position); |
| 6626 | ERR_CONTINUE(err != OK); |
| 6627 | p_track.position_track.values.write[key_i] = position; |
| 6628 | } |
| 6629 | } |
| 6630 | } else if (track_type == Animation::TYPE_ROTATION_3D) { |
| 6631 | if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 6632 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6633 | p_track.rotation_track.times.clear(); |
| 6634 | p_track.rotation_track.values.clear(); |
| 6635 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6636 | const double increment = 1.0 / BAKE_FPS; |
| 6637 | double time = 0.0; |
| 6638 | bool last = false; |
| 6639 | while (true) { |
| 6640 | Quaternion rotation; |
| 6641 | Error err = p_animation->try_rotation_track_interpolate(p_track_i, time, &rotation); |
| 6642 | ERR_CONTINUE(err != OK); |
| 6643 | p_track.rotation_track.values.push_back(rotation); |
| 6644 | p_track.rotation_track.times.push_back(time); |
| 6645 | if (last) { |
| 6646 | break; |
| 6647 | } |
| 6648 | time += increment; |
| 6649 | if (time >= anim_end) { |
| 6650 | last = true; |
| 6651 | time = anim_end; |
| 6652 | } |
| 6653 | } |
| 6654 | } else { |
| 6655 | p_track.rotation_track.times = times; |
| 6656 | p_track.rotation_track.values.resize(key_count); |
| 6657 | p_track.rotation_track.interpolation = gltf_interpolation; |
| 6658 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6659 | Quaternion rotation; |
| 6660 | Error err = p_animation->rotation_track_get_key(p_track_i, key_i, &rotation); |
| 6661 | ERR_CONTINUE(err != OK); |
| 6662 | p_track.rotation_track.values.write[key_i] = rotation; |
| 6663 | } |
| 6664 | } |
| 6665 | } else if (track_type == Animation::TYPE_VALUE) { |
| 6666 | if (path.contains(":position" )) { |
| 6667 | p_track.position_track.interpolation = gltf_interpolation; |
| 6668 | p_track.position_track.times = times; |
| 6669 | p_track.position_track.values.resize(key_count); |
| 6670 | |
| 6671 | if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 6672 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6673 | p_track.position_track.times.clear(); |
| 6674 | p_track.position_track.values.clear(); |
| 6675 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6676 | const double increment = 1.0 / BAKE_FPS; |
| 6677 | double time = 0.0; |
| 6678 | bool last = false; |
| 6679 | while (true) { |
| 6680 | Vector3 position; |
| 6681 | Error err = p_animation->try_position_track_interpolate(p_track_i, time, &position); |
| 6682 | ERR_CONTINUE(err != OK); |
| 6683 | p_track.position_track.values.push_back(position); |
| 6684 | p_track.position_track.times.push_back(time); |
| 6685 | if (last) { |
| 6686 | break; |
| 6687 | } |
| 6688 | time += increment; |
| 6689 | if (time >= anim_end) { |
| 6690 | last = true; |
| 6691 | time = anim_end; |
| 6692 | } |
| 6693 | } |
| 6694 | } else { |
| 6695 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6696 | Vector3 position = p_animation->track_get_key_value(p_track_i, key_i); |
| 6697 | p_track.position_track.values.write[key_i] = position; |
| 6698 | } |
| 6699 | } |
| 6700 | } else if (path.contains(":rotation" )) { |
| 6701 | p_track.rotation_track.interpolation = gltf_interpolation; |
| 6702 | p_track.rotation_track.times = times; |
| 6703 | p_track.rotation_track.values.resize(key_count); |
| 6704 | if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 6705 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6706 | p_track.rotation_track.times.clear(); |
| 6707 | p_track.rotation_track.values.clear(); |
| 6708 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6709 | const double increment = 1.0 / BAKE_FPS; |
| 6710 | double time = 0.0; |
| 6711 | bool last = false; |
| 6712 | while (true) { |
| 6713 | Quaternion rotation; |
| 6714 | Error err = p_animation->try_rotation_track_interpolate(p_track_i, time, &rotation); |
| 6715 | ERR_CONTINUE(err != OK); |
| 6716 | p_track.rotation_track.values.push_back(rotation); |
| 6717 | p_track.rotation_track.times.push_back(time); |
| 6718 | if (last) { |
| 6719 | break; |
| 6720 | } |
| 6721 | time += increment; |
| 6722 | if (time >= anim_end) { |
| 6723 | last = true; |
| 6724 | time = anim_end; |
| 6725 | } |
| 6726 | } |
| 6727 | } else { |
| 6728 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6729 | Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i); |
| 6730 | p_track.rotation_track.values.write[key_i] = Quaternion::from_euler(rotation_radian); |
| 6731 | } |
| 6732 | } |
| 6733 | } else if (path.contains(":scale" )) { |
| 6734 | p_track.scale_track.times = times; |
| 6735 | p_track.scale_track.interpolation = gltf_interpolation; |
| 6736 | |
| 6737 | p_track.scale_track.values.resize(key_count); |
| 6738 | p_track.scale_track.interpolation = gltf_interpolation; |
| 6739 | |
| 6740 | if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { |
| 6741 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6742 | p_track.scale_track.times.clear(); |
| 6743 | p_track.scale_track.values.clear(); |
| 6744 | // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. |
| 6745 | const double increment = 1.0 / BAKE_FPS; |
| 6746 | double time = 0.0; |
| 6747 | bool last = false; |
| 6748 | while (true) { |
| 6749 | Vector3 scale; |
| 6750 | Error err = p_animation->try_scale_track_interpolate(p_track_i, time, &scale); |
| 6751 | ERR_CONTINUE(err != OK); |
| 6752 | p_track.scale_track.values.push_back(scale); |
| 6753 | p_track.scale_track.times.push_back(time); |
| 6754 | if (last) { |
| 6755 | break; |
| 6756 | } |
| 6757 | time += increment; |
| 6758 | if (time >= anim_end) { |
| 6759 | last = true; |
| 6760 | time = anim_end; |
| 6761 | } |
| 6762 | } |
| 6763 | } else { |
| 6764 | for (int32_t key_i = 0; key_i < key_count; key_i++) { |
| 6765 | Vector3 scale_track = p_animation->track_get_key_value(p_track_i, key_i); |
| 6766 | p_track.scale_track.values.write[key_i] = scale_track; |
| 6767 | } |
| 6768 | } |
| 6769 | } |
| 6770 | } else if (track_type == Animation::TYPE_BEZIER) { |
| 6771 | const int32_t keys = anim_end * BAKE_FPS; |
| 6772 | if (path.contains(":scale" )) { |
| 6773 | if (!p_track.scale_track.times.size()) { |
| 6774 | p_track.scale_track.interpolation = gltf_interpolation; |
| 6775 | Vector<real_t> new_times; |
| 6776 | new_times.resize(keys); |
| 6777 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6778 | new_times.write[key_i] = key_i / BAKE_FPS; |
| 6779 | } |
| 6780 | p_track.scale_track.times = new_times; |
| 6781 | |
| 6782 | p_track.scale_track.values.resize(keys); |
| 6783 | |
| 6784 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6785 | p_track.scale_track.values.write[key_i] = Vector3(1.0f, 1.0f, 1.0f); |
| 6786 | } |
| 6787 | |
| 6788 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6789 | Vector3 bezier_track = p_track.scale_track.values[key_i]; |
| 6790 | if (path.contains(":scale:x" )) { |
| 6791 | bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6792 | } else if (path.contains(":scale:y" )) { |
| 6793 | bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6794 | } else if (path.contains(":scale:z" )) { |
| 6795 | bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6796 | } |
| 6797 | p_track.scale_track.values.write[key_i] = bezier_track; |
| 6798 | } |
| 6799 | } |
| 6800 | } else if (path.contains(":position" )) { |
| 6801 | if (!p_track.position_track.times.size()) { |
| 6802 | p_track.position_track.interpolation = gltf_interpolation; |
| 6803 | Vector<real_t> new_times; |
| 6804 | new_times.resize(keys); |
| 6805 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6806 | new_times.write[key_i] = key_i / BAKE_FPS; |
| 6807 | } |
| 6808 | p_track.position_track.times = new_times; |
| 6809 | |
| 6810 | p_track.position_track.values.resize(keys); |
| 6811 | } |
| 6812 | |
| 6813 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6814 | Vector3 bezier_track = p_track.position_track.values[key_i]; |
| 6815 | if (path.contains(":position:x" )) { |
| 6816 | bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6817 | } else if (path.contains(":position:y" )) { |
| 6818 | bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6819 | } else if (path.contains(":position:z" )) { |
| 6820 | bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6821 | } |
| 6822 | p_track.position_track.values.write[key_i] = bezier_track; |
| 6823 | } |
| 6824 | } else if (path.contains(":rotation" )) { |
| 6825 | if (!p_track.rotation_track.times.size()) { |
| 6826 | p_track.rotation_track.interpolation = gltf_interpolation; |
| 6827 | Vector<real_t> new_times; |
| 6828 | new_times.resize(keys); |
| 6829 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6830 | new_times.write[key_i] = key_i / BAKE_FPS; |
| 6831 | } |
| 6832 | p_track.rotation_track.times = new_times; |
| 6833 | |
| 6834 | p_track.rotation_track.values.resize(keys); |
| 6835 | } |
| 6836 | for (int32_t key_i = 0; key_i < keys; key_i++) { |
| 6837 | Quaternion bezier_track = p_track.rotation_track.values[key_i]; |
| 6838 | if (path.contains(":rotation:x" )) { |
| 6839 | bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6840 | } else if (path.contains(":rotation:y" )) { |
| 6841 | bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6842 | } else if (path.contains(":rotation:z" )) { |
| 6843 | bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6844 | } else if (path.contains(":rotation:w" )) { |
| 6845 | bezier_track.w = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); |
| 6846 | } |
| 6847 | p_track.rotation_track.values.write[key_i] = bezier_track; |
| 6848 | } |
| 6849 | } |
| 6850 | } |
| 6851 | return p_track; |
| 6852 | } |
| 6853 | |
| 6854 | void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name) { |
| 6855 | Ref<Animation> animation = p_animation_player->get_animation(p_animation_track_name); |
| 6856 | Ref<GLTFAnimation> gltf_animation; |
| 6857 | gltf_animation.instantiate(); |
| 6858 | gltf_animation->set_name(_gen_unique_name(p_state, p_animation_track_name)); |
| 6859 | for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) { |
| 6860 | if (!animation->track_is_enabled(track_i)) { |
| 6861 | continue; |
| 6862 | } |
| 6863 | String final_track_path = animation->track_get_path(track_i); |
| 6864 | Node *animation_base_node = p_animation_player->get_parent(); |
| 6865 | ERR_CONTINUE_MSG(!animation_base_node, "Cannot get the parent of the animation player." ); |
| 6866 | if (String(final_track_path).contains(":position" )) { |
| 6867 | const Vector<String> node_suffix = String(final_track_path).split(":position" ); |
| 6868 | const NodePath path = node_suffix[0]; |
| 6869 | const Node *node = animation_base_node->get_node_or_null(path); |
| 6870 | ERR_CONTINUE_MSG(!node, "Cannot get the node from a position path." ); |
| 6871 | for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : p_state->scene_nodes) { |
| 6872 | if (position_scene_node_i.value == node) { |
| 6873 | GLTFNodeIndex node_index = position_scene_node_i.key; |
| 6874 | HashMap<int, GLTFAnimation::Track>::Iterator position_track_i = gltf_animation->get_tracks().find(node_index); |
| 6875 | GLTFAnimation::Track track; |
| 6876 | if (position_track_i) { |
| 6877 | track = position_track_i->value; |
| 6878 | } |
| 6879 | track = _convert_animation_track(p_state, track, animation, track_i, node_index); |
| 6880 | gltf_animation->get_tracks().insert(node_index, track); |
| 6881 | } |
| 6882 | } |
| 6883 | } else if (String(final_track_path).contains(":rotation_degrees" )) { |
| 6884 | const Vector<String> node_suffix = String(final_track_path).split(":rotation_degrees" ); |
| 6885 | const NodePath path = node_suffix[0]; |
| 6886 | const Node *node = animation_base_node->get_node_or_null(path); |
| 6887 | ERR_CONTINUE_MSG(!node, "Cannot get the node from a rotation degrees path." ); |
| 6888 | for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : p_state->scene_nodes) { |
| 6889 | if (rotation_degree_scene_node_i.value == node) { |
| 6890 | GLTFNodeIndex node_index = rotation_degree_scene_node_i.key; |
| 6891 | HashMap<int, GLTFAnimation::Track>::Iterator rotation_degree_track_i = gltf_animation->get_tracks().find(node_index); |
| 6892 | GLTFAnimation::Track track; |
| 6893 | if (rotation_degree_track_i) { |
| 6894 | track = rotation_degree_track_i->value; |
| 6895 | } |
| 6896 | track = _convert_animation_track(p_state, track, animation, track_i, node_index); |
| 6897 | gltf_animation->get_tracks().insert(node_index, track); |
| 6898 | } |
| 6899 | } |
| 6900 | } else if (String(final_track_path).contains(":scale" )) { |
| 6901 | const Vector<String> node_suffix = String(final_track_path).split(":scale" ); |
| 6902 | const NodePath path = node_suffix[0]; |
| 6903 | const Node *node = animation_base_node->get_node_or_null(path); |
| 6904 | ERR_CONTINUE_MSG(!node, "Cannot get the node from a scale path." ); |
| 6905 | for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : p_state->scene_nodes) { |
| 6906 | if (scale_scene_node_i.value == node) { |
| 6907 | GLTFNodeIndex node_index = scale_scene_node_i.key; |
| 6908 | HashMap<int, GLTFAnimation::Track>::Iterator scale_track_i = gltf_animation->get_tracks().find(node_index); |
| 6909 | GLTFAnimation::Track track; |
| 6910 | if (scale_track_i) { |
| 6911 | track = scale_track_i->value; |
| 6912 | } |
| 6913 | track = _convert_animation_track(p_state, track, animation, track_i, node_index); |
| 6914 | gltf_animation->get_tracks().insert(node_index, track); |
| 6915 | } |
| 6916 | } |
| 6917 | } else if (String(final_track_path).contains(":transform" )) { |
| 6918 | const Vector<String> node_suffix = String(final_track_path).split(":transform" ); |
| 6919 | const NodePath path = node_suffix[0]; |
| 6920 | const Node *node = animation_base_node->get_node_or_null(path); |
| 6921 | ERR_CONTINUE_MSG(!node, "Cannot get the node from a transform path." ); |
| 6922 | for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : p_state->scene_nodes) { |
| 6923 | if (transform_track_i.value == node) { |
| 6924 | GLTFAnimation::Track track; |
| 6925 | track = _convert_animation_track(p_state, track, animation, track_i, transform_track_i.key); |
| 6926 | gltf_animation->get_tracks().insert(transform_track_i.key, track); |
| 6927 | } |
| 6928 | } |
| 6929 | } else if (String(final_track_path).contains(":" ) && animation->track_get_type(track_i) == Animation::TYPE_BLEND_SHAPE) { |
| 6930 | const Vector<String> node_suffix = String(final_track_path).split(":" ); |
| 6931 | const NodePath path = node_suffix[0]; |
| 6932 | const String suffix = node_suffix[1]; |
| 6933 | Node *node = animation_base_node->get_node_or_null(path); |
| 6934 | ERR_CONTINUE_MSG(!node, "Cannot get the node from a blend shape path." ); |
| 6935 | MeshInstance3D *mi = cast_to<MeshInstance3D>(node); |
| 6936 | if (!mi) { |
| 6937 | continue; |
| 6938 | } |
| 6939 | Ref<Mesh> mesh = mi->get_mesh(); |
| 6940 | ERR_CONTINUE(mesh.is_null()); |
| 6941 | int32_t mesh_index = -1; |
| 6942 | for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : p_state->scene_nodes) { |
| 6943 | if (mesh_track_i.value == node) { |
| 6944 | mesh_index = mesh_track_i.key; |
| 6945 | } |
| 6946 | } |
| 6947 | ERR_CONTINUE(mesh_index == -1); |
| 6948 | HashMap<int, GLTFAnimation::Track> &tracks = gltf_animation->get_tracks(); |
| 6949 | GLTFAnimation::Track track = gltf_animation->get_tracks().has(mesh_index) ? gltf_animation->get_tracks()[mesh_index] : GLTFAnimation::Track(); |
| 6950 | if (!tracks.has(mesh_index)) { |
| 6951 | for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) { |
| 6952 | String shape_name = mesh->get_blend_shape_name(shape_i); |
| 6953 | NodePath shape_path = String(path) + ":" + shape_name; |
| 6954 | int32_t shape_track_i = animation->find_track(shape_path, Animation::TYPE_BLEND_SHAPE); |
| 6955 | if (shape_track_i == -1) { |
| 6956 | GLTFAnimation::Channel<real_t> weight; |
| 6957 | weight.interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6958 | weight.times.push_back(0.0f); |
| 6959 | weight.times.push_back(0.0f); |
| 6960 | weight.values.push_back(0.0f); |
| 6961 | weight.values.push_back(0.0f); |
| 6962 | track.weight_tracks.push_back(weight); |
| 6963 | continue; |
| 6964 | } |
| 6965 | Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i); |
| 6966 | GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6967 | if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) { |
| 6968 | gltf_interpolation = GLTFAnimation::INTERP_LINEAR; |
| 6969 | } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) { |
| 6970 | gltf_interpolation = GLTFAnimation::INTERP_STEP; |
| 6971 | } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) { |
| 6972 | gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE; |
| 6973 | } |
| 6974 | int32_t key_count = animation->track_get_key_count(shape_track_i); |
| 6975 | GLTFAnimation::Channel<real_t> weight; |
| 6976 | weight.interpolation = gltf_interpolation; |
| 6977 | weight.times.resize(key_count); |
| 6978 | for (int32_t time_i = 0; time_i < key_count; time_i++) { |
| 6979 | weight.times.write[time_i] = animation->track_get_key_time(shape_track_i, time_i); |
| 6980 | } |
| 6981 | weight.values.resize(key_count); |
| 6982 | for (int32_t value_i = 0; value_i < key_count; value_i++) { |
| 6983 | weight.values.write[value_i] = animation->track_get_key_value(shape_track_i, value_i); |
| 6984 | } |
| 6985 | track.weight_tracks.push_back(weight); |
| 6986 | } |
| 6987 | tracks[mesh_index] = track; |
| 6988 | } |
| 6989 | } else if (String(final_track_path).contains(":" )) { |
| 6990 | //Process skeleton |
| 6991 | const Vector<String> node_suffix = String(final_track_path).split(":" ); |
| 6992 | const String node = node_suffix[0]; |
| 6993 | const NodePath node_path = node; |
| 6994 | const String suffix = node_suffix[1]; |
| 6995 | Node *godot_node = animation_base_node->get_node_or_null(node_path); |
| 6996 | if (!godot_node) { |
| 6997 | continue; |
| 6998 | } |
| 6999 | Skeleton3D *skeleton = cast_to<Skeleton3D>(animation_base_node->get_node_or_null(node)); |
| 7000 | if (!skeleton) { |
| 7001 | continue; |
| 7002 | } |
| 7003 | GLTFSkeletonIndex skeleton_gltf_i = -1; |
| 7004 | for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < p_state->skeletons.size(); skeleton_i++) { |
| 7005 | if (p_state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) { |
| 7006 | skeleton = p_state->skeletons[skeleton_i]->godot_skeleton; |
| 7007 | skeleton_gltf_i = skeleton_i; |
| 7008 | ERR_CONTINUE(!skeleton); |
| 7009 | Ref<GLTFSkeleton> skeleton_gltf = p_state->skeletons[skeleton_gltf_i]; |
| 7010 | int32_t bone = skeleton->find_bone(suffix); |
| 7011 | ERR_CONTINUE_MSG(bone == -1, vformat("Cannot find the bone %s." , suffix)); |
| 7012 | if (!skeleton_gltf->godot_bone_node.has(bone)) { |
| 7013 | continue; |
| 7014 | } |
| 7015 | GLTFNodeIndex node_i = skeleton_gltf->godot_bone_node[bone]; |
| 7016 | HashMap<int, GLTFAnimation::Track>::Iterator property_track_i = gltf_animation->get_tracks().find(node_i); |
| 7017 | GLTFAnimation::Track track; |
| 7018 | if (property_track_i) { |
| 7019 | track = property_track_i->value; |
| 7020 | } |
| 7021 | track = _convert_animation_track(p_state, track, animation, track_i, node_i); |
| 7022 | gltf_animation->get_tracks()[node_i] = track; |
| 7023 | } |
| 7024 | } |
| 7025 | } else if (!String(final_track_path).contains(":" )) { |
| 7026 | ERR_CONTINUE(!animation_base_node); |
| 7027 | Node *godot_node = animation_base_node->get_node_or_null(final_track_path); |
| 7028 | ERR_CONTINUE_MSG(!godot_node, vformat("Cannot get the node from a skeleton path %s." , final_track_path)); |
| 7029 | for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : p_state->scene_nodes) { |
| 7030 | if (scene_node_i.value == godot_node) { |
| 7031 | GLTFNodeIndex node_i = scene_node_i.key; |
| 7032 | HashMap<int, GLTFAnimation::Track>::Iterator node_track_i = gltf_animation->get_tracks().find(node_i); |
| 7033 | GLTFAnimation::Track track; |
| 7034 | if (node_track_i) { |
| 7035 | track = node_track_i->value; |
| 7036 | } |
| 7037 | track = _convert_animation_track(p_state, track, animation, track_i, node_i); |
| 7038 | gltf_animation->get_tracks()[node_i] = track; |
| 7039 | break; |
| 7040 | } |
| 7041 | } |
| 7042 | } |
| 7043 | } |
| 7044 | if (gltf_animation->get_tracks().size()) { |
| 7045 | p_state->animations.push_back(gltf_animation); |
| 7046 | } |
| 7047 | } |
| 7048 | |
| 7049 | Error GLTFDocument::_parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file) { |
| 7050 | Error err; |
| 7051 | if (p_file.is_null()) { |
| 7052 | return FAILED; |
| 7053 | } |
| 7054 | p_file->seek(0); |
| 7055 | uint32_t magic = p_file->get_32(); |
| 7056 | if (magic == 0x46546C67) { |
| 7057 | //binary file |
| 7058 | //text file |
| 7059 | p_file->seek(0); |
| 7060 | err = _parse_glb(p_file, p_state); |
| 7061 | if (err != OK) { |
| 7062 | return err; |
| 7063 | } |
| 7064 | } else { |
| 7065 | p_file->seek(0); |
| 7066 | String text = p_file->get_as_utf8_string(); |
| 7067 | JSON json; |
| 7068 | err = json.parse(text); |
| 7069 | if (err != OK) { |
| 7070 | _err_print_error("" , "" , json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); |
| 7071 | } |
| 7072 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7073 | p_state->json = json.get_data(); |
| 7074 | } |
| 7075 | |
| 7076 | err = _parse_asset_header(p_state); |
| 7077 | ERR_FAIL_COND_V(err != OK, err); |
| 7078 | |
| 7079 | document_extensions.clear(); |
| 7080 | for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { |
| 7081 | ERR_CONTINUE(ext.is_null()); |
| 7082 | err = ext->import_preflight(p_state, p_state->json["extensionsUsed" ]); |
| 7083 | if (err == OK) { |
| 7084 | document_extensions.push_back(ext); |
| 7085 | } |
| 7086 | } |
| 7087 | |
| 7088 | err = _parse_gltf_state(p_state, p_path); |
| 7089 | ERR_FAIL_COND_V(err != OK, err); |
| 7090 | |
| 7091 | return OK; |
| 7092 | } |
| 7093 | |
| 7094 | Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { |
| 7095 | Dictionary texture_transform; |
| 7096 | bool is_offset = p_offset != Vector2(0.0, 0.0); |
| 7097 | if (is_offset) { |
| 7098 | Array offset; |
| 7099 | offset.resize(2); |
| 7100 | offset[0] = p_offset.x; |
| 7101 | offset[1] = p_offset.y; |
| 7102 | texture_transform["offset" ] = offset; |
| 7103 | } |
| 7104 | bool is_scaled = p_scale != Vector2(1.0, 1.0); |
| 7105 | if (is_scaled) { |
| 7106 | Array scale; |
| 7107 | scale.resize(2); |
| 7108 | scale[0] = p_scale.x; |
| 7109 | scale[1] = p_scale.y; |
| 7110 | texture_transform["scale" ] = scale; |
| 7111 | } |
| 7112 | Dictionary extension; |
| 7113 | // Note: Godot doesn't support texture rotation. |
| 7114 | if (is_offset || is_scaled) { |
| 7115 | extension["KHR_texture_transform" ] = texture_transform; |
| 7116 | } |
| 7117 | return extension; |
| 7118 | } |
| 7119 | |
| 7120 | Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { |
| 7121 | ERR_FAIL_NULL_V(p_material, Dictionary()); |
| 7122 | Vector3 offset = p_material->get_uv1_offset(); |
| 7123 | Vector3 scale = p_material->get_uv1_scale(); |
| 7124 | return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); |
| 7125 | } |
| 7126 | |
| 7127 | Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { |
| 7128 | ERR_FAIL_NULL_V(p_material, Dictionary()); |
| 7129 | Vector3 offset = p_material->get_uv2_offset(); |
| 7130 | Vector3 scale = p_material->get_uv2_scale(); |
| 7131 | return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); |
| 7132 | } |
| 7133 | |
| 7134 | Error GLTFDocument::(Ref<GLTFState> p_state) { |
| 7135 | const String version = "2.0" ; |
| 7136 | p_state->major_version = version.get_slice("." , 0).to_int(); |
| 7137 | p_state->minor_version = version.get_slice("." , 1).to_int(); |
| 7138 | Dictionary asset; |
| 7139 | asset["version" ] = version; |
| 7140 | if (!p_state->copyright.is_empty()) { |
| 7141 | asset["copyright" ] = p_state->copyright; |
| 7142 | } |
| 7143 | String hash = String(VERSION_HASH); |
| 7144 | asset["generator" ] = String(VERSION_FULL_NAME) + String("@" ) + (hash.is_empty() ? String("unknown" ) : hash); |
| 7145 | p_state->json["asset" ] = asset; |
| 7146 | ERR_FAIL_COND_V(!asset.has("version" ), Error::FAILED); |
| 7147 | ERR_FAIL_COND_V(!p_state->json.has("asset" ), Error::FAILED); |
| 7148 | return OK; |
| 7149 | } |
| 7150 | |
| 7151 | Error GLTFDocument::_serialize_file(Ref<GLTFState> p_state, const String p_path) { |
| 7152 | Error err = FAILED; |
| 7153 | if (p_path.to_lower().ends_with("glb" )) { |
| 7154 | err = _encode_buffer_glb(p_state, p_path); |
| 7155 | ERR_FAIL_COND_V(err != OK, err); |
| 7156 | Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); |
| 7157 | ERR_FAIL_COND_V(file.is_null(), FAILED); |
| 7158 | |
| 7159 | String json = Variant(p_state->json).to_json_string(); |
| 7160 | |
| 7161 | const uint32_t magic = 0x46546C67; // GLTF |
| 7162 | const int32_t = 12; |
| 7163 | const int32_t = 8; |
| 7164 | CharString cs = json.utf8(); |
| 7165 | const uint32_t text_data_length = cs.length(); |
| 7166 | const uint32_t text_chunk_length = ((text_data_length + 3) & (~3)); |
| 7167 | const uint32_t text_chunk_type = 0x4E4F534A; //JSON |
| 7168 | |
| 7169 | uint32_t binary_data_length = 0; |
| 7170 | if (p_state->buffers.size()) { |
| 7171 | binary_data_length = p_state->buffers[0].size(); |
| 7172 | } |
| 7173 | const uint32_t binary_chunk_length = ((binary_data_length + 3) & (~3)); |
| 7174 | const uint32_t binary_chunk_type = 0x004E4942; //BIN |
| 7175 | |
| 7176 | file->create(FileAccess::ACCESS_RESOURCES); |
| 7177 | file->store_32(magic); |
| 7178 | file->store_32(p_state->major_version); // version |
| 7179 | file->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length |
| 7180 | file->store_32(text_chunk_length); |
| 7181 | file->store_32(text_chunk_type); |
| 7182 | file->store_buffer((uint8_t *)&cs[0], cs.length()); |
| 7183 | for (uint32_t pad_i = text_data_length; pad_i < text_chunk_length; pad_i++) { |
| 7184 | file->store_8(' '); |
| 7185 | } |
| 7186 | if (binary_chunk_length) { |
| 7187 | file->store_32(binary_chunk_length); |
| 7188 | file->store_32(binary_chunk_type); |
| 7189 | file->store_buffer(p_state->buffers[0].ptr(), binary_data_length); |
| 7190 | } |
| 7191 | for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { |
| 7192 | file->store_8(0); |
| 7193 | } |
| 7194 | } else { |
| 7195 | err = _encode_buffer_bins(p_state, p_path); |
| 7196 | ERR_FAIL_COND_V(err != OK, err); |
| 7197 | Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); |
| 7198 | ERR_FAIL_COND_V(file.is_null(), FAILED); |
| 7199 | |
| 7200 | file->create(FileAccess::ACCESS_RESOURCES); |
| 7201 | String json = Variant(p_state->json).to_json_string(); |
| 7202 | file->store_string(json); |
| 7203 | } |
| 7204 | return err; |
| 7205 | } |
| 7206 | |
| 7207 | void GLTFDocument::_bind_methods() { |
| 7208 | ClassDB::bind_method(D_METHOD("append_from_file" , "path" , "state" , "flags" , "base_path" ), |
| 7209 | &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(String())); |
| 7210 | ClassDB::bind_method(D_METHOD("append_from_buffer" , "bytes" , "base_path" , "state" , "flags" ), |
| 7211 | &GLTFDocument::append_from_buffer, DEFVAL(0)); |
| 7212 | ClassDB::bind_method(D_METHOD("append_from_scene" , "node" , "state" , "flags" ), |
| 7213 | &GLTFDocument::append_from_scene, DEFVAL(0)); |
| 7214 | ClassDB::bind_method(D_METHOD("generate_scene" , "state" , "bake_fps" , "trimming" , "remove_immutable_tracks" ), |
| 7215 | &GLTFDocument::generate_scene, DEFVAL(30), DEFVAL(false), DEFVAL(true)); |
| 7216 | ClassDB::bind_method(D_METHOD("generate_buffer" , "state" ), |
| 7217 | &GLTFDocument::generate_buffer); |
| 7218 | ClassDB::bind_method(D_METHOD("write_to_filesystem" , "state" , "path" ), |
| 7219 | &GLTFDocument::write_to_filesystem); |
| 7220 | |
| 7221 | ClassDB::bind_method(D_METHOD("set_image_format" , "image_format" ), &GLTFDocument::set_image_format); |
| 7222 | ClassDB::bind_method(D_METHOD("get_image_format" ), &GLTFDocument::get_image_format); |
| 7223 | ClassDB::bind_method(D_METHOD("set_lossy_quality" , "lossy_quality" ), &GLTFDocument::set_lossy_quality); |
| 7224 | ClassDB::bind_method(D_METHOD("get_lossy_quality" ), &GLTFDocument::get_lossy_quality); |
| 7225 | |
| 7226 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_format" ), "set_image_format" , "get_image_format" ); |
| 7227 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lossy_quality" ), "set_lossy_quality" , "get_lossy_quality" ); |
| 7228 | |
| 7229 | ClassDB::bind_static_method("GLTFDocument" , D_METHOD("register_gltf_document_extension" , "extension" , "first_priority" ), |
| 7230 | &GLTFDocument::register_gltf_document_extension, DEFVAL(false)); |
| 7231 | ClassDB::bind_static_method("GLTFDocument" , D_METHOD("unregister_gltf_document_extension" , "extension" ), |
| 7232 | &GLTFDocument::unregister_gltf_document_extension); |
| 7233 | } |
| 7234 | |
| 7235 | void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> p_state) { |
| 7236 | // build the hierarchy |
| 7237 | for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { |
| 7238 | for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) { |
| 7239 | GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j]; |
| 7240 | ERR_FAIL_INDEX(child_i, p_state->nodes.size()); |
| 7241 | if (p_state->nodes.write[child_i]->parent != -1) { |
| 7242 | continue; |
| 7243 | } |
| 7244 | p_state->nodes.write[child_i]->parent = node_i; |
| 7245 | } |
| 7246 | } |
| 7247 | } |
| 7248 | |
| 7249 | Vector<Ref<GLTFDocumentExtension>> GLTFDocument::all_document_extensions; |
| 7250 | |
| 7251 | void GLTFDocument::register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority) { |
| 7252 | if (all_document_extensions.find(p_extension) == -1) { |
| 7253 | if (p_first_priority) { |
| 7254 | all_document_extensions.insert(0, p_extension); |
| 7255 | } else { |
| 7256 | all_document_extensions.push_back(p_extension); |
| 7257 | } |
| 7258 | } |
| 7259 | } |
| 7260 | |
| 7261 | void GLTFDocument::unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension) { |
| 7262 | all_document_extensions.erase(p_extension); |
| 7263 | } |
| 7264 | |
| 7265 | void GLTFDocument::unregister_all_gltf_document_extensions() { |
| 7266 | all_document_extensions.clear(); |
| 7267 | } |
| 7268 | |
| 7269 | PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) { |
| 7270 | Error err = _encode_buffer_glb(p_state, "" ); |
| 7271 | if (r_err) { |
| 7272 | *r_err = err; |
| 7273 | } |
| 7274 | ERR_FAIL_COND_V(err != OK, PackedByteArray()); |
| 7275 | String json = Variant(p_state->json).to_json_string(); |
| 7276 | |
| 7277 | const uint32_t magic = 0x46546C67; // GLTF |
| 7278 | const int32_t = 12; |
| 7279 | const int32_t = 8; |
| 7280 | |
| 7281 | int32_t padding = (chunk_header_size + json.utf8().length()) % 4; |
| 7282 | json += String(" " ).repeat(padding); |
| 7283 | |
| 7284 | CharString cs = json.utf8(); |
| 7285 | const uint32_t text_chunk_length = cs.length(); |
| 7286 | |
| 7287 | const uint32_t text_chunk_type = 0x4E4F534A; //JSON |
| 7288 | int32_t binary_data_length = 0; |
| 7289 | if (p_state->buffers.size()) { |
| 7290 | binary_data_length = p_state->buffers[0].size(); |
| 7291 | } |
| 7292 | const int32_t binary_chunk_length = binary_data_length; |
| 7293 | const int32_t binary_chunk_type = 0x004E4942; //BIN |
| 7294 | |
| 7295 | Ref<StreamPeerBuffer> buffer; |
| 7296 | buffer.instantiate(); |
| 7297 | buffer->put_32(magic); |
| 7298 | buffer->put_32(p_state->major_version); // version |
| 7299 | buffer->put_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length |
| 7300 | buffer->put_32(text_chunk_length); |
| 7301 | buffer->put_32(text_chunk_type); |
| 7302 | buffer->put_data((uint8_t *)&cs[0], cs.length()); |
| 7303 | if (binary_chunk_length) { |
| 7304 | buffer->put_32(binary_chunk_length); |
| 7305 | buffer->put_32(binary_chunk_type); |
| 7306 | buffer->put_data(p_state->buffers[0].ptr(), binary_data_length); |
| 7307 | } |
| 7308 | return buffer->get_data_array(); |
| 7309 | } |
| 7310 | |
| 7311 | PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> p_state) { |
| 7312 | ERR_FAIL_NULL_V(p_state, PackedByteArray()); |
| 7313 | // For buffers, set the state filename to an empty string, but |
| 7314 | // don't touch the base path, in case the user set it manually. |
| 7315 | p_state->filename = "" ; |
| 7316 | Error err = _serialize(p_state); |
| 7317 | ERR_FAIL_COND_V(err != OK, PackedByteArray()); |
| 7318 | PackedByteArray bytes = _serialize_glb_buffer(p_state, &err); |
| 7319 | return bytes; |
| 7320 | } |
| 7321 | |
| 7322 | Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) { |
| 7323 | ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); |
| 7324 | p_state->base_path = p_path.get_base_dir(); |
| 7325 | p_state->filename = p_path.get_file(); |
| 7326 | Error err = _serialize(p_state); |
| 7327 | if (err != OK) { |
| 7328 | return err; |
| 7329 | } |
| 7330 | err = _serialize_file(p_state, p_path); |
| 7331 | if (err != OK) { |
| 7332 | return Error::FAILED; |
| 7333 | } |
| 7334 | return OK; |
| 7335 | } |
| 7336 | |
| 7337 | Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) { |
| 7338 | Node *single_root = memnew(Node3D); |
| 7339 | for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) { |
| 7340 | _generate_scene_node(p_state, p_state->root_nodes[root_i], single_root, single_root); |
| 7341 | } |
| 7342 | // Assign the scene name and single root name to each other |
| 7343 | // if one is missing, or do nothing if both are already set. |
| 7344 | if (unlikely(p_state->scene_name.is_empty())) { |
| 7345 | p_state->scene_name = single_root->get_name(); |
| 7346 | } else if (single_root->get_name() == StringName()) { |
| 7347 | single_root->set_name(_gen_unique_name(p_state, p_state->scene_name)); |
| 7348 | } |
| 7349 | return single_root; |
| 7350 | } |
| 7351 | |
| 7352 | Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming, bool p_remove_immutable_tracks) { |
| 7353 | ERR_FAIL_NULL_V(p_state, nullptr); |
| 7354 | ERR_FAIL_INDEX_V(0, p_state->root_nodes.size(), nullptr); |
| 7355 | Error err = OK; |
| 7356 | Node *root = _generate_scene_node_tree(p_state); |
| 7357 | ERR_FAIL_NULL_V(root, nullptr); |
| 7358 | _process_mesh_instances(p_state); |
| 7359 | if (p_state->get_create_animations() && p_state->animations.size()) { |
| 7360 | AnimationPlayer *ap = memnew(AnimationPlayer); |
| 7361 | root->add_child(ap, true); |
| 7362 | ap->set_owner(root); |
| 7363 | for (int i = 0; i < p_state->animations.size(); i++) { |
| 7364 | _import_animation(p_state, ap, i, p_bake_fps, p_trimming, p_remove_immutable_tracks); |
| 7365 | } |
| 7366 | } |
| 7367 | for (KeyValue<GLTFNodeIndex, Node *> E : p_state->scene_nodes) { |
| 7368 | ERR_CONTINUE(!E.value); |
| 7369 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 7370 | ERR_CONTINUE(ext.is_null()); |
| 7371 | ERR_CONTINUE(!p_state->json.has("nodes" )); |
| 7372 | Array nodes = p_state->json["nodes" ]; |
| 7373 | ERR_CONTINUE(E.key >= nodes.size()); |
| 7374 | ERR_CONTINUE(E.key < 0); |
| 7375 | Dictionary node_json = nodes[E.key]; |
| 7376 | Ref<GLTFNode> gltf_node = p_state->nodes[E.key]; |
| 7377 | err = ext->import_node(p_state, gltf_node, node_json, E.value); |
| 7378 | ERR_CONTINUE(err != OK); |
| 7379 | } |
| 7380 | } |
| 7381 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 7382 | ERR_CONTINUE(ext.is_null()); |
| 7383 | err = ext->import_post(p_state, root); |
| 7384 | ERR_CONTINUE(err != OK); |
| 7385 | } |
| 7386 | ERR_FAIL_NULL_V(root, nullptr); |
| 7387 | return root; |
| 7388 | } |
| 7389 | |
| 7390 | Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) { |
| 7391 | ERR_FAIL_COND_V(p_state.is_null(), FAILED); |
| 7392 | p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; |
| 7393 | p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; |
| 7394 | if (!p_state->buffers.size()) { |
| 7395 | p_state->buffers.push_back(Vector<uint8_t>()); |
| 7396 | } |
| 7397 | // Perform export preflight for document extensions. Only extensions that |
| 7398 | // return OK will be used for the rest of the export steps. |
| 7399 | document_extensions.clear(); |
| 7400 | for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { |
| 7401 | ERR_CONTINUE(ext.is_null()); |
| 7402 | Error err = ext->export_preflight(p_state, p_node); |
| 7403 | if (err == OK) { |
| 7404 | document_extensions.push_back(ext); |
| 7405 | } |
| 7406 | } |
| 7407 | // Add the root node(s) and their descendants to the state. |
| 7408 | _convert_scene_node(p_state, p_node, -1, -1); |
| 7409 | return OK; |
| 7410 | } |
| 7411 | |
| 7412 | Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags) { |
| 7413 | ERR_FAIL_COND_V(p_state.is_null(), FAILED); |
| 7414 | // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire |
| 7415 | Error err = FAILED; |
| 7416 | p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; |
| 7417 | p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; |
| 7418 | |
| 7419 | Ref<FileAccessMemory> file_access; |
| 7420 | file_access.instantiate(); |
| 7421 | file_access->open_custom(p_bytes.ptr(), p_bytes.size()); |
| 7422 | p_state->base_path = p_base_path.get_base_dir(); |
| 7423 | err = _parse(p_state, p_state->base_path, file_access); |
| 7424 | ERR_FAIL_COND_V(err != OK, err); |
| 7425 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 7426 | ERR_CONTINUE(ext.is_null()); |
| 7427 | err = ext->import_post_parse(p_state); |
| 7428 | ERR_FAIL_COND_V(err != OK, err); |
| 7429 | } |
| 7430 | return OK; |
| 7431 | } |
| 7432 | |
| 7433 | Error GLTFDocument::(Ref<GLTFState> p_state) { |
| 7434 | if (!p_state->json.has("asset" )) { |
| 7435 | return ERR_PARSE_ERROR; |
| 7436 | } |
| 7437 | Dictionary asset = p_state->json["asset" ]; |
| 7438 | if (!asset.has("version" )) { |
| 7439 | return ERR_PARSE_ERROR; |
| 7440 | } |
| 7441 | String version = asset["version" ]; |
| 7442 | p_state->major_version = version.get_slice("." , 0).to_int(); |
| 7443 | p_state->minor_version = version.get_slice("." , 1).to_int(); |
| 7444 | if (asset.has("copyright" )) { |
| 7445 | p_state->copyright = asset["copyright" ]; |
| 7446 | } |
| 7447 | return OK; |
| 7448 | } |
| 7449 | |
| 7450 | Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path) { |
| 7451 | Error err; |
| 7452 | |
| 7453 | /* PARSE EXTENSIONS */ |
| 7454 | err = _parse_gltf_extensions(p_state); |
| 7455 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7456 | |
| 7457 | /* PARSE SCENE */ |
| 7458 | err = _parse_scenes(p_state); |
| 7459 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7460 | |
| 7461 | /* PARSE NODES */ |
| 7462 | err = _parse_nodes(p_state); |
| 7463 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7464 | |
| 7465 | /* PARSE BUFFERS */ |
| 7466 | err = _parse_buffers(p_state, p_search_path); |
| 7467 | |
| 7468 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7469 | |
| 7470 | /* PARSE BUFFER VIEWS */ |
| 7471 | err = _parse_buffer_views(p_state); |
| 7472 | |
| 7473 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7474 | |
| 7475 | /* PARSE ACCESSORS */ |
| 7476 | err = _parse_accessors(p_state); |
| 7477 | |
| 7478 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7479 | |
| 7480 | if (!p_state->discard_meshes_and_materials) { |
| 7481 | /* PARSE IMAGES */ |
| 7482 | err = _parse_images(p_state, p_search_path); |
| 7483 | |
| 7484 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7485 | |
| 7486 | /* PARSE TEXTURE SAMPLERS */ |
| 7487 | err = _parse_texture_samplers(p_state); |
| 7488 | |
| 7489 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7490 | |
| 7491 | /* PARSE TEXTURES */ |
| 7492 | err = _parse_textures(p_state); |
| 7493 | |
| 7494 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7495 | |
| 7496 | /* PARSE TEXTURES */ |
| 7497 | err = _parse_materials(p_state); |
| 7498 | |
| 7499 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7500 | } |
| 7501 | |
| 7502 | /* PARSE SKINS */ |
| 7503 | err = _parse_skins(p_state); |
| 7504 | |
| 7505 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7506 | |
| 7507 | /* DETERMINE SKELETONS */ |
| 7508 | err = _determine_skeletons(p_state); |
| 7509 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7510 | |
| 7511 | /* CREATE SKELETONS */ |
| 7512 | err = _create_skeletons(p_state); |
| 7513 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7514 | |
| 7515 | /* CREATE SKINS */ |
| 7516 | err = _create_skins(p_state); |
| 7517 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7518 | |
| 7519 | /* PARSE MESHES (we have enough info now) */ |
| 7520 | err = _parse_meshes(p_state); |
| 7521 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7522 | |
| 7523 | /* PARSE LIGHTS */ |
| 7524 | err = _parse_lights(p_state); |
| 7525 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7526 | |
| 7527 | /* PARSE CAMERAS */ |
| 7528 | err = _parse_cameras(p_state); |
| 7529 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7530 | |
| 7531 | /* PARSE ANIMATIONS */ |
| 7532 | err = _parse_animations(p_state); |
| 7533 | ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); |
| 7534 | |
| 7535 | /* ASSIGN SCENE NAMES */ |
| 7536 | _assign_node_names(p_state); |
| 7537 | |
| 7538 | return OK; |
| 7539 | } |
| 7540 | |
| 7541 | Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags, String p_base_path) { |
| 7542 | // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire |
| 7543 | if (p_state == Ref<GLTFState>()) { |
| 7544 | p_state.instantiate(); |
| 7545 | } |
| 7546 | p_state->filename = p_path.get_file().get_basename(); |
| 7547 | p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; |
| 7548 | p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; |
| 7549 | Error err; |
| 7550 | Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); |
| 7551 | ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); |
| 7552 | ERR_FAIL_NULL_V(file, ERR_FILE_CANT_OPEN); |
| 7553 | String base_path = p_base_path; |
| 7554 | if (base_path.is_empty()) { |
| 7555 | base_path = p_path.get_base_dir(); |
| 7556 | } |
| 7557 | p_state->base_path = base_path; |
| 7558 | err = _parse(p_state, base_path, file); |
| 7559 | ERR_FAIL_COND_V(err != OK, err); |
| 7560 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 7561 | ERR_CONTINUE(ext.is_null()); |
| 7562 | err = ext->import_post_parse(p_state); |
| 7563 | ERR_FAIL_COND_V(err != OK, err); |
| 7564 | } |
| 7565 | return OK; |
| 7566 | } |
| 7567 | |
| 7568 | Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) { |
| 7569 | ERR_FAIL_NULL_V(p_state, ERR_PARSE_ERROR); |
| 7570 | if (p_state->json.has("extensionsUsed" )) { |
| 7571 | Vector<String> ext_array = p_state->json["extensionsUsed" ]; |
| 7572 | p_state->extensions_used = ext_array; |
| 7573 | } |
| 7574 | if (p_state->json.has("extensionsRequired" )) { |
| 7575 | Vector<String> ext_array = p_state->json["extensionsRequired" ]; |
| 7576 | p_state->extensions_required = ext_array; |
| 7577 | } |
| 7578 | HashSet<String> supported_extensions; |
| 7579 | supported_extensions.insert("KHR_lights_punctual" ); |
| 7580 | supported_extensions.insert("KHR_materials_pbrSpecularGlossiness" ); |
| 7581 | supported_extensions.insert("KHR_texture_transform" ); |
| 7582 | supported_extensions.insert("KHR_materials_unlit" ); |
| 7583 | supported_extensions.insert("KHR_materials_emissive_strength" ); |
| 7584 | for (Ref<GLTFDocumentExtension> ext : document_extensions) { |
| 7585 | ERR_CONTINUE(ext.is_null()); |
| 7586 | Vector<String> ext_supported_extensions = ext->get_supported_extensions(); |
| 7587 | for (int i = 0; i < ext_supported_extensions.size(); ++i) { |
| 7588 | supported_extensions.insert(ext_supported_extensions[i]); |
| 7589 | } |
| 7590 | } |
| 7591 | Error ret = OK; |
| 7592 | for (int i = 0; i < p_state->extensions_required.size(); i++) { |
| 7593 | if (!supported_extensions.has(p_state->extensions_required[i])) { |
| 7594 | ERR_PRINT("GLTF: Can't import file '" + p_state->filename + "', required extension '" + String(p_state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?" ); |
| 7595 | ret = ERR_UNAVAILABLE; |
| 7596 | } |
| 7597 | } |
| 7598 | return ret; |
| 7599 | } |
| 7600 | |