Update blender export flags for 3.6.
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 96a73cb664
.
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>
This commit is contained in:
parent
ba3fb66d71
commit
7e64c6c399
|
@ -48,6 +48,67 @@
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#endif
|
#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 {
|
uint32_t EditorSceneFormatImporterBlend::get_import_flags() const {
|
||||||
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
|
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
|
||||||
}
|
}
|
||||||
|
@ -59,8 +120,13 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions)
|
||||||
Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags,
|
Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags,
|
||||||
const HashMap<StringName, Variant> &p_options,
|
const HashMap<StringName, Variant> &p_options,
|
||||||
List<String> *r_missing_deps, Error *r_err) {
|
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.
|
// 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 source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
|
||||||
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
|
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;
|
parameters_map["export_tangents"] = false;
|
||||||
}
|
}
|
||||||
if (p_options.has(SNAME("blender/animation/group_tracks")) && p_options[SNAME("blender/animation/group_tracks")]) {
|
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 {
|
} 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")]) {
|
if (p_options.has(SNAME("blender/animation/limit_playback")) && p_options[SNAME("blender/animation/limit_playback")]) {
|
||||||
parameters_map["export_frame_range"] = true;
|
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) {
|
static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
|
||||||
String path = p_path;
|
int major, minor;
|
||||||
#ifdef WINDOWS_ENABLED
|
return _get_blender_version(p_path, major, minor, r_err);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const {
|
bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const {
|
||||||
|
|
|
@ -43,6 +43,9 @@ class ConfirmationDialog;
|
||||||
class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter {
|
class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter {
|
||||||
GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter);
|
GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter);
|
||||||
|
|
||||||
|
int blender_major_version = -1;
|
||||||
|
int blender_minor_version = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
BLEND_VISIBLE_ALL,
|
BLEND_VISIBLE_ALL,
|
||||||
|
|
Loading…
Reference in New Issue