Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ufbx for FBX importing #81746

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions COPYRIGHT.txt
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,11 @@ Copyright: 2014-2021, Syoyo Fujita
2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
License: BSD-3-clause

Files: ./thirdparty/ufbx/
Comment: ufbx
Copyright: 2020, Samuli Raivio
License: Expat

Files: ./thirdparty/vhacd/
Comment: V-HACD
Copyright: 2011, Khaled Mamou
Expand Down
4 changes: 2 additions & 2 deletions doc/classes/EditorSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,9 @@
The maximum idle uptime (in seconds) of the Blender process.
This prevents Godot from having to create a new process for each import within the given seconds.
</member>
<member name="filesystem/import/fbx/fbx2gltf_path" type="String" setter="" getter="">
<member name="filesystem/import/fbx2gltf/fbx2gltf_path" type="String" setter="" getter="">
The path to the FBX2glTF executable used for converting Autodesk FBX 3D scene files [code].fbx[/code] to glTF 2.0 format during import.
To enable this feature for your specific project, use [member ProjectSettings.filesystem/import/fbx/enabled].
To enable this feature for your specific project, use [member ProjectSettings.filesystem/import/fbx2gltf/enabled].
</member>
<member name="filesystem/on_save/compress_binary_resources" type="bool" setter="" getter="">
If [code]true[/code], uses lossless compression for binary resources.
Expand Down
12 changes: 6 additions & 6 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -984,15 +984,15 @@
<member name="filesystem/import/blender/enabled.web" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/blender/enabled] on the Web where Blender can't easily be accessed from Godot.
</member>
<member name="filesystem/import/fbx/enabled" type="bool" setter="" getter="" default="true">
<member name="filesystem/import/fbx2gltf/enabled" type="bool" setter="" getter="" default="true">
If [code]true[/code], Autodesk FBX 3D scene files with the [code].fbx[/code] extension will be imported by converting them to glTF 2.0.
This requires configuring a path to a FBX2glTF executable in the editor settings at [code]filesystem/import/fbx/fbx2gltf_path[/code].
This requires configuring a path to a FBX2glTF executable in the editor settings at [member EditorSettings.filesystem/import/fbx2gltf/fbx2gltf_path].
</member>
<member name="filesystem/import/fbx/enabled.android" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/fbx/enabled] on Android where FBX2glTF can't easily be accessed from Godot.
<member name="filesystem/import/fbx2gltf/enabled.android" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/fbx2gltf/enabled] on Android where FBX2glTF can't easily be accessed from Godot.
</member>
<member name="filesystem/import/fbx/enabled.web" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/fbx/enabled] on the Web where FBX2glTF can't easily be accessed from Godot.
<member name="filesystem/import/fbx2gltf/enabled.web" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/fbx2gltf/enabled] on the Web where FBX2glTF can't easily be accessed from Godot.
</member>
<member name="gui/common/default_scroll_deadzone" type="int" setter="" getter="" default="0">
Default value for [member ScrollContainer.scroll_deadzone], which will be used for all [ScrollContainer]s unless overridden.
Expand Down
2 changes: 1 addition & 1 deletion editor/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/blender/blender_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_port", 6011, "0,65535,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_server_uptime", 5, "0,300,1,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx2gltf/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)

// Tools (denoise)
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/tools/oidn/oidn_denoise_path", "", "", PROPERTY_USAGE_DEFAULT)
Expand Down
12 changes: 6 additions & 6 deletions editor/fbx_importer_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void FBXImporterManager::_notification(int p_what) {
}

