Skip to content

Commit

Permalink
Update blender export flags for 3.6.
Browse files Browse the repository at this point in the history
Fixes godotengine#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>
(cherry picked from commit 7e64c6c)
  • Loading branch information
rcorre authored and YuriSizov committed Oct 24, 2023
1 parent 578fa86 commit c93d74a
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 64 deletions.
143 changes: 79 additions & 64 deletions modules/gltf/editor/editor_scene_importer_blend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,67 @@
#include <shlwapi.h>
#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<String> 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;
}
Expand All @@ -59,8 +120,13 @@ 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) {
// 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(
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> 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 {
Expand Down
3 changes: 3 additions & 0 deletions modules/gltf/editor/editor_scene_importer_blend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit c93d74a

Please sign in to comment.