Update blender_path behavior to require exact path to executable instead of trying to guess it

This commit is contained in:
mxaddict 2023-11-28 17:56:04 +08:00
parent 17e7f85c06
commit ad106a283b
8 changed files with 99 additions and 120 deletions

View file

@ -495,7 +495,7 @@
<member name="filesystem/file_dialog/thumbnail_size" type="int" setter="" getter="">
The thumbnail size to use in the editor's file dialogs (in pixels). See also [member docks/filesystem/thumbnail_size].
</member>
<member name="filesystem/import/blender/blender3_path" type="String" setter="" getter="">
<member name="filesystem/import/blender/blender_path" type="String" setter="" getter="">
The path to the directory containing the Blender executable used for converting the Blender 3D scene files [code].blend[/code] to glTF 2.0 format during import. Blender 3.0 or later is required.
To enable this feature for your specific project, use [member ProjectSettings.filesystem/import/blender/enabled].
</member>

View file

@ -943,7 +943,7 @@
</member>
<member name="filesystem/import/blender/enabled" type="bool" setter="" getter="" default="true">
If [code]true[/code], Blender 3D scene files with the [code].blend[/code] extension will be imported by converting them to glTF 2.0.
This requires configuring a path to a Blender executable in the editor settings at [code]filesystem/import/blender/blender3_path[/code]. Blender 3.0 or later is required.
This requires configuring a path to a Blender executable in the editor settings at [code]filesystem/import/blender/blender_path[/code]. Blender 3.0 or later is required.
</member>
<member name="filesystem/import/blender/enabled.android" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/blender/enabled] on Android where Blender can't easily be accessed from Godot.

View file

@ -520,7 +520,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/file_dialog/thumbnail_size", 64, "32,128,16")
// Import (for glft module)
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/import/blender/blender3_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
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)

View file

@ -5,7 +5,7 @@
</brief_description>
<description>
Imports Blender scenes in the [code].blend[/code] file format through the glTF 2.0 3D import pipeline. This importer requires Blender to be installed by the user, so that it can be used to export the scene as glTF 2.0.
The location of the Blender binary is set via the [code]filesystem/import/blender/blender3_path[/code] editor setting.
The location of the Blender binary is set via the [code]filesystem/import/blender/blender_path[/code] editor setting.
This importer is only used if [member ProjectSettings.filesystem/import/blender/enabled] is enabled, otherwise [code].blend[/code] files present in the project folder are not imported.
Blend import requires Blender 3.0.
Internally, the EditorSceneFormatImporterBlend uses the Blender glTF "Use Original" mode to reference external textures.

View file

