Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/fbx/fbx_document.cpp
10277 views
1
/**************************************************************************/
2
/* fbx_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 "fbx_document.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/crypto/crypto_core.h"
35
#include "core/io/config_file.h"
36
#include "core/io/file_access.h"
37
#include "core/io/file_access_memory.h"
38
#include "core/io/image.h"
39
#include "core/math/color.h"
40
#include "scene/3d/bone_attachment_3d.h"
41
#include "scene/3d/camera_3d.h"
42
#include "scene/3d/importer_mesh_instance_3d.h"
43
#include "scene/3d/light_3d.h"
44
#include "scene/resources/image_texture.h"
45
#include "scene/resources/material.h"
46
#include "scene/resources/portable_compressed_texture.h"
47
#include "scene/resources/surface_tool.h"
48
49
#include "modules/gltf/extensions/gltf_light.h"
50
#include "modules/gltf/gltf_defines.h"
51
#include "modules/gltf/skin_tool.h"
52
#include "modules/gltf/structures/gltf_animation.h"
53
#include "modules/gltf/structures/gltf_camera.h"
54
55
#ifdef TOOLS_ENABLED
56
#include "editor/file_system/editor_file_system.h"
57
#endif
58
59
// FIXME: Hardcoded to avoid editor dependency.
60
#define FBX_IMPORT_USE_NAMED_SKIN_BINDS 16
61
#define FBX_IMPORT_DISCARD_MESHES_AND_MATERIALS 32
62
#define FBX_IMPORT_FORCE_DISABLE_MESH_COMPRESSION 64
63
64
#include <ufbx.h>
65
66
static size_t _file_access_read_fn(void *user, void *data, size_t size) {
67
FileAccess *file = static_cast<FileAccess *>(user);
68
return (size_t)file->get_buffer((uint8_t *)data, (uint64_t)size);
69
}
70
71
static bool _file_access_skip_fn(void *user, size_t size) {
72
FileAccess *file = static_cast<FileAccess *>(user);
73
file->seek(file->get_position() + size);
74
return true;
75
}
76
77
static Vector2 _as_vec2(const ufbx_vec2 &p_vector) {
78
return Vector2(real_t(p_vector.x), real_t(p_vector.y));
79
}
80
81
static Color _as_color(const ufbx_vec4 &p_vector) {
82
return Color(real_t(p_vector.x), real_t(p_vector.y), real_t(p_vector.z), real_t(p_vector.w));
83
}
84
85
static Quaternion _as_quaternion(const ufbx_quat &p_quat) {
86
return Quaternion(real_t(p_quat.x), real_t(p_quat.y), real_t(p_quat.z), real_t(p_quat.w));
87
}
88
89
static Transform3D _as_transform(const ufbx_transform &p_xform) {
90
Transform3D result;
91
result.origin = FBXDocument::_as_vec3(p_xform.translation);
92
result.basis.set_quaternion_scale(_as_quaternion(p_xform.rotation), FBXDocument::_as_vec3(p_xform.scale));
93
return result;
94
}
95
96
static real_t _relative_error(const Vector3 &p_a, const Vector3 &p_b) {
97
return p_a.distance_to(p_b) / MAX(p_a.length(), p_b.length());
98
}
99
100
static Color _material_color(const ufbx_material_map &p_map) {
101
if (p_map.value_components == 1) {
102
float r = float(p_map.value_real);
103
return Color(r, r, r);
104
} else if (p_map.value_components == 3) {
105
float r = float(p_map.value_vec3.x);
106
float g = float(p_map.value_vec3.y);
107
float b = float(p_map.value_vec3.z);
108
return Color(r, g, b);
109
} else {
110
float r = float(p_map.value_vec4.x);
111
float g = float(p_map.value_vec4.y);
112
float b = float(p_map.value_vec4.z);
113
float a = float(p_map.value_vec4.z);
114
return Color(r, g, b, a);
115
}
116
}
117
118
static Color _material_color(const ufbx_material_map &p_map, const ufbx_material_map &p_factor) {
119
Color color = _material_color(p_map);
120
if (p_factor.has_value) {
121
float factor = float(p_factor.value_real);
122
color.r *= factor;
123
color.g *= factor;
124
color.b *= factor;
125
}
126
return color;
127
}
128
129
static const ufbx_texture *_get_file_texture(const ufbx_texture *p_texture) {
130
if (!p_texture) {
131
return nullptr;
132
}
133
for (const ufbx_texture *texture : p_texture->file_textures) {
134
if (texture->file_index != UFBX_NO_INDEX) {
135
return texture;
136
}
137
}
138
return nullptr;
139
}
140
141
static Ref<Image> _get_decompressed_image(Ref<Texture2D> texture) {
142
if (texture.is_null()) {
143
return Ref<Image>();
144
}
145
Ref<Image> image = texture->get_image();
146
if (image.is_null()) {
147
return Ref<Image>();
148
}
149
image = image->duplicate();
150
image->decompress();
151
return image;
152
}
153
154
static Vector<Vector2> _decode_vertex_attrib_vec2(const ufbx_vertex_vec2 &p_attrib, const Vector<uint32_t> &p_indices) {
155
Vector<Vector2> ret;
156
157
int num_indices = p_indices.size();
158
ret.resize(num_indices);
159
for (int i = 0; i < num_indices; i++) {
160
ret.write[i] = _as_vec2(p_attrib[p_indices[i]]);
161
}
162
return ret;
163
}
164
165
static Vector<Vector3> _decode_vertex_attrib_vec3(const ufbx_vertex_vec3 &p_attrib, const Vector<uint32_t> &p_indices) {
166
Vector<Vector3> ret;
167
168
int num_indices = p_indices.size();
169
ret.resize(num_indices);
170
for (int i = 0; i < num_indices; i++) {
171
ret.write[i] = FBXDocument::_as_vec3(p_attrib[p_indices[i]]);
172
}
173
return ret;
174
}
175
176
static Vector<float> _decode_vertex_attrib_vec3_as_tangent(const ufbx_vertex_vec3 &p_attrib, const Vector<uint32_t> &p_indices) {
177
Vector<float> ret;
178
179
int num_indices = p_indices.size();
180
ret.resize(num_indices * 4);
181
for (int i = 0; i < num_indices; i++) {
182
Vector3 v = FBXDocument::_as_vec3(p_attrib[p_indices[i]]);
183
ret.write[i * 4 + 0] = v.x;
184
ret.write[i * 4 + 1] = v.y;
185
ret.write[i * 4 + 2] = v.z;
186
ret.write[i * 4 + 3] = 1.0f;
187
}
188
return ret;
189
}
190
191
static Vector<Color> _decode_vertex_attrib_color(const ufbx_vertex_vec4 &p_attrib, const Vector<uint32_t> &p_indices) {
192
Vector<Color> ret;
193
194
int num_indices = p_indices.size();
195
ret.resize(num_indices);
196
for (int i = 0; i < num_indices; i++) {
197
ret.write[i] = _as_color(p_attrib[p_indices[i]]);
198
}
199
return ret;
200
}
201
202
static Vector3 _encode_vertex_index(uint32_t p_index) {
203
return Vector3(real_t(p_index & 0xffff), real_t(p_index >> 16), 0.0f);
204
}
205
206
static uint32_t _decode_vertex_index(const Vector3 &p_vertex) {
207
return uint32_t(p_vertex.x) | uint32_t(p_vertex.y) << 16;
208
}
209
210
static ufbx_skin_deformer *_find_skin_deformer(ufbx_skin_cluster *p_cluster) {
211
for (const ufbx_connection &conn : p_cluster->element.connections_src) {
212
ufbx_skin_deformer *deformer = ufbx_as_skin_deformer(conn.dst);
213
if (deformer) {
214
return deformer;
215
}
216
}
217
return nullptr;
218
}
219
220
static String _find_element_name(ufbx_element *p_element) {
221
if (p_element->name.length > 0) {
222
return FBXDocument::_as_string(p_element->name);
223
} else if (p_element->instances.count > 0) {
224
return _find_element_name(&p_element->instances[0]->element);
225
} else {
226
return "";
227
}
228
}
229
230
struct ThreadPoolFBX {
231
struct Group {
232
ufbx_thread_pool_context ctx = {};
233
WorkerThreadPool::GroupID task_id = {};
234
uint32_t start_index = 0;
235
};
236
237
WorkerThreadPool *pool = nullptr;
238
Group groups[UFBX_THREAD_GROUP_COUNT] = {};
239
};
240
241
static void _thread_pool_task(void *user, uint32_t index) {
242
ThreadPoolFBX::Group *group = (ThreadPoolFBX::Group *)user;
243
ufbx_thread_pool_run_task(group->ctx, group->start_index + index);
244
}
245
246
static bool _thread_pool_init_fn(void *user, ufbx_thread_pool_context ctx, const ufbx_thread_pool_info *info) {
247
ThreadPoolFBX *pool = (ThreadPoolFBX *)user;
248
for (ThreadPoolFBX::Group &group : pool->groups) {
249
group.ctx = ctx;
250
}
251
return true;
252
}
253
254
static void _thread_pool_run_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t start_index, uint32_t count) {
255
ThreadPoolFBX *pool = (ThreadPoolFBX *)user;
256
ThreadPoolFBX::Group &pool_group = pool->groups[group];
257
pool_group.start_index = start_index;
258
pool_group.task_id = pool->pool->add_native_group_task(_thread_pool_task, &pool_group, (int)count, -1, true, "ufbx");
259
}
260
261
static void _thread_pool_wait_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t max_index) {
262
ThreadPoolFBX *pool = (ThreadPoolFBX *)user;
263
pool->pool->wait_for_group_task_completion(pool->groups[group].task_id);
264
}
265
266
String FBXDocument::_gen_unique_name(HashSet<String> &unique_names, const String &p_name) {
267
const String s_name = p_name.validate_node_name();
268
269
String u_name;
270
int index = 1;
271
while (true) {
272
u_name = s_name;
273
274
if (index > 1) {
275
u_name += itos(index);
276
}
277
if (!unique_names.has(u_name)) {
278
break;
279
}
280
index++;
281
}
282
283
unique_names.insert(u_name);
284
285
return u_name;
286
}
287
288
String FBXDocument::_sanitize_animation_name(const String &p_name) {
289
String anim_name = p_name.validate_node_name();
290
return AnimationLibrary::validate_library_name(anim_name);
291
}
292
293
String FBXDocument::_gen_unique_animation_name(Ref<FBXState> p_state, const String &p_name) {
294
const String s_name = _sanitize_animation_name(p_name);
295
296
String u_name;
297
int index = 1;
298
while (true) {
299
u_name = s_name;
300
301
if (index > 1) {
302
u_name += itos(index);
303
}
304
if (!p_state->unique_animation_names.has(u_name)) {
305
break;
306
}
307
index++;
308
}
309
310
p_state->unique_animation_names.insert(u_name);
311
312
return u_name;
313
}
314
315
Error FBXDocument::_parse_scenes(Ref<FBXState> p_state) {
316
p_state->unique_names.insert("Skeleton3D"); // Reserve skeleton name.
317
318
const ufbx_scene *fbx_scene = p_state->scene.get();
319
320
// TODO: Multi-document support, would need test files for structure
321
p_state->scene_name = "";
322
323
// TODO: Append the root node directly if we use root-based space conversion
324
for (const ufbx_node *root_node : fbx_scene->root_node->children) {
325
p_state->root_nodes.push_back(int(root_node->typed_id));
326
}
327
328
return OK;
329
}
330
331
Error FBXDocument::_parse_nodes(Ref<FBXState> p_state) {
332
const ufbx_scene *fbx_scene = p_state->scene.get();
333
334
for (int node_i = 0; node_i < static_cast<int>(fbx_scene->nodes.count); node_i++) {
335
const ufbx_node *fbx_node = fbx_scene->nodes[node_i];
336
337
Ref<GLTFNode> node;
338
node.instantiate();
339
340
node->height = int(fbx_node->node_depth);
341
342
if (fbx_node->name.length > 0) {
343
node->set_name(_as_string(fbx_node->name));
344
node->set_original_name(node->get_name());
345
} else if (fbx_node->is_root) {
346
node->set_name("RootNode");
347
}
348
if (fbx_node->camera) {
349
node->camera = fbx_node->camera->typed_id;
350
}
351
if (fbx_node->light) {
352
node->light = fbx_node->light->typed_id;
353
}
354
if (fbx_node->mesh) {
355
node->mesh = fbx_node->mesh->typed_id;
356
}
357
358
{
359
node->transform = _as_transform(fbx_node->local_transform);
360
361
bool found_rest_xform = false;
362
bool bad_rest_xform = false;
363
Transform3D candidate_rest_xform;
364
365
if (fbx_node->parent) {
366
// Attempt to resolve a rest pose for bones: This uses internal FBX connections to find
367
// all skin clusters connected to the bone.
368
for (const ufbx_connection &child_conn : fbx_node->element.connections_src) {
369
ufbx_skin_cluster *child_cluster = ufbx_as_skin_cluster(child_conn.dst);
370
if (!child_cluster) {
371
continue;
372
}
373
ufbx_skin_deformer *child_deformer = _find_skin_deformer(child_cluster);
374
if (!child_deformer) {
375
continue;
376
}
377
378
// Found a skin cluster: Now iterate through all the skin clusters of the parent and
379
// try to find one that used by the same deformer.
380
for (const ufbx_connection &parent_conn : fbx_node->parent->element.connections_src) {
381
ufbx_skin_cluster *parent_cluster = ufbx_as_skin_cluster(parent_conn.dst);
382
if (!parent_cluster) {
383
continue;
384
}
385
ufbx_skin_deformer *parent_deformer = _find_skin_deformer(parent_cluster);
386
if (parent_deformer != child_deformer) {
387
continue;
388
}
389
390
// Success: Found two skin clusters from the same deformer, now we can resolve the
391
// local bind pose from the difference between the two world-space bind poses.
392
ufbx_matrix child_to_world = child_cluster->bind_to_world;
393
ufbx_matrix world_to_parent = ufbx_matrix_invert(&parent_cluster->bind_to_world);
394
ufbx_matrix child_to_parent = ufbx_matrix_mul(&world_to_parent, &child_to_world);
395
Transform3D xform = _as_transform(ufbx_matrix_to_transform(&child_to_parent));
396
397
if (!found_rest_xform) {
398
// Found the first bind pose for the node, assume that this one is good
399
found_rest_xform = true;
400
candidate_rest_xform = xform;
401
} else if (!bad_rest_xform) {
402
// Found another: Let's hope it's similar to the previous one, if not warn and
403
// use the initial pose, which is used by default if rest pose is not found.
404
real_t error = 0.0f;
405
error += _relative_error(candidate_rest_xform.origin, xform.origin);
406
for (int i = 0; i < 3; i++) {
407
error += _relative_error(candidate_rest_xform.basis.rows[i], xform.basis.rows[i]);
408
}
409
const real_t max_error = 0.01f;
410
if (error >= max_error) {
411
WARN_PRINT(vformat("FBX: Node '%s' has multiple bind poses, using initial pose as rest pose.", node->get_name()));
412
bad_rest_xform = true;
413
}
414
}
415
}
416
}
417
}
418
419
Transform3D godot_rest_xform = node->transform;
420
if (found_rest_xform && !bad_rest_xform) {
421
godot_rest_xform = candidate_rest_xform;
422
}
423
node->set_additional_data("GODOT_rest_transform", godot_rest_xform);
424
}
425
426
for (const ufbx_node *child : fbx_node->children) {
427
node->children.push_back(child->typed_id);
428
}
429
430
p_state->nodes.push_back(node);
431
}
432
433
// build the hierarchy
434
for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) {
435
for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) {
436
GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j];
437
438
ERR_FAIL_INDEX_V(child_i, p_state->nodes.size(), ERR_FILE_CORRUPT);
439
ERR_CONTINUE(p_state->nodes[child_i]->parent != -1); //node already has a parent, wtf.
440
441
p_state->nodes.write[child_i]->parent = node_i;
442
}
443
}
444
445
return OK;
446
}
447
448
Error FBXDocument::_parse_meshes(Ref<FBXState> p_state) {
449
ufbx_scene *fbx_scene = p_state->scene.get();
450
451
LocalVector<int> nodes_by_mesh_id;
452
nodes_by_mesh_id.reserve(fbx_scene->meshes.count);
453
for (size_t i = 0; i < fbx_scene->meshes.count; i++) {
454
nodes_by_mesh_id.push_back(-1);
455
}
456
for (int i = 0; i < p_state->nodes.size(); i++) {
457
const Ref<GLTFNode> &node = p_state->nodes[i];
458
if (node->mesh >= 0 && (unsigned)node->mesh < nodes_by_mesh_id.size()) {
459
nodes_by_mesh_id[node->mesh] = i;
460
}
461
}
462
463
for (const ufbx_mesh *fbx_mesh : fbx_scene->meshes) {
464
print_verbose("FBX: Parsing mesh: " + itos(int64_t(fbx_mesh->typed_id)));
465
466
static const Mesh::PrimitiveType primitive_types[] = {
467
Mesh::PRIMITIVE_TRIANGLES,
468
Mesh::PRIMITIVE_POINTS,
469
Mesh::PRIMITIVE_LINES,
470
};
471
472
Ref<ImporterMesh> import_mesh;
473
import_mesh.instantiate();
474
String mesh_name = "mesh";
475
String original_name;
476
if (fbx_mesh->name.length > 0) {
477
mesh_name = _as_string(fbx_mesh->name);
478
original_name = mesh_name;
479
} else if (fbx_mesh->typed_id < (unsigned)p_state->nodes.size() && nodes_by_mesh_id[fbx_mesh->typed_id] != -1) {
480
const Ref<GLTFNode> &node = p_state->nodes[nodes_by_mesh_id[fbx_mesh->typed_id]];
481
original_name = node->get_original_name();
482
mesh_name = node->get_name();
483
}
484
import_mesh->set_name(_gen_unique_name(p_state->unique_mesh_names, mesh_name));
485
486
bool use_blend_shapes = false;
487
if (fbx_mesh->blend_deformers.count > 0) {
488
use_blend_shapes = true;
489
}
490
491
Vector<float> blend_weights;
492
Vector<int> blend_channels;
493
if (use_blend_shapes) {
494
print_verbose("FBX: Mesh has targets");
495
496
import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
497
498
for (const ufbx_blend_deformer *fbx_deformer : fbx_mesh->blend_deformers) {
499
for (const ufbx_blend_channel *fbx_channel : fbx_deformer->channels) {
500
if (fbx_channel->keyframes.count == 0) {
501
continue;
502
}
503
String bs_name;
504
if (fbx_channel->name.length > 0) {
505
bs_name = _as_string(fbx_channel->name);
506
} else {
507
bs_name = String("morph_") + itos(blend_channels.size());
508
}
509
import_mesh->add_blend_shape(bs_name);
510
blend_weights.push_back(float(fbx_channel->weight));
511
blend_channels.push_back(float(fbx_channel->typed_id));
512
}
513
}
514
}
515
516
for (const ufbx_mesh_part &fbx_mesh_part : fbx_mesh->material_parts) {
517
for (Mesh::PrimitiveType primitive : primitive_types) {
518
uint32_t num_indices = 0;
519
switch (primitive) {
520
case Mesh::PRIMITIVE_POINTS:
521
num_indices = fbx_mesh_part.num_point_faces * 1;
522
break;
523
case Mesh::PRIMITIVE_LINES:
524
num_indices = fbx_mesh_part.num_line_faces * 2;
525
break;
526
case Mesh::PRIMITIVE_TRIANGLES:
527
num_indices = fbx_mesh_part.num_triangles * 3;
528
break;
529
case Mesh::PRIMITIVE_TRIANGLE_STRIP:
530
// FIXME 2021-09-15 fire
531
break;
532
case Mesh::PRIMITIVE_LINE_STRIP:
533
// FIXME 2021-09-15 fire
534
break;
535
default:
536
// FIXME 2021-09-15 fire
537
break;
538
}
539
if (num_indices == 0) {
540
continue;
541
}
542
543
Vector<uint32_t> indices;
544
indices.resize(num_indices);
545
546
uint32_t offset = 0;
547
for (uint32_t face_index : fbx_mesh_part.face_indices) {
548
ufbx_face face = fbx_mesh->faces[face_index];
549
switch (primitive) {
550
case Mesh::PRIMITIVE_POINTS: {
551
if (face.num_indices == 1) {
552
indices.write[offset] = face.index_begin;
553
offset += 1;
554
}
555
} break;
556
case Mesh::PRIMITIVE_LINES:
557
if (face.num_indices == 2) {
558
indices.write[offset] = face.index_begin;
559
indices.write[offset + 1] = face.index_begin + 1;
560
offset += 2;
561
}
562
break;
563
case Mesh::PRIMITIVE_TRIANGLES:
564
if (face.num_indices >= 3) {
565
uint32_t *dst = indices.ptrw() + offset;
566
size_t space = indices.size() - offset;
567
uint32_t num_triangles = ufbx_triangulate_face(dst, space, fbx_mesh, face);
568
offset += num_triangles * 3;
569
570
// Godot uses clockwise winding order!
571
for (uint32_t i = 0; i < num_triangles; i++) {
572
SWAP(dst[i * 3 + 0], dst[i * 3 + 2]);
573
}
574
}
575
break;
576
case Mesh::PRIMITIVE_TRIANGLE_STRIP:
577
// FIXME 2021-09-15 fire
578
break;
579
case Mesh::PRIMITIVE_LINE_STRIP:
580
// FIXME 2021-09-15 fire
581
break;
582
default:
583
// FIXME 2021-09-15 fire
584
break;
585
}
586
}
587
ERR_CONTINUE((uint64_t)offset != (uint64_t)indices.size());
588
589
int32_t vertex_num = indices.size();
590
bool has_vertex_color = false;
591
592
uint32_t flags = 0;
593
594
Array array;
595
array.resize(Mesh::ARRAY_MAX);
596
597
// HACK: If we have blend shapes we cannot merge vertices at identical positions
598
// if they have different indices in the file. To avoid this encode the vertex index
599
// into the vertex position for the time being.
600
// Ideally this would be an extra channel in the vertex but as the vertex format is
601
// fixed and we already use user data for extra UV channels this'll do.
602
if (use_blend_shapes) {
603
Vector<Vector3> vertex_indices;
604
int num_blend_shape_indices = indices.size();
605
vertex_indices.resize(num_blend_shape_indices);
606
for (int i = 0; i < num_blend_shape_indices; i++) {
607
vertex_indices.write[i] = _encode_vertex_index(fbx_mesh->vertex_indices[indices[i]]);
608
}
609
array[Mesh::ARRAY_VERTEX] = vertex_indices;
610
} else {
611
array[Mesh::ARRAY_VERTEX] = _decode_vertex_attrib_vec3(fbx_mesh->vertex_position, indices);
612
}
613
614
// Normals always exist as they're generated if missing,
615
// see `ufbx_load_opts.generate_missing_normals`.
616
Vector<Vector3> normals = _decode_vertex_attrib_vec3(fbx_mesh->vertex_normal, indices);
617
array[Mesh::ARRAY_NORMAL] = normals;
618
619
if (fbx_mesh->vertex_tangent.exists) {
620
Vector<float> tangents = _decode_vertex_attrib_vec3_as_tangent(fbx_mesh->vertex_tangent, indices);
621
622
// Patch bitangent sign if available
623
if (fbx_mesh->vertex_bitangent.exists) {
624
for (int i = 0; i < vertex_num; i++) {
625
Vector3 tangent = Vector3(tangents[i * 4], tangents[i * 4 + 1], tangents[i * 4 + 2]);
626
Vector3 bitangent = _as_vec3(fbx_mesh->vertex_bitangent[indices[i]]);
627
Vector3 generated_bitangent = normals[i].cross(tangent);
628
if (generated_bitangent.dot(bitangent) < 0.0f) {
629
tangents.write[i * 4 + 3] = -1.0f;
630
}
631
}
632
}
633
634
array[Mesh::ARRAY_TANGENT] = tangents;
635
}
636
637
if (fbx_mesh->vertex_uv.exists) {
638
PackedVector2Array uv_array = _decode_vertex_attrib_vec2(fbx_mesh->vertex_uv, indices);
639
_process_uv_set(uv_array);
640
array[Mesh::ARRAY_TEX_UV] = uv_array;
641
}
642
643
if (fbx_mesh->uv_sets.count >= 2 && fbx_mesh->uv_sets[1].vertex_uv.exists) {
644
PackedVector2Array uv2_array = _decode_vertex_attrib_vec2(fbx_mesh->uv_sets[1].vertex_uv, indices);
645
_process_uv_set(uv2_array);
646
array[Mesh::ARRAY_TEX_UV2] = uv2_array;
647
}
648
649
for (int uv_i = 2; uv_i < 8; uv_i += 2) {
650
Vector<float> cur_custom;
651
Vector<Vector2> texcoord_first;
652
Vector<Vector2> texcoord_second;
653
654
int texcoord_i = uv_i;
655
int texcoord_next = texcoord_i + 1;
656
int num_channels = 0;
657
if (texcoord_i < static_cast<int>(fbx_mesh->uv_sets.count) && fbx_mesh->uv_sets[texcoord_i].vertex_uv.exists) {
658
texcoord_first = _decode_vertex_attrib_vec2(fbx_mesh->uv_sets[texcoord_i].vertex_uv, indices);
659
_process_uv_set(texcoord_first);
660
num_channels = 2;
661
}
662
if (texcoord_next < static_cast<int>(fbx_mesh->uv_sets.count) && fbx_mesh->uv_sets[texcoord_next].vertex_uv.exists) {
663
texcoord_second = _decode_vertex_attrib_vec2(fbx_mesh->uv_sets[texcoord_next].vertex_uv, indices);
664
_process_uv_set(texcoord_second);
665
num_channels = 4;
666
}
667
if (!num_channels) {
668
break;
669
}
670
cur_custom.resize(vertex_num * num_channels);
671
for (int32_t uv_first_i = 0; uv_first_i < texcoord_first.size() && uv_first_i < vertex_num; uv_first_i++) {
672
int index = uv_first_i * num_channels;
673
cur_custom.write[index] = texcoord_first[uv_first_i].x;
674
cur_custom.write[index + 1] = texcoord_first[uv_first_i].y;
675
}
676
if (num_channels == 4) {
677
for (int32_t uv_second_i = 0; uv_second_i < texcoord_second.size() && uv_second_i < vertex_num; uv_second_i++) {
678
int index = uv_second_i * num_channels;
679
cur_custom.write[index + 2] = texcoord_second[uv_second_i].x;
680
cur_custom.write[index + 3] = texcoord_second[uv_second_i].y;
681
}
682
_zero_unused_elements(cur_custom, texcoord_second.size(), vertex_num, num_channels);
683
} else if (num_channels == 2) {
684
_zero_unused_elements(cur_custom, texcoord_first.size(), vertex_num, num_channels);
685
}
686
if (!cur_custom.is_empty()) {
687
array[Mesh::ARRAY_CUSTOM0 + ((uv_i - 2) / 2)] = cur_custom; // Map uv2-uv7 to custom0-custom2
688
int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + ((uv_i - 2) / 2) * Mesh::ARRAY_FORMAT_CUSTOM_BITS;
689
flags |= (num_channels == 2 ? Mesh::ARRAY_CUSTOM_RG_FLOAT : Mesh::ARRAY_CUSTOM_RGBA_FLOAT) << custom_shift;
690
}
691
}
692
693
if (fbx_mesh->vertex_color.exists) {
694
array[Mesh::ARRAY_COLOR] = _decode_vertex_attrib_color(fbx_mesh->vertex_color, indices);
695
has_vertex_color = true;
696
}
697
698
int32_t num_skin_weights = 0;
699
700
// Find the first imported skin deformer
701
for (ufbx_skin_deformer *fbx_skin : fbx_mesh->skin_deformers) {
702
GLTFSkinIndex skin_i = p_state->original_skin_indices[fbx_skin->typed_id];
703
if (skin_i < 0) {
704
continue;
705
}
706
707
// Tag all nodes to use the skin
708
for (const ufbx_node *node : fbx_mesh->instances) {
709
p_state->nodes[node->typed_id]->skin = skin_i;
710
}
711
712
num_skin_weights = fbx_skin->max_weights_per_vertex > 4 ? 8 : 4;
713
714
Vector<int32_t> bones;
715
Vector<float> weights;
716
717
bones.resize(vertex_num * num_skin_weights);
718
weights.resize(vertex_num * num_skin_weights);
719
for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
720
uint32_t fbx_vertex_index = fbx_mesh->vertex_indices[indices[vertex_i]];
721
ufbx_skin_vertex skin_vertex = fbx_skin->vertices[fbx_vertex_index];
722
float total_weight = 0.0f;
723
int32_t num_weights = MIN(int32_t(skin_vertex.num_weights), num_skin_weights);
724
for (int32_t i = 0; i < num_weights; i++) {
725
ufbx_skin_weight skin_weight = fbx_skin->weights[skin_vertex.weight_begin + i];
726
int index = vertex_i * num_skin_weights + i;
727
float weight = float(skin_weight.weight);
728
bones.write[index] = int(skin_weight.cluster_index);
729
weights.write[index] = weight;
730
total_weight += weight;
731
}
732
if (total_weight > 0.0f) {
733
for (int32_t i = 0; i < num_weights; i++) {
734
int index = vertex_i * num_skin_weights + i;
735
weights.write[index] /= total_weight;
736
}
737
}
738
// Pad the rest with empty weights
739
for (int32_t i = num_weights; i < num_skin_weights; i++) {
740
int index = vertex_i * num_skin_weights + i;
741
bones.write[index] = 0; // TODO: What should this be padded with?
742
weights.write[index] = 0.0f;
743
}
744
}
745
array[Mesh::ARRAY_BONES] = bones;
746
array[Mesh::ARRAY_WEIGHTS] = weights;
747
748
if (num_skin_weights == 8) {
749
flags |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
750
}
751
752
// Only use the first found skin
753
break;
754
}
755
756
bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !array[Mesh::ARRAY_TANGENT] && array[Mesh::ARRAY_TEX_UV] && array[Mesh::ARRAY_NORMAL]);
757
758
Ref<SurfaceTool> mesh_surface_tool;
759
mesh_surface_tool.instantiate();
760
mesh_surface_tool->create_from_triangle_arrays(array);
761
mesh_surface_tool->set_skin_weight_count(num_skin_weights == 8 ? SurfaceTool::SKIN_8_WEIGHTS : SurfaceTool::SKIN_4_WEIGHTS);
762
mesh_surface_tool->index();
763
if (generate_tangents) {
764
//must generate mikktspace tangents.. ergh..
765
mesh_surface_tool->generate_tangents();
766
}
767
array = mesh_surface_tool->commit_to_arrays();
768
769
Array morphs;
770
//blend shapes
771
if (use_blend_shapes) {
772
print_verbose("FBX: Mesh has targets");
773
774
import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
775
776
for (const ufbx_blend_deformer *fbx_deformer : fbx_mesh->blend_deformers) {
777
for (const ufbx_blend_channel *fbx_channel : fbx_deformer->channels) {
778
if (fbx_channel->keyframes.count == 0) {
779
continue;
780
}
781
782
// Use the last shape keyframe by default
783
ufbx_blend_shape *fbx_shape = fbx_channel->keyframes[fbx_channel->keyframes.count - 1].shape;
784
785
Array array_copy;
786
array_copy.resize(Mesh::ARRAY_MAX);
787
788
for (int l = 0; l < Mesh::ARRAY_MAX; l++) {
789
array_copy[l] = array[l];
790
}
791
792
Vector<Vector3> varr;
793
Vector<Vector3> narr;
794
const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
795
const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
796
const int size = src_varr.size();
797
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
798
{
799
varr.resize(size);
800
narr.resize(size);
801
802
Vector3 *w_varr = varr.ptrw();
803
Vector3 *w_narr = narr.ptrw();
804
const Vector3 *r_varr = src_varr.ptr();
805
const Vector3 *r_narr = src_narr.ptr();
806
for (int l = 0; l < size; l++) {
807
uint32_t vertex_index = _decode_vertex_index(r_varr[l]);
808
uint32_t offset_index = ufbx_get_blend_shape_offset_index(fbx_shape, vertex_index);
809
Vector3 position = _as_vec3(fbx_mesh->vertices[vertex_index]);
810
Vector3 normal = r_narr[l];
811
812
if (offset_index != UFBX_NO_INDEX && offset_index < fbx_shape->position_offsets.count) {
813
Vector3 blend_shape_position_offset = _as_vec3(fbx_shape->position_offsets[offset_index]);
814
w_varr[l] = position + blend_shape_position_offset;
815
} else {
816
w_varr[l] = position;
817
}
818
819
if (offset_index != UFBX_NO_INDEX && offset_index < fbx_shape->normal_offsets.count) {
820
w_narr[l] = (normal.normalized() + _as_vec3(fbx_shape->normal_offsets[offset_index])).normalized();
821
} else {
822
w_narr[l] = normal;
823
}
824
}
825
}
826
array_copy[Mesh::ARRAY_VERTEX] = varr;
827
array_copy[Mesh::ARRAY_NORMAL] = narr;
828
829
Ref<SurfaceTool> blend_surface_tool;
830
blend_surface_tool.instantiate();
831
blend_surface_tool->create_from_triangle_arrays(array_copy);
832
blend_surface_tool->set_skin_weight_count(num_skin_weights == 8 ? SurfaceTool::SKIN_8_WEIGHTS : SurfaceTool::SKIN_4_WEIGHTS);
833
if (generate_tangents) {
834
//must generate mikktspace tangents.. ergh..
835
blend_surface_tool->generate_tangents();
836
}
837
array_copy = blend_surface_tool->commit_to_arrays();
838
839
// Enforce blend shape mask array format
840
for (int l = 0; l < Mesh::ARRAY_MAX; l++) {
841
if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (static_cast<int64_t>(1) << l))) {
842
array_copy[l] = Variant();
843
}
844
}
845
846
morphs.push_back(array_copy);
847
}
848
}
849
}
850
851
// Decode the original vertex positions now that we're done processing blend shapes.
852
if (use_blend_shapes) {
853
Vector<Vector3> varr = array[Mesh::ARRAY_VERTEX];
854
Vector3 *w_varr = varr.ptrw();
855
const int size = varr.size();
856
for (int i = 0; i < size; i++) {
857
uint32_t vertex_index = _decode_vertex_index(w_varr[i]);
858
w_varr[i] = _as_vec3(fbx_mesh->vertices[vertex_index]);
859
}
860
array[Mesh::ARRAY_VERTEX] = varr;
861
}
862
863
Ref<Material> mat;
864
String mat_name;
865
if (!p_state->discard_meshes_and_materials) {
866
ufbx_material *fbx_material = nullptr;
867
if (fbx_mesh_part.index < fbx_mesh->materials.count) {
868
fbx_material = fbx_mesh->materials[fbx_mesh_part.index];
869
}
870
if (fbx_material) {
871
const int material = int(fbx_material->typed_id);
872
ERR_FAIL_INDEX_V(material, p_state->materials.size(), ERR_FILE_CORRUPT);
873
Ref<Material> mat3d = p_state->materials[material];
874
ERR_FAIL_COND_V(mat3d.is_null(), ERR_FILE_CORRUPT);
875
876
Ref<BaseMaterial3D> base_material = mat3d;
877
if (has_vertex_color && base_material.is_valid()) {
878
base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
879
}
880
mat = mat3d;
881
882
} else {
883
Ref<StandardMaterial3D> mat3d;
884
mat3d.instantiate();
885
if (has_vertex_color) {
886
mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
887
}
888
mat = mat3d;
889
}
890
ERR_FAIL_COND_V(mat.is_null(), ERR_FILE_CORRUPT);
891
mat_name = mat->get_name();
892
}
893
import_mesh->add_surface(primitive, array, morphs,
894
Dictionary(), mat, mat_name, flags);
895
}
896
}
897
898
Ref<GLTFMesh> mesh;
899
mesh.instantiate();
900
Dictionary additional_data;
901
additional_data["blend_channels"] = blend_channels;
902
mesh->set_additional_data("GODOT_mesh_blend_channels", additional_data);
903
mesh->set_blend_weights(blend_weights);
904
mesh->set_mesh(import_mesh);
905
mesh->set_name(import_mesh->get_name());
906
mesh->set_original_name(original_name);
907
908
p_state->meshes.push_back(mesh);
909
}
910
911
print_verbose("FBX: Total meshes: " + itos(p_state->meshes.size()));
912
913
return OK;
914
}
915
916
Ref<Image> FBXDocument::_parse_image_bytes_into_image(Ref<FBXState> p_state, const Vector<uint8_t> &p_bytes, const String &p_filename, int p_index) {
917
Ref<Image> r_image;
918
r_image.instantiate();
919
// Try to import first based on filename.
920
String filename_lower = p_filename.to_lower();
921
if (filename_lower.ends_with(".png")) {
922
r_image->load_png_from_buffer(p_bytes);
923
} else if (filename_lower.ends_with(".jpg")) {
924
r_image->load_jpg_from_buffer(p_bytes);
925
} else if (filename_lower.ends_with(".tga")) {
926
r_image->load_tga_from_buffer(p_bytes);
927
}
928
// If we didn't pass the above tests, try loading as each option.
929
if (r_image->is_empty()) { // Try PNG first.
930
r_image->load_png_from_buffer(p_bytes);
931
}
932
if (r_image->is_empty()) { // And then JPEG.
933
r_image->load_jpg_from_buffer(p_bytes);
934
}
935
if (r_image->is_empty()) { // And then TGA.
936
r_image->load_jpg_from_buffer(p_bytes);
937
}
938
// If it still can't be loaded, give up and insert an empty image as placeholder.
939
if (r_image->is_empty()) {
940
ERR_PRINT(vformat("FBX: Couldn't load image index '%d'", p_index));
941
}
942
return r_image;
943
}
944
945
GLTFImageIndex FBXDocument::_parse_image_save_image(Ref<FBXState> p_state, const Vector<uint8_t> &p_bytes, const String &p_file_extension, int p_index, Ref<Image> p_image) {
946
FBXState::GLTFHandleBinary handling = FBXState::GLTFHandleBinary(p_state->handle_binary_image);
947
if (p_image->is_empty() || handling == FBXState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) {
948
if (p_index < 0) {
949
return -1;
950
}
951
p_state->images.push_back(Ref<Texture2D>());
952
p_state->source_images.push_back(Ref<Image>());
953
return p_state->images.size() - 1;
954
}
955
#ifdef TOOLS_ENABLED
956
if (Engine::get_singleton()->is_editor_hint() && handling == FBXState::GLTFHandleBinary::HANDLE_BINARY_EXTRACT_TEXTURES) {
957
if (p_state->base_path.is_empty()) {
958
if (p_index < 0) {
959
return -1;
960
}
961
p_state->images.push_back(Ref<Texture2D>());
962
p_state->source_images.push_back(Ref<Image>());
963
} else if (p_image->get_name().is_empty()) {
964
if (p_index < 0) {
965
return -1;
966
}
967
WARN_PRINT(vformat("FBX: Image index '%d' couldn't be named. Skipping it.", p_index));
968
p_state->images.push_back(Ref<Texture2D>());
969
p_state->source_images.push_back(Ref<Image>());
970
} else {
971
bool must_import = true;
972
Vector<uint8_t> img_data = p_image->get_data();
973
Dictionary generator_parameters;
974
String file_path = p_state->get_base_path().path_join(p_state->filename.get_basename() + "_" + p_image->get_name());
975
file_path += p_file_extension.is_empty() ? ".png" : p_file_extension;
976
if (FileAccess::exists(file_path + ".import")) {
977
Ref<ConfigFile> config;
978
config.instantiate();
979
config->load(file_path + ".import");
980
if (config->has_section_key("remap", "generator_parameters")) {
981
generator_parameters = (Dictionary)config->get_value("remap", "generator_parameters");
982
}
983
if (!generator_parameters.has("md5")) {
984
must_import = false; // Didn't come from a gltf document; don't overwrite.
985
}
986
}
987
if (must_import) {
988
String existing_md5 = generator_parameters["md5"];
989
unsigned char md5_hash[16];
990
CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash);
991
String new_md5 = String::hex_encode_buffer(md5_hash, 16);
992
generator_parameters["md5"] = new_md5;
993
if (new_md5 == existing_md5) {
994
must_import = false;
995
}
996
}
997
if (must_import) {
998
Error err = OK;
999
if (p_file_extension.is_empty()) {
1000
// If a file extension was not specified, save the image data to a PNG file.
1001
err = p_image->save_png(file_path);
1002
ERR_FAIL_COND_V(err != OK, -1);
1003
} else {
1004
// If a file extension was specified, save the original bytes to a file with that extension.
1005
Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE, &err);
1006
ERR_FAIL_COND_V(err != OK, -1);
1007
file->store_buffer(p_bytes);
1008
file->close();
1009
}
1010
// ResourceLoader::import will crash if not is_editor_hint(), so this case is protected above and will fall through to uncompressed.
1011
HashMap<StringName, Variant> custom_options;
1012
custom_options[SNAME("mipmaps/generate")] = true;
1013
// Will only use project settings defaults if custom_importer is empty.
1014
EditorFileSystem::get_singleton()->update_file(file_path);
1015
EditorFileSystem::get_singleton()->reimport_append(file_path, custom_options, String(), generator_parameters);
1016
}
1017
Ref<Texture2D> saved_image = ResourceLoader::load(_get_texture_path(p_state->get_base_path(), file_path), "Texture2D");
1018
if (saved_image.is_valid()) {
1019
p_state->images.push_back(saved_image);
1020
p_state->source_images.push_back(saved_image->get_image());
1021
} else if (p_index < 0) {
1022
return -1;
1023
} else {
1024
WARN_PRINT(vformat("FBX: Image index '%d' couldn't be loaded with the name: %s. Skipping it.", p_index, p_image->get_name()));
1025
// Placeholder to keep count.
1026
p_state->images.push_back(Ref<Texture2D>());
1027
p_state->source_images.push_back(Ref<Image>());
1028
}
1029
}
1030
return p_state->images.size() - 1;
1031
}
1032
#endif // TOOLS_ENABLED
1033
if (handling == FBXState::HANDLE_BINARY_EMBED_AS_BASISU) {
1034
Ref<PortableCompressedTexture2D> tex;
1035
tex.instantiate();
1036
tex->set_name(p_image->get_name());
1037
tex->set_keep_compressed_buffer(true);
1038
tex->create_from_image(p_image, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL);
1039
p_state->images.push_back(tex);
1040
p_state->source_images.push_back(p_image);
1041
return p_state->images.size() - 1;
1042
}
1043
// This handles the case of HANDLE_BINARY_EMBED_AS_UNCOMPRESSED, and it also serves
1044
// as a fallback for HANDLE_BINARY_EXTRACT_TEXTURES when this is not the editor.
1045
Ref<ImageTexture> tex;
1046
tex.instantiate();
1047
tex->set_name(p_image->get_name());
1048
tex->set_image(p_image);
1049
p_state->images.push_back(tex);
1050
p_state->source_images.push_back(p_image);
1051
return p_state->images.size() - 1;
1052
}
1053
1054
Error FBXDocument::_parse_images(Ref<FBXState> p_state, const String &p_base_path) {
1055
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
1056
1057
const ufbx_scene *fbx_scene = p_state->scene.get();
1058
for (int texture_i = 0; texture_i < static_cast<int>(fbx_scene->texture_files.count); texture_i++) {
1059
const ufbx_texture_file &fbx_texture_file = fbx_scene->texture_files[texture_i];
1060
String path = _as_string(fbx_texture_file.filename);
1061
// Use only filename for absolute paths to avoid portability issues.
1062
if (path.is_absolute_path()) {
1063
path = path.get_file();
1064
}
1065
if (!p_base_path.is_empty()) {
1066
path = p_base_path.path_join(path);
1067
}
1068
path = path.simplify_path();
1069
Vector<uint8_t> data;
1070
if (fbx_texture_file.content.size > 0 && fbx_texture_file.content.size <= INT_MAX) {
1071
data.resize(int(fbx_texture_file.content.size));
1072
memcpy(data.ptrw(), fbx_texture_file.content.data, fbx_texture_file.content.size);
1073
} else {
1074
String base_dir = p_state->get_base_path();
1075
Ref<Texture2D> texture = ResourceLoader::load(_get_texture_path(base_dir, path), "Texture2D");
1076
if (texture.is_valid()) {
1077
p_state->images.push_back(texture);
1078
p_state->source_images.push_back(texture->get_image());
1079
continue;
1080
}
1081
// Fallback to loading as byte array.
1082
data = FileAccess::get_file_as_bytes(path);
1083
if (data.is_empty()) {
1084
WARN_PRINT(vformat("FBX: Image index '%d' couldn't be loaded from path: %s because there was no data to load. Skipping it.", texture_i, path));
1085
p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
1086
p_state->source_images.push_back(Ref<Image>());
1087
continue;
1088
}
1089
}
1090
1091
// Parse the image data from bytes into an Image resource and save if needed.
1092
String file_extension;
1093
Ref<Image> img = _parse_image_bytes_into_image(p_state, data, path, texture_i);
1094
img->set_name(itos(texture_i));
1095
_parse_image_save_image(p_state, data, file_extension, texture_i, img);
1096
}
1097
1098
// Create a texture for each file texture.
1099
for (int texture_file_i = 0; texture_file_i < static_cast<int>(fbx_scene->texture_files.count); texture_file_i++) {
1100
Ref<GLTFTexture> texture;
1101
texture.instantiate();
1102
texture->set_src_image(GLTFImageIndex(texture_file_i));
1103
p_state->textures.push_back(texture);
1104
}
1105
1106
print_verbose("FBX: Total images: " + itos(p_state->images.size()));
1107
1108
return OK;
1109
}
1110
1111
Ref<Texture2D> FBXDocument::_get_texture(Ref<FBXState> p_state, const GLTFTextureIndex p_texture, int p_texture_types) {
1112
ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>());
1113
const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image();
1114
ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref<Texture2D>());
1115
if (FBXState::GLTFHandleBinary(p_state->handle_binary_image) == FBXState::HANDLE_BINARY_EMBED_AS_BASISU) {
1116
ERR_FAIL_INDEX_V(image, p_state->source_images.size(), Ref<Texture2D>());
1117
Ref<PortableCompressedTexture2D> portable_texture;
1118
portable_texture.instantiate();
1119
portable_texture->set_keep_compressed_buffer(true);
1120
Ref<Image> new_img = p_state->source_images[image]->duplicate();
1121
ERR_FAIL_COND_V(new_img.is_null(), Ref<Texture2D>());
1122
new_img->generate_mipmaps();
1123
if (p_texture_types) {
1124
portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, true);
1125
} else {
1126
portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, false);
1127
}
1128
p_state->images.write[image] = portable_texture;
1129
p_state->source_images.write[image] = new_img;
1130
}
1131
return p_state->images[image];
1132
}
1133
1134
Error FBXDocument::_parse_materials(Ref<FBXState> p_state) {
1135
const ufbx_scene *fbx_scene = p_state->scene.get();
1136
for (GLTFMaterialIndex material_i = 0; material_i < static_cast<GLTFMaterialIndex>(fbx_scene->materials.count); material_i++) {
1137
const ufbx_material *fbx_material = fbx_scene->materials[material_i];
1138
1139
Ref<StandardMaterial3D> material;
1140
material.instantiate();
1141
if (fbx_material->name.length > 0) {
1142
material->set_name(_as_string(fbx_material->name));
1143
} else {
1144
material->set_name(vformat("material_%s", itos(material_i)));
1145
}
1146
material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
1147
Dictionary material_extensions;
1148
1149
if (fbx_material->pbr.base_color.has_value) {
1150
Color albedo = _material_color(fbx_material->pbr.base_color, fbx_material->pbr.base_factor);
1151
material->set_albedo(albedo.linear_to_srgb());
1152
}
1153
1154
if (fbx_material->features.double_sided.enabled) {
1155
material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
1156
}
1157
1158
const ufbx_texture *base_texture = _get_file_texture(fbx_material->pbr.base_color.texture);
1159
if (base_texture) {
1160
bool wrap = base_texture->wrap_u == UFBX_WRAP_REPEAT && base_texture->wrap_v == UFBX_WRAP_REPEAT;
1161
material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, wrap);
1162
1163
Ref<Texture2D> albedo_texture = _get_texture(p_state, GLTFTextureIndex(base_texture->file_index), TEXTURE_TYPE_GENERIC);
1164
1165
// Search for transparency map.
1166
Ref<Texture2D> transparency_texture;
1167
const ufbx_texture *transparency_sources[] = {
1168
fbx_material->pbr.opacity.texture,
1169
fbx_material->fbx.transparency_color.texture,
1170
};
1171
for (const ufbx_texture *transparency_source : transparency_sources) {
1172
const ufbx_texture *fbx_transparency_texture = _get_file_texture(transparency_source);
1173
if (fbx_transparency_texture) {
1174
transparency_texture = _get_texture(p_state, GLTFTextureIndex(fbx_transparency_texture->file_index), TEXTURE_TYPE_GENERIC);
1175
if (transparency_texture.is_valid()) {
1176
break;
1177
}
1178
}
1179
}
1180
1181
// Multiply the albedo alpha with the transparency texture if necessary.
1182
if (albedo_texture.is_valid() && transparency_texture.is_valid() && albedo_texture != transparency_texture) {
1183
Pair<uint64_t, uint64_t> key = { albedo_texture->get_rid().get_id(), transparency_texture->get_rid().get_id() };
1184
GLTFTextureIndex *texture_index_ptr = p_state->albedo_transparency_textures.getptr(key);
1185
if (texture_index_ptr != nullptr) {
1186
if (*texture_index_ptr >= 0) {
1187
albedo_texture = _get_texture(p_state, *texture_index_ptr, TEXTURE_TYPE_GENERIC);
1188
}
1189
} else {
1190
Ref<Image> albedo_image = _get_decompressed_image(albedo_texture);
1191
Ref<Image> transparency_image = _get_decompressed_image(transparency_texture);
1192
1193
if (albedo_image.is_valid() && transparency_image.is_valid()) {
1194
albedo_image->convert(Image::Format::FORMAT_RGBA8);
1195
transparency_image->resize(albedo_texture->get_width(), albedo_texture->get_height(), Image::INTERPOLATE_LANCZOS);
1196
for (int y = 0; y < albedo_image->get_height(); y++) {
1197
for (int x = 0; x < albedo_image->get_width(); x++) {
1198
Color albedo_pixel = albedo_image->get_pixel(x, y);
1199
Color transparency_pixel = transparency_image->get_pixel(x, y);
1200
albedo_pixel.a *= transparency_pixel.r;
1201
albedo_image->set_pixel(x, y, albedo_pixel);
1202
}
1203
}
1204
1205
albedo_image->clear_mipmaps();
1206
albedo_image->generate_mipmaps();
1207
1208
albedo_image->set_name(vformat("alpha_%d", p_state->albedo_transparency_textures.size()));
1209
1210
GLTFImageIndex new_image = _parse_image_save_image(p_state, PackedByteArray(), "", -1, albedo_image);
1211
if (new_image >= 0) {
1212
Ref<GLTFTexture> new_texture;
1213
new_texture.instantiate();
1214
new_texture->set_src_image(GLTFImageIndex(new_image));
1215
p_state->textures.push_back(new_texture);
1216
1217
GLTFTextureIndex texture_index = p_state->textures.size() - 1;
1218
p_state->albedo_transparency_textures[key] = texture_index;
1219
1220
albedo_texture = _get_texture(p_state, texture_index, TEXTURE_TYPE_GENERIC);
1221
} else {
1222
WARN_PRINT(vformat("FBX: Could not save modified albedo texture from RID (%d, %d).", key.first, key.second));
1223
p_state->albedo_transparency_textures[key] = -1;
1224
}
1225
}
1226
}
1227
}
1228
1229
Image::AlphaMode alpha_mode;
1230
if (albedo_texture.is_valid()) {
1231
Image::AlphaMode *alpha_mode_ptr = p_state->alpha_mode_cache.getptr(albedo_texture->get_rid().get_id());
1232
if (alpha_mode_ptr != nullptr) {
1233
alpha_mode = *alpha_mode_ptr;
1234
} else {
1235
Ref<Image> albedo_image = _get_decompressed_image(albedo_texture);
1236
alpha_mode = albedo_image->detect_alpha();
1237
p_state->alpha_mode_cache[albedo_texture->get_rid().get_id()] = alpha_mode;
1238
}
1239
1240
if (alpha_mode == Image::ALPHA_BLEND) {
1241
material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
1242
} else if (alpha_mode == Image::ALPHA_BIT) {
1243
material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
1244
}
1245
material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, albedo_texture);
1246
}
1247
1248
// Combined textures and factors are very unreliable in FBX
1249
Color albedo_factor = Color(1, 1, 1);
1250
if (fbx_material->pbr.base_factor.has_value) {
1251
albedo_factor *= (float)fbx_material->pbr.base_factor.value_real;
1252
}
1253
material->set_albedo(albedo_factor.linear_to_srgb());
1254
1255
// TODO: Does not support rotation, could be inverted?
1256
material->set_uv1_offset(_as_vec3(base_texture->uv_transform.translation));
1257
Vector3 scale = _as_vec3(base_texture->uv_transform.scale);
1258
material->set_uv1_scale(scale);
1259
}
1260
1261
if (fbx_material->features.pbr.enabled) {
1262
if (fbx_material->pbr.metalness.has_value) {
1263
material->set_metallic(float(fbx_material->pbr.metalness.value_real));
1264
} else {
1265
material->set_metallic(1.0);
1266
}
1267
1268
if (fbx_material->pbr.roughness.has_value) {
1269
material->set_roughness(float(fbx_material->pbr.roughness.value_real));
1270
} else {
1271
material->set_roughness(1.0);
1272
}
1273
1274
const ufbx_texture *metalness_texture = _get_file_texture(fbx_material->pbr.metalness.texture);
1275
if (metalness_texture) {
1276
material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, _get_texture(p_state, GLTFTextureIndex(metalness_texture->file_index), TEXTURE_TYPE_GENERIC));
1277
material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
1278
material->set_metallic(1.0);
1279
}
1280
1281
const ufbx_texture *roughness_texture = _get_file_texture(fbx_material->pbr.roughness.texture);
1282
if (roughness_texture) {
1283
material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, _get_texture(p_state, GLTFTextureIndex(roughness_texture->file_index), TEXTURE_TYPE_GENERIC));
1284
material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
1285
material->set_roughness(1.0);
1286
}
1287
}
1288
1289
const ufbx_texture *normal_texture = _get_file_texture(fbx_material->pbr.normal_map.texture);
1290
if (normal_texture) {
1291
material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, GLTFTextureIndex(normal_texture->file_index), TEXTURE_TYPE_NORMAL));
1292
material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true);
1293
if (fbx_material->pbr.normal_map.has_value) {
1294
material->set_normal_scale(fbx_material->pbr.normal_map.value_real);
1295
}
1296
}
1297
1298
const ufbx_texture *occlusion_texture = _get_file_texture(fbx_material->pbr.ambient_occlusion.texture);
1299
if (occlusion_texture) {
1300
material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, GLTFTextureIndex(occlusion_texture->file_index), TEXTURE_TYPE_GENERIC));
1301
material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
1302
material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true);
1303
}
1304
1305
if (fbx_material->pbr.emission_color.has_value) {
1306
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
1307
material->set_emission(_material_color(fbx_material->pbr.emission_color).linear_to_srgb());
1308
material->set_emission_energy_multiplier(float(fbx_material->pbr.emission_factor.value_real));
1309
}
1310
1311
const ufbx_texture *emission_texture = _get_file_texture(fbx_material->pbr.emission_color.texture);
1312
if (emission_texture) {
1313
material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, GLTFTextureIndex(emission_texture->file_index), TEXTURE_TYPE_GENERIC));
1314
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
1315
material->set_emission(Color(0, 0, 0));
1316
}
1317
1318
if (fbx_material->features.double_sided.enabled && fbx_material->features.double_sided.is_explicit) {
1319
material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
1320
}
1321
p_state->materials.push_back(material);
1322
}
1323
1324
print_verbose("Total materials: " + itos(p_state->materials.size()));
1325
1326
return OK;
1327
}
1328
Error FBXDocument::_parse_cameras(Ref<FBXState> p_state) {
1329
const ufbx_scene *fbx_scene = p_state->scene.get();
1330
for (GLTFCameraIndex i = 0; i < static_cast<GLTFCameraIndex>(fbx_scene->cameras.count); i++) {
1331
const ufbx_camera *fbx_camera = fbx_scene->cameras[i];
1332
1333
Ref<GLTFCamera> camera;
1334
camera.instantiate();
1335
camera->set_name(_as_string(fbx_camera->name));
1336
if (fbx_camera->projection_mode == UFBX_PROJECTION_MODE_PERSPECTIVE) {
1337
camera->set_perspective(true);
1338
camera->set_fov(Math::deg_to_rad(real_t(fbx_camera->field_of_view_deg.y)));
1339
} else {
1340
camera->set_perspective(false);
1341
camera->set_size_mag(real_t(fbx_camera->orthographic_size.y * 0.5f));
1342
}
1343
if (fbx_camera->near_plane != 0.0f) {
1344
camera->set_depth_near(fbx_camera->near_plane);
1345
}
1346
if (fbx_camera->far_plane != 0.0f) {
1347
camera->set_depth_far(fbx_camera->far_plane);
1348
}
1349
p_state->cameras.push_back(camera);
1350
}
1351
1352
print_verbose("FBX: Total cameras: " + itos(p_state->cameras.size()));
1353
1354
return OK;
1355
}
1356
1357
Error FBXDocument::_parse_animations(Ref<FBXState> p_state) {
1358
const ufbx_scene *fbx_scene = p_state->scene.get();
1359
for (GLTFAnimationIndex animation_i = 0; animation_i < static_cast<GLTFAnimationIndex>(fbx_scene->anim_stacks.count); animation_i++) {
1360
const ufbx_anim_stack *fbx_anim_stack = fbx_scene->anim_stacks[animation_i];
1361
1362
Ref<GLTFAnimation> animation;
1363
animation.instantiate();
1364
1365
if (fbx_anim_stack->name.length > 0) {
1366
const String anim_name = _as_string(fbx_anim_stack->name);
1367
const String anim_name_lower = anim_name.to_lower();
1368
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")) {
1369
animation->set_loop(true);
1370
}
1371
animation->set_original_name(anim_name);
1372
animation->set_name(_gen_unique_animation_name(p_state, anim_name));
1373
}
1374
1375
Dictionary additional_data;
1376
additional_data["time_begin"] = fbx_anim_stack->time_begin;
1377
additional_data["time_end"] = fbx_anim_stack->time_end;
1378
animation->set_additional_data("GODOT_animation_time_begin_time_end", additional_data);
1379
ufbx_bake_opts opts = {};
1380
opts.resample_rate = p_state->get_bake_fps();
1381
opts.minimum_sample_rate = p_state->get_bake_fps();
1382
opts.max_keyframe_segments = 1024;
1383
1384
ufbx_error error;
1385
ufbx_unique_ptr<ufbx_baked_anim> fbx_baked_anim{ ufbx_bake_anim(fbx_scene, fbx_anim_stack->anim, &opts, &error) };
1386
if (!fbx_baked_anim) {
1387
char err_buf[512];
1388
ufbx_format_error(err_buf, sizeof(err_buf), &error);
1389
ERR_FAIL_V_MSG(FAILED, err_buf);
1390
}
1391
1392
for (const ufbx_baked_node &fbx_baked_node : fbx_baked_anim->nodes) {
1393
const GLTFNodeIndex node = fbx_baked_node.typed_id;
1394
GLTFAnimation::NodeTrack &track = animation->get_node_tracks()[node];
1395
1396
for (const ufbx_baked_vec3 &key : fbx_baked_node.translation_keys) {
1397
track.position_track.times.push_back(float(key.time));
1398
track.position_track.values.push_back(_as_vec3(key.value));
1399
}
1400
1401
for (const ufbx_baked_quat &key : fbx_baked_node.rotation_keys) {
1402
track.rotation_track.times.push_back(float(key.time));
1403
track.rotation_track.values.push_back(_as_quaternion(key.value));
1404
}
1405
1406
for (const ufbx_baked_vec3 &key : fbx_baked_node.scale_keys) {
1407
track.scale_track.times.push_back(float(key.time));
1408
track.scale_track.values.push_back(_as_vec3(key.value));
1409
}
1410
}
1411
1412
Dictionary blend_shape_animations;
1413
1414
for (const ufbx_baked_element &fbx_baked_element : fbx_baked_anim->elements) {
1415
const ufbx_element *fbx_element = fbx_scene->elements[fbx_baked_element.element_id];
1416
1417
for (const ufbx_baked_prop &fbx_baked_prop : fbx_baked_element.props) {
1418
String prop_name = _as_string(fbx_baked_prop.name);
1419
1420
if (fbx_element->type == UFBX_ELEMENT_BLEND_CHANNEL && prop_name == UFBX_DeformPercent) {
1421
const ufbx_blend_channel *fbx_blend_channel = ufbx_as_blend_channel(fbx_element);
1422
1423
int blend_i = fbx_blend_channel->typed_id;
1424
Vector<real_t> track_times;
1425
Vector<real_t> track_values;
1426
1427
for (const ufbx_baked_vec3 &key : fbx_baked_prop.keys) {
1428
track_times.push_back(float(key.time));
1429
track_values.push_back(real_t(key.value.x / 100.0));
1430
}
1431
1432
Dictionary track;
1433
track["times"] = track_times;
1434
track["values"] = track_values;
1435
blend_shape_animations[blend_i] = track;
1436
}
1437
}
1438
}
1439
1440
animation->set_additional_data("GODOT_blend_shape_animations", blend_shape_animations);
1441
1442
p_state->animations.push_back(animation);
1443
}
1444
1445
print_verbose("FBX: Total animations '" + itos(p_state->animations.size()) + "'.");
1446
1447
return OK;
1448
}
1449
1450
void FBXDocument::_assign_node_names(Ref<FBXState> p_state) {
1451
for (int i = 0; i < p_state->nodes.size(); i++) {
1452
Ref<GLTFNode> fbx_node = p_state->nodes[i];
1453
1454
// Any joints get unique names generated when the skeleton is made, unique to the skeleton
1455
if (fbx_node->skeleton >= 0) {
1456
continue;
1457
}
1458
1459
if (fbx_node->get_name().is_empty()) {
1460
if (fbx_node->mesh >= 0) {
1461
fbx_node->set_name(_gen_unique_name(p_state->unique_names, "Mesh"));
1462
} else if (fbx_node->camera >= 0) {
1463
fbx_node->set_name(_gen_unique_name(p_state->unique_names, "Camera3D"));
1464
} else {
1465
fbx_node->set_name(_gen_unique_name(p_state->unique_names, "Node"));
1466
}
1467
}
1468
1469
fbx_node->set_name(_gen_unique_name(p_state->unique_names, fbx_node->get_name()));
1470
}
1471
}
1472
1473
BoneAttachment3D *FBXDocument::_generate_bone_attachment(Ref<FBXState> p_state, Skeleton3D *p_skeleton, const GLTFNodeIndex p_node_index, const GLTFNodeIndex p_bone_index) {
1474
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1475
Ref<GLTFNode> bone_node = p_state->nodes[p_bone_index];
1476
BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D);
1477
print_verbose("FBX: Creating bone attachment for: " + fbx_node->get_name());
1478
1479
ERR_FAIL_COND_V(!bone_node->joint, nullptr);
1480
1481
bone_attachment->set_bone_name(bone_node->get_name());
1482
1483
return bone_attachment;
1484
}
1485
1486
ImporterMeshInstance3D *FBXDocument::_generate_mesh_instance(Ref<FBXState> p_state, const GLTFNodeIndex p_node_index) {
1487
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1488
1489
ERR_FAIL_INDEX_V(fbx_node->mesh, p_state->meshes.size(), nullptr);
1490
1491
ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
1492
print_verbose("FBX: Creating mesh for: " + fbx_node->get_name());
1493
1494
p_state->scene_mesh_instances.insert(p_node_index, mi);
1495
Ref<GLTFMesh> mesh = p_state->meshes.write[fbx_node->mesh];
1496
if (mesh.is_null()) {
1497
return mi;
1498
}
1499
Ref<ImporterMesh> import_mesh = mesh->get_mesh();
1500
if (import_mesh.is_null()) {
1501
return mi;
1502
}
1503
mi->set_mesh(import_mesh);
1504
return mi;
1505
}
1506
1507
Camera3D *FBXDocument::_generate_camera(Ref<FBXState> p_state, const GLTFNodeIndex p_node_index) {
1508
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1509
1510
ERR_FAIL_INDEX_V(fbx_node->camera, p_state->cameras.size(), nullptr);
1511
1512
print_verbose("FBX: Creating camera for: " + fbx_node->get_name());
1513
1514
Ref<GLTFCamera> c = p_state->cameras[fbx_node->camera];
1515
return c->to_node();
1516
}
1517
1518
Light3D *FBXDocument::_generate_light(Ref<FBXState> p_state, const GLTFNodeIndex p_node_index) {
1519
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1520
1521
ERR_FAIL_INDEX_V(fbx_node->light, p_state->lights.size(), nullptr);
1522
1523
print_verbose("FBX: Creating light for: " + fbx_node->get_name());
1524
1525
Ref<GLTFLight> l = p_state->lights[fbx_node->light];
1526
Light3D *light = nullptr;
1527
1528
if (l->get_light_type() == "point") {
1529
light = memnew(OmniLight3D);
1530
} else if (l->get_light_type() == "directional") {
1531
light = memnew(DirectionalLight3D);
1532
} else if (l->get_light_type() == "spot") {
1533
light = memnew(SpotLight3D);
1534
} else {
1535
ERR_FAIL_NULL_V(light, nullptr);
1536
}
1537
1538
if (light) {
1539
light->set_name(l->get_name());
1540
light->set_color(l->get_color());
1541
light->set_param(Light3D::PARAM_ENERGY, l->get_intensity());
1542
Dictionary additional_data = l->get_additional_data("GODOT_fbx_light");
1543
if (additional_data.has("castShadows")) {
1544
light->set_shadow(additional_data["castShadows"]);
1545
}
1546
if (additional_data.has("castLight")) {
1547
light->set_visible(additional_data["castLight"]);
1548
}
1549
1550
Transform3D transform;
1551
DirectionalLight3D *dir_light = Object::cast_to<DirectionalLight3D>(light);
1552
SpotLight3D *spot_light = Object::cast_to<SpotLight3D>(light);
1553
OmniLight3D *omni_light = Object::cast_to<OmniLight3D>(light);
1554
if (dir_light) {
1555
dir_light->set_transform(transform);
1556
} else if (spot_light) {
1557
spot_light->set_transform(transform);
1558
spot_light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, l->get_outer_cone_angle() / 2.0f);
1559
}
1560
if (omni_light || spot_light) {
1561
light->set_param(OmniLight3D::PARAM_RANGE, 4096);
1562
}
1563
1564
// This is "correct", but FBX files may have unexpected decay modes.
1565
// Also does not match with what FBX2glTF does, so it might be better to not do any of this..
1566
#if 0
1567
if (omni_light || spot_light) {
1568
float attenuation = 1.0f;
1569
if (additional_data.has("decay")) {
1570
String decay_type = additional_data["decay"];
1571
if (decay_type == "none") {
1572
attenuation = 0.001f;
1573
} else if (decay_type == "linear") {
1574
attenuation = 1.0f;
1575
} else if (decay_type == "quadratic") {
1576
attenuation = 2.0f;
1577
} else if (decay_type == "cubic") {
1578
attenuation = 3.0f;
1579
}
1580
}
1581
light->set_param(Light3D::PARAM_ATTENUATION, attenuation);
1582
}
1583
#endif
1584
1585
if (spot_light) {
1586
// Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b
1587
// The points in desmos are not exact, except for (1, infinity).
1588
float angle_ratio = l->get_inner_cone_angle() / l->get_outer_cone_angle();
1589
float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1;
1590
light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation);
1591
}
1592
}
1593
1594
return light;
1595
}
1596
1597
Node3D *FBXDocument::_generate_spatial(Ref<FBXState> p_state, const GLTFNodeIndex p_node_index) {
1598
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1599
1600
Node3D *spatial = memnew(Node3D);
1601
print_verbose("FBX: Converting spatial: " + fbx_node->get_name());
1602
1603
return spatial;
1604
}
1605
1606
void FBXDocument::_generate_scene_node(Ref<FBXState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root) {
1607
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1608
1609
if (fbx_node->skeleton >= 0) {
1610
_generate_skeleton_bone_node(p_state, p_node_index, p_scene_parent, p_scene_root);
1611
return;
1612
}
1613
1614
Node3D *current_node = nullptr;
1615
1616
// Is our parent a skeleton
1617
Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent);
1618
1619
const bool non_bone_parented_to_skeleton = active_skeleton;
1620
1621
// skinned meshes must not be placed in a bone attachment.
1622
if (non_bone_parented_to_skeleton && fbx_node->skin < 0) {
1623
// Bone Attachment - Parent Case
1624
BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, fbx_node->parent);
1625
1626
p_scene_parent->add_child(bone_attachment, true);
1627
bone_attachment->set_owner(p_scene_root);
1628
1629
// There is no fbx_node that represent this, so just directly create a unique name
1630
bone_attachment->set_name(fbx_node->get_name());
1631
1632
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
1633
// and attach it to the bone_attachment
1634
p_scene_parent = bone_attachment;
1635
}
1636
if (!current_node) {
1637
if (fbx_node->skin >= 0 && fbx_node->mesh >= 0 && !fbx_node->children.is_empty()) {
1638
current_node = _generate_spatial(p_state, p_node_index);
1639
Node3D *mesh_inst = _generate_mesh_instance(p_state, p_node_index);
1640
mesh_inst->set_name(fbx_node->get_name());
1641
1642
current_node->add_child(mesh_inst, true);
1643
} else if (fbx_node->mesh >= 0) {
1644
current_node = _generate_mesh_instance(p_state, p_node_index);
1645
} else if (fbx_node->camera >= 0) {
1646
current_node = _generate_camera(p_state, p_node_index);
1647
} else if (fbx_node->light >= 0) {
1648
current_node = _generate_light(p_state, p_node_index);
1649
} else {
1650
current_node = _generate_spatial(p_state, p_node_index);
1651
}
1652
}
1653
1654
ERR_FAIL_NULL(current_node);
1655
1656
// Add the node we generated and set the owner to the scene root.
1657
p_scene_parent->add_child(current_node, true);
1658
if (current_node != p_scene_root) {
1659
Array args = { p_scene_root };
1660
current_node->propagate_call(StringName("set_owner"), args);
1661
}
1662
current_node->set_transform(fbx_node->transform);
1663
current_node->set_name(fbx_node->get_name());
1664
1665
p_state->scene_nodes.insert(p_node_index, current_node);
1666
for (int i = 0; i < fbx_node->children.size(); ++i) {
1667
_generate_scene_node(p_state, fbx_node->children[i], current_node, p_scene_root);
1668
}
1669
}
1670
1671
void FBXDocument::_generate_skeleton_bone_node(Ref<FBXState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root) {
1672
Ref<GLTFNode> fbx_node = p_state->nodes[p_node_index];
1673
1674
Node3D *current_node = nullptr;
1675
1676
Skeleton3D *skeleton = p_state->skeletons[fbx_node->skeleton]->godot_skeleton;
1677
// In this case, this node is already a bone in skeleton.
1678
const bool is_skinned_mesh = (fbx_node->skin >= 0 && fbx_node->mesh >= 0);
1679
const bool requires_extra_node = (fbx_node->mesh >= 0 || fbx_node->camera >= 0 || fbx_node->light >= 0);
1680
1681
Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent);
1682
if (active_skeleton != skeleton) {
1683
if (active_skeleton) {
1684
// Should no longer be possible.
1685
ERR_PRINT(vformat("FBX: Generating scene detected direct parented Skeletons at node %d", p_node_index));
1686
BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, fbx_node->parent);
1687
p_scene_parent->add_child(bone_attachment, true);
1688
bone_attachment->set_owner(p_scene_root);
1689
// There is no fbx_node that represent this, so just directly create a unique name
1690
bone_attachment->set_name(_gen_unique_name(p_state->unique_names, "BoneAttachment3D"));
1691
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
1692
// and attach it to the bone_attachment
1693
p_scene_parent = bone_attachment;
1694
}
1695
if (skeleton->get_parent() == nullptr) {
1696
p_scene_parent->add_child(skeleton, true);
1697
skeleton->set_owner(p_scene_root);
1698
}
1699
}
1700
1701
active_skeleton = skeleton;
1702
current_node = active_skeleton;
1703
if (active_skeleton) {
1704
p_scene_parent = active_skeleton;
1705
}
1706
1707
if (requires_extra_node) {
1708
current_node = nullptr;
1709
// skinned meshes must not be placed in a bone attachment.
1710
if (!is_skinned_mesh) {
1711
// Bone Attachment - Same Node Case
1712
BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index);
1713
1714
p_scene_parent->add_child(bone_attachment, true);
1715
bone_attachment->set_owner(p_scene_root);
1716
1717
// There is no fbx_node that represent this, so just directly create a unique name
1718
bone_attachment->set_name(fbx_node->get_name());
1719
1720
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
1721
// and attach it to the bone_attachment
1722
p_scene_parent = bone_attachment;
1723
}
1724
// TODO: 20240118 // fire
1725
// // Check if any GLTFDocumentExtension classes want to generate a node for us.
1726
// for (Ref<GLTFDocumentExtension> ext : document_extensions) {
1727
// ERR_CONTINUE(ext.is_null());
1728
// current_node = ext->generate_scene_node(p_state, fbx_node, p_scene_parent);
1729
// if (current_node) {
1730
// break;
1731
// }
1732
// }
1733
// If none of our GLTFDocumentExtension classes generated us a node, we generate one.
1734
if (!current_node) {
1735
if (fbx_node->mesh >= 0) {
1736
current_node = _generate_mesh_instance(p_state, p_node_index);
1737
} else if (fbx_node->camera >= 0) {
1738
current_node = _generate_camera(p_state, p_node_index);
1739
} else {
1740
current_node = _generate_spatial(p_state, p_node_index);
1741
}
1742
}
1743
// Add the node we generated and set the owner to the scene root.
1744
p_scene_parent->add_child(current_node, true);
1745
if (current_node != p_scene_root) {
1746
Array args = { p_scene_root };
1747
current_node->propagate_call(StringName("set_owner"), args);
1748
}
1749
// Do not set transform here. Transform is already applied to our bone.
1750
current_node->set_name(fbx_node->get_name());
1751
}
1752
1753
p_state->scene_nodes.insert(p_node_index, current_node);
1754
1755
for (int i = 0; i < fbx_node->children.size(); ++i) {
1756
_generate_scene_node(p_state, fbx_node->children[i], active_skeleton, p_scene_root);
1757
}
1758
}
1759
1760
void FBXDocument::_import_animation(Ref<FBXState> p_state, AnimationPlayer *p_animation_player, const GLTFAnimationIndex p_index, const bool p_trimming, const bool p_remove_immutable_tracks) {
1761
Ref<GLTFAnimation> anim = p_state->animations[p_index];
1762
1763
String anim_name = anim->get_name();
1764
if (anim_name.is_empty()) {
1765
// No node represent these, and they are not in the hierarchy, so just make a unique name
1766
anim_name = _gen_unique_name(p_state->unique_names, "Animation");
1767
}
1768
1769
Ref<Animation> animation;
1770
animation.instantiate();
1771
animation->set_name(anim_name);
1772
animation->set_step(1.0 / p_state->get_bake_fps());
1773
1774
if (anim->get_loop()) {
1775
animation->set_loop_mode(Animation::LOOP_LINEAR);
1776
}
1777
1778
Dictionary additional_animation_data = anim->get_additional_data("GODOT_animation_time_begin_time_end");
1779
1780
double anim_start_offset = p_trimming ? double(additional_animation_data["time_begin"]) : 0.0;
1781
1782
for (const KeyValue<int, GLTFAnimation::NodeTrack> &track_i : anim->get_node_tracks()) {
1783
const GLTFAnimation::NodeTrack &track = track_i.value;
1784
//need to find the path: for skeletons, weight tracks will affect the mesh
1785
NodePath node_path;
1786
//for skeletons, transform tracks always affect bones
1787
NodePath transform_node_path;
1788
GLTFNodeIndex node_index = track_i.key;
1789
Node *root = p_animation_player->get_parent();
1790
ERR_FAIL_NULL(root);
1791
HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index);
1792
ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation.", node_index));
1793
node_path = root->get_path_to(node_element->value);
1794
1795
const Ref<GLTFNode> fbx_node = p_state->nodes[track_i.key];
1796
1797
if (fbx_node->skeleton >= 0) {
1798
const Skeleton3D *sk = p_state->skeletons[fbx_node->skeleton]->godot_skeleton;
1799
ERR_FAIL_NULL(sk);
1800
1801
const String path = String(p_animation_player->get_parent()->get_path_to(sk));
1802
const String bone = fbx_node->get_name();
1803
transform_node_path = path + ":" + bone;
1804
} else {
1805
transform_node_path = node_path;
1806
}
1807
1808
// Animated TRS properties will not affect a skinned mesh.
1809
const bool transform_affects_skinned_mesh_instance = fbx_node->skeleton < 0 && fbx_node->skin >= 0;
1810
if ((track.rotation_track.values.size() || track.position_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) {
1811
// Make a transform track.
1812
int base_idx = animation->get_track_count();
1813
int position_idx = -1;
1814
int rotation_idx = -1;
1815
int scale_idx = -1;
1816
1817
if (track.position_track.values.size()) {
1818
bool is_default = true; // Discard the track if all it contains is default values.
1819
if (p_remove_immutable_tracks) {
1820
Vector3 base_pos = p_state->nodes[track_i.key]->transform.origin;
1821
for (int i = 0; i < track.position_track.times.size(); i++) {
1822
Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i];
1823
if (!value.is_equal_approx(base_pos)) {
1824
is_default = false;
1825
break;
1826
}
1827
}
1828
}
1829
if (!p_remove_immutable_tracks || !is_default) {
1830
position_idx = base_idx;
1831
animation->add_track(Animation::TYPE_POSITION_3D);
1832
animation->track_set_path(position_idx, transform_node_path);
1833
animation->track_set_imported(position_idx, true); // Helps merging positions later.
1834
base_idx++;
1835
}
1836
}
1837
if (track.rotation_track.values.size()) {
1838
bool is_default = true; // Discard the track if all the track contains is the default values.
1839
if (p_remove_immutable_tracks) {
1840
Quaternion base_rot = p_state->nodes[track_i.key]->transform.basis.get_rotation_quaternion();
1841
for (int i = 0; i < track.rotation_track.times.size(); i++) {
1842
Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized();
1843
if (!value.is_equal_approx(base_rot)) {
1844
is_default = false;
1845
break;
1846
}
1847
}
1848
}
1849
if (!p_remove_immutable_tracks || !is_default) {
1850
rotation_idx = base_idx;
1851
animation->add_track(Animation::TYPE_ROTATION_3D);
1852
animation->track_set_path(rotation_idx, transform_node_path);
1853
animation->track_set_imported(rotation_idx, true); //helps merging later
1854
base_idx++;
1855
}
1856
}
1857
if (track.scale_track.values.size()) {
1858
bool is_default = true; // Discard the track if all the track contains is the default values.
1859
if (p_remove_immutable_tracks) {
1860
Vector3 base_scale = p_state->nodes[track_i.key]->transform.basis.get_scale();
1861
for (int i = 0; i < track.scale_track.times.size(); i++) {
1862
Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i];
1863
if (!value.is_equal_approx(base_scale)) {
1864
is_default = false;
1865
break;
1866
}
1867
}
1868
}
1869
if (!p_remove_immutable_tracks || !is_default) {
1870
scale_idx = base_idx;
1871
animation->add_track(Animation::TYPE_SCALE_3D);
1872
animation->track_set_path(scale_idx, transform_node_path);
1873
animation->track_set_imported(scale_idx, true); //helps merging later
1874
base_idx++;
1875
}
1876
}
1877
1878
if (position_idx != -1) {
1879
animation->track_set_interpolation_type(position_idx, Animation::INTERPOLATION_LINEAR);
1880
for (int j = 0; j < track.position_track.times.size(); j++) {
1881
const float t = track.position_track.times[j] - anim_start_offset;
1882
const Vector3 value = track.position_track.values[j];
1883
animation->position_track_insert_key(position_idx, t, value);
1884
}
1885
}
1886
1887
if (rotation_idx != -1) {
1888
animation->track_set_interpolation_type(rotation_idx, Animation::INTERPOLATION_LINEAR);
1889
for (int j = 0; j < track.rotation_track.times.size(); j++) {
1890
const float t = track.rotation_track.times[j] - anim_start_offset;
1891
const Quaternion value = track.rotation_track.values[j];
1892
animation->rotation_track_insert_key(rotation_idx, t, value);
1893
}
1894
}
1895
1896
if (scale_idx != -1) {
1897
animation->track_set_interpolation_type(scale_idx, Animation::INTERPOLATION_LINEAR);
1898
for (int j = 0; j < track.scale_track.times.size(); j++) {
1899
const float t = track.scale_track.times[j] - anim_start_offset;
1900
const Vector3 value = track.scale_track.values[j];
1901
animation->scale_track_insert_key(scale_idx, t, value);
1902
}
1903
}
1904
}
1905
}
1906
1907
Dictionary blend_shape_animations = anim->get_additional_data("GODOT_blend_shape_animations");
1908
1909
for (GLTFNodeIndex node_index = 0; node_index < p_state->nodes.size(); node_index++) {
1910
Ref<GLTFNode> node = p_state->nodes[node_index];
1911
if (node->mesh < 0) {
1912
continue;
1913
}
1914
1915
// For meshes, especially skinned meshes, there are cases where it will be added as a child.
1916
NodePath mesh_instance_node_path;
1917
1918
Node *root = p_animation_player->get_parent();
1919
ERR_FAIL_NULL(root);
1920
HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index);
1921
ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation.", node_index));
1922
NodePath node_path = root->get_path_to(node_element->value);
1923
HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mesh_instance_element = p_state->scene_mesh_instances.find(node_index);
1924
if (mesh_instance_element) {
1925
mesh_instance_node_path = root->get_path_to(mesh_instance_element->value);
1926
} else {
1927
mesh_instance_node_path = node_path;
1928
}
1929
1930
Ref<GLTFMesh> mesh = p_state->meshes[node->mesh];
1931
ERR_CONTINUE(mesh.is_null());
1932
ERR_CONTINUE(mesh->get_mesh().is_null());
1933
ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null());
1934
1935
Dictionary mesh_additional_data = mesh->get_additional_data("GODOT_mesh_blend_channels");
1936
Vector<int> blend_channels = mesh_additional_data["blend_channels"];
1937
1938
for (int i = 0; i < blend_channels.size(); i++) {
1939
int blend_i = blend_channels[i];
1940
if (!blend_shape_animations.has(blend_i)) {
1941
continue;
1942
}
1943
Dictionary blend_track = blend_shape_animations[blend_i];
1944
1945
GLTFAnimation::Channel<real_t> weights;
1946
weights.interpolation = GLTFAnimation::INTERP_LINEAR;
1947
weights.times = blend_track["times"];
1948
weights.values = blend_track["values"];
1949
1950
const String blend_path = String(mesh_instance_node_path) + ":" + String(mesh->get_mesh()->get_blend_shape_name(i));
1951
const int track_idx = animation->get_track_count();
1952
animation->add_track(Animation::TYPE_BLEND_SHAPE);
1953
animation->track_set_path(track_idx, blend_path);
1954
animation->track_set_imported(track_idx, true); // Helps merging later.
1955
1956
animation->track_set_interpolation_type(track_idx, Animation::INTERPOLATION_LINEAR);
1957
for (int j = 0; j < weights.times.size(); j++) {
1958
const double t = weights.times[j] - anim_start_offset;
1959
const real_t attribs = weights.values[j];
1960
animation->blend_shape_track_insert_key(track_idx, t, attribs);
1961
}
1962
}
1963
}
1964
double time_begin = additional_animation_data["time_begin"];
1965
double time_end = additional_animation_data["time_end"];
1966
double length = p_trimming ? time_end - time_begin : time_end;
1967
animation->set_length(length);
1968
1969
Ref<AnimationLibrary> library;
1970
if (!p_animation_player->has_animation_library("")) {
1971
library.instantiate();
1972
p_animation_player->add_animation_library("", library);
1973
} else {
1974
library = p_animation_player->get_animation_library("");
1975
}
1976
library->add_animation(anim_name, animation);
1977
}
1978
1979
void FBXDocument::_process_mesh_instances(Ref<FBXState> p_state, Node *p_scene_root) {
1980
for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) {
1981
Ref<GLTFNode> node = p_state->nodes[node_i];
1982
1983
if (node.is_null() || !(node->skin >= 0 && node->mesh >= 0)) {
1984
continue;
1985
}
1986
1987
const GLTFSkinIndex skin_i = node->skin;
1988
1989
ImporterMeshInstance3D *mi = nullptr;
1990
HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mi_element = p_state->scene_mesh_instances.find(node_i);
1991
if (!mi_element) {
1992
HashMap<GLTFNodeIndex, Node *>::Iterator si_element = p_state->scene_nodes.find(node_i);
1993
ERR_CONTINUE_MSG(!si_element, vformat("Unable to find node %d", node_i));
1994
mi = Object::cast_to<ImporterMeshInstance3D>(si_element->value);
1995
ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, si_element->value->get_class_name()));
1996
} else {
1997
mi = mi_element->value;
1998
}
1999
2000
bool is_skin_valid = node->skin >= 0;
2001
bool is_skin_accessible = is_skin_valid && node->skin < p_state->skins.size();
2002
bool is_valid = is_skin_accessible && p_state->skins.write[node->skin]->skeleton >= 0;
2003
2004
if (!is_valid) {
2005
continue;
2006
}
2007
2008
const GLTFSkeletonIndex skel_i = p_state->skins.write[node->skin]->skeleton;
2009
Ref<GLTFSkeleton> fbx_skeleton = p_state->skeletons.write[skel_i];
2010
Skeleton3D *skeleton = fbx_skeleton->godot_skeleton;
2011
ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d", node_i, skin_i));
2012
2013
mi->get_parent()->remove_child(mi);
2014
mi->set_owner(nullptr);
2015
skeleton->add_child(mi, true);
2016
mi->set_owner(skeleton->get_owner());
2017
2018
mi->set_skin(p_state->skins.write[skin_i]->godot_skin);
2019
mi->set_skeleton_path(mi->get_path_to(skeleton));
2020
mi->set_transform(Transform3D());
2021
}
2022
}
2023
2024
Error FBXDocument::_parse(Ref<FBXState> p_state, String p_path, Ref<FileAccess> p_file) {
2025
p_state->scene.reset();
2026
2027
Error err = ERR_INVALID_DATA;
2028
if (p_file.is_null()) {
2029
return FAILED;
2030
}
2031
2032
ufbx_load_opts opts = {};
2033
opts.target_axes = ufbx_axes_right_handed_y_up;
2034
opts.target_unit_meters = 1.0f;
2035
opts.space_conversion = UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY;
2036
if (!p_state->get_allow_geometry_helper_nodes()) {
2037
opts.geometry_transform_handling = UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK;
2038
opts.inherit_mode_handling = UFBX_INHERIT_MODE_HANDLING_COMPENSATE_NO_FALLBACK;
2039
} else {
2040
opts.geometry_transform_handling = UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES;
2041
opts.inherit_mode_handling = UFBX_INHERIT_MODE_HANDLING_COMPENSATE;
2042
}
2043
opts.pivot_handling = UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT;
2044
opts.geometry_transform_helper_name.data = "GeometryTransformHelper";
2045
opts.geometry_transform_helper_name.length = SIZE_MAX;
2046
opts.scale_helper_name.data = "ScaleHelper";
2047
opts.scale_helper_name.length = SIZE_MAX;
2048
opts.node_depth_limit = 512;
2049
opts.target_camera_axes = ufbx_axes_right_handed_y_up;
2050
opts.target_light_axes = ufbx_axes_right_handed_y_up;
2051
opts.clean_skin_weights = true;
2052
if (p_state->discard_meshes_and_materials) {
2053
opts.ignore_geometry = true;
2054
opts.ignore_embedded = true;
2055
}
2056
opts.generate_missing_normals = true;
2057
2058
ThreadPoolFBX thread_pool;
2059
thread_pool.pool = WorkerThreadPool::get_singleton();
2060
2061
opts.thread_opts.pool.init_fn = &_thread_pool_init_fn;
2062
opts.thread_opts.pool.run_fn = &_thread_pool_run_fn;
2063
opts.thread_opts.pool.wait_fn = &_thread_pool_wait_fn;
2064
opts.thread_opts.pool.user = &thread_pool;
2065
opts.thread_opts.memory_limit = 64 * 1024 * 1024;
2066
2067
ufbx_error error;
2068
ufbx_stream file_stream = {};
2069
file_stream.read_fn = &_file_access_read_fn;
2070
file_stream.skip_fn = &_file_access_skip_fn;
2071
file_stream.user = p_file.ptr();
2072
p_state->scene.reset(ufbx_load_stream(&file_stream, &opts, &error));
2073
2074
if (!p_state->scene.get()) {
2075
char err_buf[512];
2076
ufbx_format_error(err_buf, sizeof(err_buf), &error);
2077
ERR_FAIL_V_MSG(ERR_PARSE_ERROR, err_buf);
2078
}
2079
2080
const int max_warning_count = 10;
2081
int warning_count[UFBX_WARNING_TYPE_COUNT] = {};
2082
int ignored_warning_count = 0;
2083
for (const ufbx_warning &warning : p_state->scene->metadata.warnings) {
2084
if (warning_count[warning.type]++ < max_warning_count) {
2085
if (warning.count > 1) {
2086
WARN_PRINT(vformat("FBX: ufbx warning: %s (x%d)", _as_string(warning.description), (int)warning.count));
2087
} else {
2088
String element_name;
2089
if (warning.element_id != UFBX_NO_INDEX) {
2090
element_name = _find_element_name(p_state->scene->elements[warning.element_id]);
2091
}
2092
if (!element_name.is_empty()) {
2093
WARN_PRINT(vformat("FBX: ufbx warning in '%s': %s", element_name, _as_string(warning.description)));
2094
} else {
2095
WARN_PRINT(vformat("FBX: ufbx warning: %s", _as_string(warning.description)));
2096
}
2097
}
2098
} else {
2099
ignored_warning_count++;
2100
}
2101
}
2102
if (ignored_warning_count > 0) {
2103
WARN_PRINT(vformat("FBX: ignored %d further ufbx warnings", ignored_warning_count));
2104
}
2105
2106
document_extensions.clear();
2107
for (Ref<GLTFDocumentExtension> ext : all_document_extensions) {
2108
ERR_CONTINUE(ext.is_null());
2109
err = ext->import_preflight(p_state, p_state->json["extensionsUsed"]);
2110
if (err == OK) {
2111
document_extensions.push_back(ext);
2112
}
2113
}
2114
2115
err = _parse_fbx_state(p_state, p_path);
2116
ERR_FAIL_COND_V(err != OK, err);
2117
2118
return OK;
2119
}
2120
2121
Node *FBXDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming, bool p_remove_immutable_tracks) {
2122
Ref<FBXState> state = p_state;
2123
ERR_FAIL_COND_V(state.is_null(), nullptr);
2124
ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr);
2125
p_state->set_bake_fps(p_bake_fps);
2126
GLTFNodeIndex fbx_root = state->root_nodes.write[0];
2127
Node *fbx_root_node = state->get_scene_node(fbx_root);
2128
Node *root = fbx_root_node;
2129
if (root && root->get_owner() && root->get_owner() != root) {
2130
root = root->get_owner();
2131
}
2132
ERR_FAIL_NULL_V(root, nullptr);
2133
_process_mesh_instances(state, root);
2134
if (state->get_create_animations() && state->animations.size()) {
2135
AnimationPlayer *ap = memnew(AnimationPlayer);
2136
root->add_child(ap, true);
2137
ap->set_owner(root);
2138
for (int i = 0; i < state->animations.size(); i++) {
2139
_import_animation(state, ap, i, p_trimming, p_remove_immutable_tracks);
2140
}
2141
}
2142
for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) {
2143
ERR_CONTINUE(!E.value);
2144
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
2145
ERR_CONTINUE(ext.is_null());
2146
Dictionary node_json;
2147
if (state->json.has("nodes")) {
2148
Array nodes = state->json["nodes"];
2149
if (0 <= E.key && E.key < nodes.size()) {
2150
node_json = nodes[E.key];
2151
}
2152
}
2153
Ref<GLTFNode> gltf_node = state->nodes[E.key];
2154
Error err = ext->import_node(p_state, gltf_node, node_json, E.value);
2155
ERR_CONTINUE(err != OK);
2156
}
2157
}
2158
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
2159
ERR_CONTINUE(ext.is_null());
2160
Error err = ext->import_post(p_state, root);
2161
ERR_CONTINUE(err != OK);
2162
}
2163
ERR_FAIL_NULL_V(root, nullptr);
2164
return root;
2165
}
2166
2167
Error FBXDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags) {
2168
Ref<FBXState> state = p_state;
2169
ERR_FAIL_COND_V(state.is_null(), ERR_INVALID_PARAMETER);
2170
ERR_FAIL_NULL_V(p_bytes.ptr(), ERR_INVALID_DATA);
2171
Error err = FAILED;
2172
state->use_named_skin_binds = p_flags & FBX_IMPORT_USE_NAMED_SKIN_BINDS;
2173
state->discard_meshes_and_materials = p_flags & FBX_IMPORT_DISCARD_MESHES_AND_MATERIALS;
2174
2175
Ref<FileAccessMemory> file_access;
2176
file_access.instantiate();
2177
file_access->open_custom(p_bytes.ptr(), p_bytes.size());
2178
state->base_path = p_base_path.get_base_dir();
2179
err = _parse(state, state->base_path, file_access);
2180
ERR_FAIL_COND_V(err != OK, err);
2181
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
2182
ERR_CONTINUE(ext.is_null());
2183
err = ext->import_post_parse(state);
2184
ERR_FAIL_COND_V(err != OK, err);
2185
}
2186
return OK;
2187
}
2188
2189
Error FBXDocument::_parse_fbx_state(Ref<FBXState> p_state, const String &p_search_path) {
2190
Error err;
2191
2192
// Abort parsing if the scene is not loaded.
2193
ERR_FAIL_NULL_V(p_state->scene.get(), ERR_PARSE_ERROR);
2194
2195
/* PARSE SCENE */
2196
err = _parse_scenes(p_state);
2197
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2198
2199
/* PARSE NODES */
2200
err = _parse_nodes(p_state);
2201
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2202
2203
if (!p_state->discard_meshes_and_materials) {
2204
/* PARSE IMAGES */
2205
err = _parse_images(p_state, p_search_path);
2206
2207
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2208
2209
/* PARSE MATERIALS */
2210
err = _parse_materials(p_state);
2211
2212
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2213
}
2214
2215
/* PARSE SKINS */
2216
err = _parse_skins(p_state);
2217
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2218
2219
/* DETERMINE SKELETONS */
2220
if (p_state->get_import_as_skeleton_bones()) {
2221
err = SkinTool::_determine_skeletons(p_state->skins, p_state->nodes, p_state->skeletons, p_state->root_nodes, true);
2222
} else {
2223
err = SkinTool::_determine_skeletons(p_state->skins, p_state->nodes, p_state->skeletons, Vector<GLTFNodeIndex>(), _naming_version < 2);
2224
}
2225
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2226
2227
/* CREATE SKELETONS */
2228
err = SkinTool::_create_skeletons(p_state->unique_names, p_state->skins, p_state->nodes, p_state->skeleton3d_to_fbx_skeleton, p_state->skeletons, p_state->scene_nodes, _naming_version);
2229
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2230
2231
/* CREATE SKINS */
2232
err = SkinTool::_create_skins(p_state->skins, p_state->nodes, p_state->use_named_skin_binds, p_state->unique_names);
2233
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2234
2235
/* PARSE MESHES (we have enough info now) */
2236
err = _parse_meshes(p_state);
2237
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2238
2239
/* PARSE LIGHTS */
2240
err = _parse_lights(p_state);
2241
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2242
2243
/* PARSE CAMERAS */
2244
err = _parse_cameras(p_state);
2245
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2246
2247
/* PARSE ANIMATIONS */
2248
err = _parse_animations(p_state);
2249
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
2250
2251
/* ASSIGN SCENE NAMES */
2252
_assign_node_names(p_state);
2253
2254
Node3D *root = memnew(Node3D);
2255
for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) {
2256
_generate_scene_node(p_state, p_state->root_nodes[root_i], root, root);
2257
}
2258
2259
return OK;
2260
}
2261
2262
Error FBXDocument::append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags, String p_base_path) {
2263
Ref<FBXState> state = p_state;
2264
ERR_FAIL_COND_V(state.is_null(), ERR_INVALID_PARAMETER);
2265
ERR_FAIL_COND_V(p_path.is_empty(), ERR_FILE_NOT_FOUND);
2266
if (p_state == Ref<FBXState>()) {
2267
p_state.instantiate();
2268
}
2269
state->filename = p_path.get_file().get_basename();
2270
state->use_named_skin_binds = p_flags & FBX_IMPORT_USE_NAMED_SKIN_BINDS;
2271
state->discard_meshes_and_materials = p_flags & FBX_IMPORT_DISCARD_MESHES_AND_MATERIALS;
2272
Error err;
2273
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err);
2274
ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN);
2275
ERR_FAIL_COND_V(file.is_null(), ERR_FILE_CANT_OPEN);
2276
String base_path = p_base_path;
2277
if (base_path.is_empty()) {
2278
base_path = p_path.get_base_dir();
2279
}
2280
state->base_path = base_path;
2281
err = _parse(p_state, base_path, file);
2282
ERR_FAIL_COND_V(err != OK, err);
2283
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
2284
ERR_CONTINUE(ext.is_null());
2285
err = ext->import_post_parse(p_state);
2286
ERR_FAIL_COND_V(err != OK, err);
2287
}
2288
return OK;
2289
}
2290
2291
void FBXDocument::_process_uv_set(PackedVector2Array &uv_array) {
2292
int uv_size = uv_array.size();
2293
for (int uv_i = 0; uv_i < uv_size; uv_i++) {
2294
Vector2 &uv = uv_array.write[uv_i];
2295
uv.y = 1.0 - uv.y;
2296
}
2297
}
2298
2299
void FBXDocument::_zero_unused_elements(Vector<float> &cur_custom, int start, int end, int num_channels) {
2300
for (int32_t uv_i = start; uv_i < end; uv_i++) {
2301
int index = uv_i * num_channels;
2302
for (int channel = 0; channel < num_channels; channel++) {
2303
cur_custom.write[index + channel] = 0;
2304
}
2305
}
2306
}
2307
2308
Error FBXDocument::_parse_lights(Ref<FBXState> p_state) {
2309
const ufbx_scene *fbx_scene = p_state->scene.get();
2310
for (size_t i = 0; i < fbx_scene->lights.count; i++) {
2311
const ufbx_light *fbx_light = fbx_scene->lights.data[i];
2312
Ref<GLTFLight> light;
2313
light.instantiate();
2314
light->set_name(_as_string(fbx_light->name));
2315
light->set_color(Color(fbx_light->color.x, fbx_light->color.y, fbx_light->color.z));
2316
light->set_intensity(fbx_light->intensity);
2317
switch (fbx_light->type) {
2318
case UFBX_LIGHT_POINT:
2319
light->set_light_type("point");
2320
break;
2321
case UFBX_LIGHT_DIRECTIONAL:
2322
light->set_light_type("directional");
2323
break;
2324
case UFBX_LIGHT_SPOT:
2325
light->set_light_type("spot");
2326
break;
2327
case UFBX_LIGHT_AREA:
2328
light->set_light_type("area");
2329
break;
2330
case UFBX_LIGHT_VOLUME:
2331
light->set_light_type("volume");
2332
break;
2333
default:
2334
light->set_light_type("unknown");
2335
break;
2336
}
2337
2338
Dictionary additional_data;
2339
additional_data["shadow"] = fbx_light->cast_shadows;
2340
if (fbx_light->decay == UFBX_LIGHT_DECAY_NONE) {
2341
additional_data["decay"] = "none";
2342
2343
} else if (fbx_light->decay == UFBX_LIGHT_DECAY_LINEAR) {
2344
additional_data["decay"] = "linear";
2345
2346
} else if (fbx_light->decay == UFBX_LIGHT_DECAY_QUADRATIC) {
2347
additional_data["decay"] = "quadratic";
2348
2349
} else if (fbx_light->decay == UFBX_LIGHT_DECAY_CUBIC) {
2350
additional_data["decay"] = "cubic";
2351
}
2352
2353
if (fbx_light->area_shape == UFBX_LIGHT_AREA_SHAPE_RECTANGLE) {
2354
additional_data["areaShape"] = "rectangle";
2355
} else if (fbx_light->area_shape == UFBX_LIGHT_AREA_SHAPE_SPHERE) {
2356
additional_data["areaShape"] = "sphere";
2357
}
2358
2359
light->set_inner_cone_angle(fbx_light->inner_angle);
2360
light->set_outer_cone_angle(fbx_light->outer_angle);
2361
2362
additional_data["castLight"] = fbx_light->cast_light;
2363
additional_data["castShadows"] = fbx_light->cast_shadows;
2364
light->set_additional_data("GODOT_fbx_light", additional_data);
2365
p_state->lights.push_back(light);
2366
}
2367
print_verbose("FBX: Total lights: " + itos(p_state->lights.size()));
2368
return OK;
2369
}
2370
2371
String FBXDocument::_get_texture_path(const String &p_base_dir, const String &p_source_file_path) const {
2372
// Check if the original path exists first.
2373
if (FileAccess::exists(p_source_file_path)) {
2374
return p_source_file_path.strip_edges();
2375
}
2376
const String tex_file_name = p_source_file_path.get_file();
2377
const Vector<String> subdirs = {
2378
"", "textures/", "Textures/", "images/",
2379
"Images/", "materials/", "Materials/",
2380
"maps/", "Maps/", "tex/", "Tex/"
2381
};
2382
String base_dir = p_base_dir;
2383
const String source_file_name = tex_file_name;
2384
while (!base_dir.is_empty()) {
2385
String old_base_dir = base_dir;
2386
for (int i = 0; i < subdirs.size(); ++i) {
2387
String full_path = base_dir.path_join(subdirs[i] + source_file_name);
2388
if (FileAccess::exists(full_path)) {
2389
return full_path.strip_edges();
2390
}
2391
}
2392
base_dir = base_dir.get_base_dir();
2393
if (base_dir == old_base_dir) {
2394
break;
2395
}
2396
}
2397
return String();
2398
}
2399
2400
Error FBXDocument::_parse_skins(Ref<FBXState> p_state) {
2401
const ufbx_scene *fbx_scene = p_state->scene.get();
2402
HashMap<GLTFNodeIndex, bool> joint_mapping;
2403
2404
for (const ufbx_skin_deformer *fbx_skin : fbx_scene->skin_deformers) {
2405
if (fbx_skin->clusters.count == 0 || fbx_skin->weights.count == 0) {
2406
p_state->skin_indices.push_back(-1);
2407
continue;
2408
}
2409
2410
Ref<GLTFSkin> skin;
2411
skin.instantiate();
2412
2413
skin->inverse_binds.resize(fbx_skin->clusters.count);
2414
for (int skin_i = 0; skin_i < static_cast<int>(fbx_skin->clusters.count); skin_i++) {
2415
const ufbx_skin_cluster *fbx_cluster = fbx_skin->clusters[skin_i];
2416
skin->inverse_binds.write[skin_i] = FBXDocument::_as_xform(fbx_cluster->geometry_to_bone);
2417
const GLTFNodeIndex node = fbx_cluster->bone_node->typed_id;
2418
2419
skin->joints.push_back(node);
2420
skin->joints_original.push_back(node);
2421
p_state->nodes.write[node]->joint = true;
2422
}
2423
2424
if (fbx_skin->name.length > 0) {
2425
skin->set_name(FBXDocument::_as_string(fbx_skin->name));
2426
} else {
2427
skin->set_name(vformat("skin_%s", itos(fbx_skin->typed_id)));
2428
}
2429
p_state->skin_indices.push_back(p_state->skins.size());
2430
p_state->skins.push_back(skin);
2431
}
2432
2433
for (const ufbx_bone *fbx_bone : fbx_scene->bones) {
2434
for (const ufbx_node *fbx_node : fbx_bone->instances) {
2435
const GLTFNodeIndex node = fbx_node->typed_id;
2436
if (!p_state->nodes.write[node]->joint) {
2437
p_state->nodes.write[node]->joint = true;
2438
2439
if (!(fbx_node->parent && fbx_node->parent->attrib_type == UFBX_ELEMENT_BONE)) {
2440
Ref<GLTFSkin> skin;
2441
skin.instantiate();
2442
skin->joints.push_back(node);
2443
skin->joints_original.push_back(node);
2444
skin->set_name(vformat("skin_%s", itos(p_state->skins.size())));
2445
p_state->skin_indices.push_back(p_state->skins.size());
2446
p_state->skins.push_back(skin);
2447
}
2448
}
2449
}
2450
}
2451
p_state->original_skin_indices = p_state->skin_indices.duplicate();
2452
Error err = SkinTool::_asset_parse_skins(
2453
p_state->original_skin_indices,
2454
p_state->skins.duplicate(),
2455
p_state->nodes.duplicate(),
2456
p_state->skin_indices,
2457
p_state->skins,
2458
joint_mapping);
2459
if (err != OK) {
2460
return err;
2461
}
2462
for (int i = 0; i < p_state->skins.size(); ++i) {
2463
Ref<GLTFSkin> skin = p_state->skins.write[i];
2464
ERR_FAIL_COND_V(skin.is_null(), ERR_PARSE_ERROR);
2465
// Expand and verify the skin
2466
ERR_FAIL_COND_V(SkinTool::_expand_skin(p_state->nodes, skin), ERR_PARSE_ERROR);
2467
ERR_FAIL_COND_V(SkinTool::_verify_skin(p_state->nodes, skin), ERR_PARSE_ERROR);
2468
}
2469
2470
print_verbose("FBX: Total skins: " + itos(p_state->skins.size()));
2471
2472
for (HashMap<GLTFNodeIndex, bool>::Iterator it = joint_mapping.begin(); it != joint_mapping.end(); ++it) {
2473
GLTFNodeIndex node_index = it->key;
2474
bool is_joint = it->value;
2475
if (is_joint) {
2476
if (p_state->nodes.size() > node_index) {
2477
p_state->nodes.write[node_index]->joint = true;
2478
}
2479
}
2480
}
2481
2482
return OK;
2483
}
2484
2485
PackedByteArray FBXDocument::generate_buffer(Ref<GLTFState> p_state) {
2486
return PackedByteArray();
2487
}
2488
2489
Error FBXDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) {
2490
return ERR_UNAVAILABLE;
2491
}
2492
2493
Error FBXDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) {
2494
return ERR_UNAVAILABLE;
2495
}
2496
2497
void FBXDocument::set_naming_version(int p_version) {
2498
_naming_version = p_version;
2499
}
2500
2501
int FBXDocument::get_naming_version() const {
2502
return _naming_version;
2503
}
2504
2505
Vector3 FBXDocument::_as_vec3(const ufbx_vec3 &p_vector) {
2506
return Vector3(real_t(p_vector.x), real_t(p_vector.y), real_t(p_vector.z));
2507
}
2508
2509
String FBXDocument::_as_string(const ufbx_string &p_string) {
2510
return String::utf8(p_string.data, (int)p_string.length);
2511
}
2512
2513
Transform3D FBXDocument::_as_xform(const ufbx_matrix &p_mat) {
2514
Transform3D xform;
2515
xform.basis.set_column(Vector3::AXIS_X, _as_vec3(p_mat.cols[0]));
2516
xform.basis.set_column(Vector3::AXIS_Y, _as_vec3(p_mat.cols[1]));
2517
xform.basis.set_column(Vector3::AXIS_Z, _as_vec3(p_mat.cols[2]));
2518
xform.set_origin(_as_vec3(p_mat.cols[3]));
2519
return xform;
2520
}
2521
2522