void FBXImporterManager::show_dialog(bool p_exclusive) {
String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path");
String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx2gltf/fbx2gltf_path");
fbx_path->set_text(fbx2gltf_path);
_validate_path(fbx2gltf_path);

Expand All @@ -56,8 +56,8 @@ void FBXImporterManager::show_dialog(bool p_exclusive) {
set_close_on_escape(!p_exclusive);

if (is_importing) {
get_cancel_button()->set_text(TTR("Disable FBX & Restart"));
get_cancel_button()->set_tooltip_text(TTR("Canceling this dialog will disable the FBX importer.\nYou can re-enable it in the Project Settings under Filesystem > Import > FBX > Enabled.\n\nThe editor will restart as importers are registered when the editor starts."));
get_cancel_button()->set_text(TTR("Disable FBX2glTF & Restart"));
get_cancel_button()->set_tooltip_text(TTR("Canceling this dialog will disable the FBX2glTF importer and use the ufbx importer.\nYou can re-enable FBX2glTF in the Project Settings under Filesystem > Import > FBX > Enabled.\n\nThe editor will restart as importers are registered when the editor starts."));
} else {
get_cancel_button()->set_text(TTR("Cancel"));
get_cancel_button()->set_tooltip_text("");
Expand Down Expand Up @@ -105,7 +105,7 @@ void FBXImporterManager::_select_file(const String &p_path) {

void FBXImporterManager::_path_confirmed() {
String path = fbx_path->get_text();
EditorSettings::get_singleton()->set("filesystem/import/fbx/fbx2gltf_path", path);
EditorSettings::get_singleton()->set("filesystem/import/fbx2gltf/fbx2gltf_path", path);
EditorSettings::get_singleton()->save();
}

Expand All @@ -114,7 +114,7 @@ void FBXImporterManager::_cancel_setup() {
return; // No worry.
}
// No escape.
ProjectSettings::get_singleton()->set("filesystem/import/fbx/enabled", false);
ProjectSettings::get_singleton()->set("filesystem/import/fbx2gltf/enabled", false);
ProjectSettings::get_singleton()->save();
EditorNode::get_singleton()->save_all_scenes();
EditorNode::get_singleton()->restart_editor();
Expand All @@ -136,7 +136,7 @@ FBXImporterManager::FBXImporterManager() {
set_title(TTR("Configure FBX Importer"));

VBoxContainer *vb = memnew(VBoxContainer);
vb->add_child(memnew(Label(TTR("FBX2glTF is required for importing FBX files.\nPlease download it and provide a valid path to the binary:"))));
vb->add_child(memnew(Label(TTR("FBX2glTF is required for importing FBX files if using FBX2glTF.\nAlternatively, you can use ufbx by disabling FBX2glTF.\nPlease download the necessary tool and provide a valid path to the binary:"))));
LinkButton *lb = memnew(LinkButton);
lb->set_text(TTR("Click this link to download FBX2glTF"));
lb->set_uri("https://godotengine.org/fbx-import");
Expand Down
29 changes: 17 additions & 12 deletions editor/import/3d/post_import_plugin_skeleton_renamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p
return;
}
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);

// Rename bones in Skeleton3D.
{
if (skeleton) {
fire marked this conversation as resolved.
Show resolved Hide resolved
// Rename bones in Skeleton3D.
int len = skeleton->get_bone_count();
for (int i = 0; i < len; i++) {
StringName bn = p_rename_map[skeleton->get_bone_name(i)];
if (bn) {
skeleton->set_bone_name(i, bn);
String current_bone_name = skeleton->get_bone_name(i);
const HashMap<String, String>::ConstIterator new_bone_name = p_rename_map.find(current_bone_name);
if (new_bone_name) {
skeleton->set_bone_name(i, new_bone_name->value);
}
}
}
Expand All @@ -76,10 +76,13 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p
Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
if (mesh_skeleton && node == skeleton) {
int len = skin->get_bind_count();

for (int i = 0; i < len; i++) {
StringName bn = p_rename_map[skin->get_bind_name(i)];
if (bn) {
skin->set_bind_name(i, bn);
String current_bone_name = skin->get_bind_name(i);
const HashMap<String, String>::ConstIterator new_bone_name = p_rename_map.find(current_bone_name);

if (new_bone_name) {
skin->set_bind_name(i, new_bone_name->value);
}
}
}
Expand Down Expand Up @@ -107,9 +110,11 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p
if (node) {
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
if (track_skeleton && track_skeleton == skeleton) {
StringName bn = p_rename_map[anim->track_get_path(i).get_subname(0)];
if (bn) {
anim->track_set_path(i, track_path + ":" + bn);
String current_bone_name = anim->track_get_path(i).get_subname(0);
const HashMap<String, String>::ConstIterator new_bone_name = p_rename_map.find(current_bone_name);
if (new_bone_name) {
String new_track_path = track_path + ":" + new_bone_name->value;
anim->track_set_path(i, new_track_path);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion editor/import/3d/resource_importer_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,9 @@ void _apply_scale_to_scalable_node_collection(ScalableNodeCollection &p_collecti
if (skeleton_3d) {
for (int i = 0; i < skeleton_3d->get_bone_count(); i++) {
Transform3D rest = skeleton_3d->get_bone_rest(i);
Vector3 position = skeleton_3d->get_bone_pose_position(i);
skeleton_3d->set_bone_rest(i, Transform3D(rest.basis, p_scale * rest.origin));
skeleton_3d->set_bone_pose_position(i, p_scale * rest.origin);
skeleton_3d->set_bone_pose_position(i, p_scale * position);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion editor/project_converter_3_to_4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ bool ProjectConverter3To4::test_array_names() {

// Callable is special class, to which normal classes may be renamed.
if (!ClassDB::class_exists(StringName(new_class)) && new_class != "Callable") {
ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4, so it cannot be used in the conversion.", old_class));
ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4, so it cannot be used in the conversion.", new_class));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR, but I triggered that bug while renaming EditorSceneFormatImporterFBX to EditorSceneFormatImporterFBX2GLTF, so I figured I'd fix it too.

valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
}
}
Expand Down
2 changes: 1 addition & 1 deletion editor/renames_map_3_to_4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ const char *RenamesMap3To4::class_renames[][2] = {
{ "DynamicFontData", "FontFile" },
{ "EditorNavigationMeshGenerator", "NavigationMeshGenerator" },
{ "EditorSceneImporter", "EditorSceneFormatImporter" },
{ "EditorSceneImporterFBX", "EditorSceneFormatImporterFBX" },
{ "EditorSceneImporterFBX", "EditorSceneFormatImporterFBX2GLTF" },
{ "EditorSceneImporterGLTF", "EditorSceneFormatImporterGLTF" },
{ "EditorSpatialGizmo", "EditorNode3DGizmo" },
{ "EditorSpatialGizmoPlugin", "EditorNode3DGizmoPlugin" },
Expand Down
11 changes: 11 additions & 0 deletions misc/extension_api_validation/4.2-stable.expected
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,14 @@ Validate extension JSON: Error: Field 'classes/Window/methods/has_theme_stylebox
Fix the default parameter value for StringName and Variant.
The changes to StringName parameters should be equivalent to the previous default values.
The change to the Variant parameter in 'add_code_completion_option' breaks behavior compatibility.


GH-81746
--------
Validate extension JSON: API was removed: classes/EditorSceneFormatImporterFBX

Renamed to EditorSceneFormatImporterFBX2GLTF.

The compat breakage was deemed necessary as this is a class most users wouldn't
use directly, and the name needs to be disambiguated with the new
EditorSceneFormatImporterUFBX.
48 changes: 48 additions & 0 deletions modules/fbx/SCsub
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python

Import("env")
Import("env_modules")

env_fbx = env_modules.Clone()

# Thirdparty source files

thirdparty_obj = []

thirdparty_dir = "#thirdparty/ufbx/"
thirdparty_sources = [thirdparty_dir + "ufbx.c"]

env_fbx.Prepend(CPPPATH=[thirdparty_dir])

env_thirdparty = env_fbx.Clone()
env_thirdparty.disable_warnings()

env_thirdparty.Append(
CPPDEFINES=[
"UFBX_NO_SUBDIVISION",
"UFBX_NO_TESSELLATION",
"UFBX_NO_GEOMETRY_CACHE",
"UFBX_NO_SCENE_EVALUATION",
"UFBX_NO_INDEX_GENERATION",
"UFBX_NO_SKINNING_EVALUATION",
"UFBX_NO_FORMAT_OBJ",
]
)

env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.modules_sources += thirdparty_obj

# Godot source files

module_obj = []

env_fbx.add_source_files(module_obj, "*.cpp")
env_fbx.add_source_files(module_obj, "structures/*.cpp")

if env.editor_build:
env_fbx.add_source_files(module_obj, "editor/*.cpp")

env.modules_sources += module_obj

# Needed to force rebuilding the module files when the thirdparty library is updated.
env.Depends(module_obj, thirdparty_obj)
20 changes: 20 additions & 0 deletions modules/fbx/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
def can_build(env, platform):
env.module_add_dependencies("fbx", ["gltf"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the tight coupling between fbx and gltf explicit. fbx can't be compiled without gltf (but gltf can be compiled without fbx, after I moved FBX2glTF here due to the introduced coupling).

return not env["disable_3d"]


def configure(env):
pass


def get_doc_classes():
return [
"EditorSceneFormatImporterFBX2GLTF",
"EditorSceneFormatImporterUFBX",
"FBXDocument",
"FBXState",
]


def get_doc_path():
return "doc_classes"
13 changes: 13 additions & 0 deletions modules/fbx/doc_classes/EditorSceneFormatImporterFBX2GLTF.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorSceneFormatImporterFBX2GLTF" inherits="EditorSceneFormatImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Importer for the [code].fbx[/code] scene file format.
</brief_description>
<description>
Imports Autodesk FBX 3D scenes by way of converting them to glTF 2.0 using the FBX2glTF command line tool.
The location of the FBX2glTF binary is set via the [member EditorSettings.filesystem/import/fbx2gltf/fbx2gltf_path] editor setting.
This importer is only used if [member ProjectSettings.filesystem/import/fbx2gltf/enabled] is set to [code]true[/code].
</description>
<tutorials>
</tutorials>
</class>
11 changes: 11 additions & 0 deletions modules/fbx/doc_classes/EditorSceneFormatImporterUFBX.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
fire marked this conversation as resolved.
Show resolved Hide resolved
<class name="EditorSceneFormatImporterUFBX" inherits="EditorSceneFormatImporter" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Import FBX files using the ufbx library.
</brief_description>
<description>
EditorSceneFormatImporterUFBX is designed to load FBX files and supports both binary and ASCII FBX files from version 3000 onward. This class supports various 3D object types like meshes, skins, blend shapes, materials, and rigging information. The class aims for feature parity with the official FBX SDK and supports FBX 7.4 specifications.
</description>
<tutorials>
</tutorials>
</class>
12 changes: 12 additions & 0 deletions modules/fbx/doc_classes/FBXDocument.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="FBXDocument" inherits="GLTFDocument" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Handles FBX documents.
</brief_description>
<description>
The FBXDocument handles FBX documents. It provides methods to append data from buffers or files, generate scenes, and register/unregister document extensions.
fire marked this conversation as resolved.
Show resolved Hide resolved
When exporting FBX from Blender, use the "FBX Units Scale" option. The "FBX Units Scale" option sets the correct scale factor and avoids manual adjustments when re-importing into Blender, such as through glTF export.
</description>
<tutorials>
</tutorials>
</class>
15 changes: 15 additions & 0 deletions modules/fbx/doc_classes/FBXState.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="FBXState" inherits="GLTFState" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
The FBXState handles the state data imported from FBX files.
</description>
<tutorials>
</tutorials>
<members>
<member name="allow_geometry_helper_nodes" type="bool" setter="set_allow_geometry_helper_nodes" getter="get_allow_geometry_helper_nodes" default="false">
If [code]true[/code], the import process used auxiliary nodes called geometry helper nodes. These nodes help preserve the pivots and transformations of the original 3D model during import.
</member>
</members>
</class>
Loading
Loading