@ -153,13 +153,7 @@ String dict_to_xmlrpc(const Dictionary &p_dict) {
}
Error EditorImportBlendRunner::start_blender(const String &p_python_script, bool p_blocking) {
String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
#ifdef WINDOWS_ENABLED
blender_path = blender_path.path_join("blender.exe");
#else
blender_path = blender_path.path_join("blender");
#endif
String blender_path = EDITOR_GET("filesystem/import/blender/blender_path");
List<String> args;
args.push_back("--background");

View file

@ -55,20 +55,7 @@
#endif
static bool _get_blender_version(const String &p_path, int &r_major, int &r_minor, String *r_err = nullptr) {
String path = p_path;
#ifdef WINDOWS_ENABLED
path = path.path_join("blender.exe");
#else
path = path.path_join("blender");
#endif
#if defined(MACOS_ENABLED)
if (!FileAccess::exists(path)) {
path = p_path.path_join("Blender");
}
#endif
if (!FileAccess::exists(path)) {
if (!FileAccess::exists(p_path)) {
if (r_err) {
*r_err = TTR("Path does not contain a Blender installation.");
}
@ -77,7 +64,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino
List<String> args;
args.push_back("--version");
String pipe;
Error err = OS::get_singleton()->execute(path, args, &pipe);
Error err = OS::get_singleton()->execute(p_path, args, &pipe);
if (err != OK) {
if (r_err) {
*r_err = TTR("Can't execute Blender binary.");
@ -87,7 +74,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino
int bl = pipe.find("Blender ");
if (bl == -1) {
if (r_err) {
*r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), path);
*r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), p_path);
}
return false;
}
@ -126,7 +113,7 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions)
Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags,
const HashMap<StringName, Variant> &p_options,
List<String> *r_missing_deps, Error *r_err) {
String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
String blender_path = EDITOR_GET("filesystem/import/blender/blender_path");
if (blender_major_version == -1 || blender_minor_version == -1) {
_get_blender_version(blender_path, blender_major_version, blender_minor_version, nullptr);
@ -369,7 +356,7 @@ static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const {
bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
if (blend_enabled && !_test_blender_path(EDITOR_GET("filesystem/import/blender/blender3_path").operator String())) {
if (blend_enabled && !_test_blender_path(EDITOR_GET("filesystem/import/blender/blender_path").operator String())) {
// Intending to import Blender, but blend not configured.
return true;
}
@ -409,11 +396,59 @@ void EditorFileSystemImportFormatSupportQueryBlend::_validate_path(String p_path
}
}
bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path(String p_path) {
if (_test_blender_path(p_path)) {
auto_detected_path = p_path;
return true;
bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path() {
// Autodetect
auto_detected_path = "";
#if defined(MACOS_ENABLED)
Vector<String> find_paths = {
"/opt/homebrew/bin/blender",
"/opt/local/bin/blender",
"/usr/local/bin/blender",
"/usr/local/opt/blender",
"/Applications/Blender.app/Contents/MacOS/Blender",
};
{
List<String> mdfind_args;
mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender");
String output;
Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output);
if (err == OK) {
for (const String &find_path : output.split("\n")) {
find_paths.push_back(find_path.path_join("Contents/MacOS/Blender"));
}
}
}
#elif defined(WINDOWS_ENABLED)
Vector<String> find_paths = {
"C:\\Program Files\\Blender Foundation\\blender.exe",
"C:\\Program Files (x86)\\Blender Foundation\\blender.exe",
};
{
char blender_opener_path[MAX_PATH];
DWORD path_len = MAX_PATH;
HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len);
if (res == S_OK) {
find_paths.push_back(String(blender_opener_path).get_base_dir().path_join("blender.exe"));
}
}
#elif defined(UNIX_ENABLED)
Vector<String> find_paths = {
"/usr/bin/blender",
"/usr/local/bin/blender",
"/opt/blender/bin/blender",
};
#endif
for (const String &find_path : find_paths) {
if (_test_blender_path(find_path)) {
auto_detected_path = find_path;
return true;
}
}
return false;
}
@ -427,7 +462,7 @@ void EditorFileSystemImportFormatSupportQueryBlend::_select_install(String p_pat
}
void EditorFileSystemImportFormatSupportQueryBlend::_browse_install() {
if (blender_path->get_text() != String()) {
browse_dialog->set_current_dir(blender_path->get_text());
browse_dialog->set_current_file(blender_path->get_text());
}
browse_dialog->popup_centered_ratio();
@ -479,76 +514,10 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() {
EditorNode::get_singleton()->get_gui_base()->add_child(browse_dialog);
}
String path = EDITOR_GET("filesystem/import/blender/blender3_path");
String path = EDITOR_GET("filesystem/import/blender/blender_path");
if (path == "") {
// Autodetect
auto_detected_path = "";
#if defined(MACOS_ENABLED)
{
Vector<String> mdfind_paths;
{
List<String> mdfind_args;
mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender");
String output;
Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output);
if (err == OK) {
mdfind_paths = output.split("\n");
}
}
bool found = false;
for (const String &found_path : mdfind_paths) {
found = _autodetect_path(found_path.path_join("Contents/MacOS"));
if (found) {
break;
}
}
if (!found) {
found = _autodetect_path("/opt/homebrew/bin");
}
if (!found) {
found = _autodetect_path("/opt/local/bin");
}
if (!found) {
found = _autodetect_path("/usr/local/bin");
}
if (!found) {
found = _autodetect_path("/usr/local/opt");
}
if (!found) {
found = _autodetect_path("/Applications/Blender.app/Contents/MacOS");
}
}
#elif defined(WINDOWS_ENABLED)
{
char blender_opener_path[MAX_PATH];
DWORD path_len = MAX_PATH;
HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len);
if (res == S_OK && _autodetect_path(String(blender_opener_path).get_base_dir())) {
// Good.
} else if (_autodetect_path("C:\\Program Files\\Blender Foundation")) {
// Good.
} else {
_autodetect_path("C:\\Program Files (x86)\\Blender Foundation");
}
}
#elif defined(UNIX_ENABLED)
if (_autodetect_path("/usr/bin")) {
// Good.
} else if (_autodetect_path("/usr/local/bin")) {
// Good
} else {
_autodetect_path("/opt/blender/bin");
}
#endif
if (auto_detected_path != "") {
path = auto_detected_path;
}
if (path.is_empty() && _autodetect_path()) {
path = auto_detected_path;
}
blender_path->set_text(path);
@ -569,7 +538,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() {
if (confirmed) {
// Can only confirm a valid path.
EditorSettings::get_singleton()->set("filesystem/import/blender/blender3_path", blender_path->get_text());
EditorSettings::get_singleton()->set("filesystem/import/blender/blender_path", blender_path->get_text());
EditorSettings::get_singleton()->save();
} else {
// Disable Blender import

View file

@ -95,7 +95,7 @@ class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImp
String auto_detected_path;
void _validate_path(String p_path);
bool _autodetect_path(String p_path);
bool _autodetect_path();
void _path_confirmed();

View file

@ -55,23 +55,39 @@ static void _editor_init() {
// Blend to glTF importer.
bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
String blender3_path = EDITOR_GET("filesystem/import/blender/blender3_path");
if (blend_enabled) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (blender3_path.is_empty()) {
WARN_PRINT(TTR("Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported."));
} else if (!da->dir_exists(blender3_path)) {
WARN_PRINT(TTR("Blend file import is enabled, but the Blender path doesn't point to an accessible directory. Blend files will not be imported."));
} else {
Ref<EditorSceneFormatImporterBlend> importer;
importer.instantiate();
ResourceImporterScene::add_scene_importer(importer);
String blender_path = EDITOR_GET("filesystem/import/blender/blender_path");
if (blender_path.is_empty() && EditorSettings::get_singleton()->has_setting("filesystem/import/blender/blender3_path")) {
blender_path = EditorSettings::get_singleton()->get("filesystem/import/blender/blender3_path");
Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
blend_import_query.instantiate();
EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query);
if (!blender_path.is_empty()) {
#if defined(MACOS_ENABLED)
if (blender_path.contains(".app")) {
blender_path += "/Contents/MacOS/Blender";
} else {
blender_path += "/blender";
}
#elif defined(WINDOWS_ENABLED)
blender_path += "\\blender.exe";
#elif defined(UNIX_ENABLED)
blender_path += "/blender";
#endif
EditorSettings::get_singleton()->set("filesystem/import/blender/blender_path", blender_path);
}
EditorSettings::get_singleton()->erase("filesystem/import/blender/blender3_path");
EditorSettings::get_singleton()->save();
}
bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
if (blend_enabled) {
Ref<EditorSceneFormatImporterBlend> importer;
importer.instantiate();
ResourceImporterScene::add_scene_importer(importer);
Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
blend_import_query.instantiate();
EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query);
}
memnew(EditorImportBlendRunner);
EditorNode::get_singleton()->add_child(EditorImportBlendRunner::get_singleton());