From 7e64c6c39973e13989ea3b0a4988f4c3da41cbda Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Thu, 31 Aug 2023 08:33:01 -0400 Subject: [PATCH] Update blender export flags for 3.6. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #76338. Blender 3.6 imports fail with: ``` TypeError: Converting py args to operator properties: : keyword "export_nla_strips" unrecognized ``` The `export_nla_strips` flag was removed and replaced with `export_animation_mode`. In 3.6.0-3.6.21, this option does not exist at all and causes the failure above. In 3.6.22, this option was re-added, but does nothing. See https://projects.blender.org/blender/blender-addons/commit/96a73cb664bca687b7ea2e464c4d08f8082d5012. We now need to check the blender version to determine what flags to use. This adds an additional shell command before every import. We might consider caching the version, but we'd have to invalidate the cache if the blender version or path changes. As an aside, the "group animations" setting in Godot does the opposite of what I'd expect. When `group_tracks=true`, each animation is exported individually. When `group_tracks=false`, all animations are exported as a single track. This seems backwards, but I've kept the 3.6 behavior consistent with 3.5. From https://docs.blender.org/api/3.6/bpy.ops.export_scene.html: > ACTIONS Actions – Export actions (actives and on NLA tracks) as separate animations. > ACTIVE_ACTIONS Active actions merged – All the currently assigned actions become one glTF animation. Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> --- .../editor/editor_scene_importer_blend.cpp | 143 ++++++++++-------- .../gltf/editor/editor_scene_importer_blend.h | 3 + 2 files changed, 82 insertions(+), 64 deletions(-) diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 91271da331ed..4967913b8565 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -48,6 +48,67 @@ #include #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 (r_err) { + *r_err = TTR("Path does not contain a Blender installation."); + } + return false; + } + List args; + args.push_back("--version"); + String pipe; + Error err = OS::get_singleton()->execute(path, args, &pipe); + if (err != OK) { + if (r_err) { + *r_err = TTR("Can't execute Blender binary."); + } + return false; + } + int bl = pipe.find("Blender "); + if (bl == -1) { + if (r_err) { + *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), path); + } + return false; + } + pipe = pipe.substr(bl); + pipe = pipe.replace_first("Blender ", ""); + int pp = pipe.find("."); + if (pp == -1) { + if (r_err) { + *r_err = TTR("Path supplied lacks a Blender binary."); + } + return false; + } + String v = pipe.substr(0, pp); + r_major = v.to_int(); + if (r_major < 3) { + if (r_err) { + *r_err = TTR("This Blender installation is too old for this importer (not 3.0+)."); + } + return false; + } + + int pp2 = pipe.find(".", pp + 1); + r_minor = pp2 > pp ? pipe.substr(pp + 1, pp2 - pp - 1).to_int() : 0; + + return true; +} + uint32_t EditorSceneFormatImporterBlend::get_import_flags() const { return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; } @@ -59,8 +120,13 @@ void EditorSceneFormatImporterBlend::get_extensions(List *r_extensions) Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags, const HashMap &p_options, List *r_missing_deps, Error *r_err) { - // Get global paths for source and sink. + String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); + if (blender_major_version == -1 || blender_minor_version == -1) { + _get_blender_version(blender_path, blender_major_version, blender_minor_version, nullptr); + } + + // Get global paths for source and sink. // Escape paths to be valid Python strings to embed in the script. const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape(); const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join( @@ -152,9 +218,17 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ parameters_map["export_tangents"] = false; } if (p_options.has(SNAME("blender/animation/group_tracks")) && p_options[SNAME("blender/animation/group_tracks")]) { - parameters_map["export_nla_strips"] = true; + if (blender_major_version > 3 || (blender_major_version == 3 && blender_minor_version >= 6)) { + parameters_map["export_animation_mode"] = "ACTIONS"; + } else { + parameters_map["export_nla_strips"] = true; + } } else { - parameters_map["export_nla_strips"] = false; + if (blender_major_version > 3 || (blender_major_version == 3 && blender_minor_version >= 6)) { + parameters_map["export_animation_mode"] = "ACTIVE_ACTIONS"; + } else { + parameters_map["export_nla_strips"] = false; + } } if (p_options.has(SNAME("blender/animation/limit_playback")) && p_options[SNAME("blender/animation/limit_playback")]) { parameters_map["export_frame_range"] = true; @@ -268,67 +342,8 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li /////////////////////////// static bool _test_blender_path(const String &p_path, 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 = path.path_join("Blender"); - } -#endif - - if (!FileAccess::exists(path)) { - if (r_err) { - *r_err = TTR("Path does not contain a Blender installation."); - } - return false; - } - List args; - args.push_back("--version"); - String pipe; - Error err = OS::get_singleton()->execute(path, args, &pipe); - if (err != OK) { - if (r_err) { - *r_err = TTR("Can't execute Blender binary."); - } - return false; - } - int bl = pipe.find("Blender "); - if (bl == -1) { - if (r_err) { - *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s"), path); - } - return false; - } - pipe = pipe.substr(bl); - pipe = pipe.replace_first("Blender ", ""); - int pp = pipe.find("."); - if (pp == -1) { - if (r_err) { - *r_err = TTR("Path supplied lacks a Blender binary."); - } - return false; - } - String v = pipe.substr(0, pp); - int version = v.to_int(); - if (version < 3) { - if (r_err) { - *r_err = TTR("This Blender installation is too old for this importer (not 3.0+)."); - } - return false; - } - if (version > 3) { - if (r_err) { - *r_err = TTR("This Blender installation is too new for this importer (not 3.x)."); - } - return false; - } - - return true; + int major, minor; + return _get_blender_version(p_path, major, minor, r_err); } bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const { diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index c77a23f9f693..ec467db457d3 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -43,6 +43,9 @@ class ConfirmationDialog; class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter { GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter); + int blender_major_version = -1; + int blender_minor_version = -1; + public: enum { BLEND_VISIBLE_ALL,