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