GLTF: Add GODOT_single_root extension

This commit is contained in:
Aaron Franke 2023-07-22 22:36:57 -05:00
parent 36945dad07
commit 446893fdd1
No known key found for this signature in database
GPG key ID: 40A1750B977E56BF
5 changed files with 77 additions and 14 deletions

View file

@ -95,5 +95,20 @@
<member name="lossy_quality" type="float" setter="set_lossy_quality" getter="get_lossy_quality" default="0.75">
If [member image_format] is a lossy image format, this determines the lossy quality of the image. On a range of [code]0.0[/code] to [code]1.0[/code], where [code]0.0[/code] is the lowest quality and [code]1.0[/code] is the highest quality. A lossy quality of [code]1.0[/code] is not the same as lossless.
</member>
<member name="root_node_mode" type="int" setter="set_root_node_mode" getter="get_root_node_mode" enum="GLTFDocument.RootNodeMode" default="0">
How to process the root node during export. See [enum RootNodeMode] for details. The default and recommended value is [constant ROOT_NODE_MODE_SINGLE_ROOT].
[b]Note:[/b] Regardless of how the glTF file is exported, when importing, the root node type and name can be overridden in the scene import settings tab.
</member>
</members>
<constants>
<constant name="ROOT_NODE_MODE_SINGLE_ROOT" value="0" enum="RootNodeMode">
Treat the Godot scene's root node as the root node of the glTF file, and mark it as the single root node via the [code]GODOT_single_root[/code] glTF extension. This will be parsed the same as [constant ROOT_NODE_MODE_KEEP_ROOT] if the implementation does not support [code]GODOT_single_root[/code].
</constant>
<constant name="ROOT_NODE_MODE_KEEP_ROOT" value="1" enum="RootNodeMode">
Treat the Godot scene's root node as the root node of the glTF file, but do not mark it as anything special. An extra root node will be generated when importing into Godot. This uses only vanilla glTF features. This is equivalent to the behavior in Godot 4.1 and earlier.
</constant>
<constant name="ROOT_NODE_MODE_MULTI_ROOT" value="2" enum="RootNodeMode">
Treat the Godot scene's root node as the name of the glTF scene, and add all of its children as root nodes of the glTF file. This uses only vanilla glTF features. This avoids an extra root node, but only the name of the Godot scene's root node will be preserved, as it will not be saved as a node.
</constant>
</constants>
</class>

View file

@ -65,6 +65,7 @@
<description>
Part of the import process. This method is run after [method _import_post_parse] and before [method _import_node].
Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node.
[b]Note:[/b] The [param scene_parent] parameter may be null if this is the single root node.
</description>
</method>
<method name="_get_image_file_extension" qualifiers="virtual">

View file

@ -101,7 +101,6 @@ Error GLTFDocumentExtension::parse_texture_json(Ref<GLTFState> p_state, const Di
Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
ERR_FAIL_NULL_V(p_state, nullptr);
ERR_FAIL_NULL_V(p_gltf_node, nullptr);
ERR_FAIL_NULL_V(p_scene_parent, nullptr);
Node3D *ret_node = nullptr;
GDVIRTUAL_CALL(_generate_scene_node, p_state, p_gltf_node, p_scene_parent, ret_node);
return ret_node;

View file

@ -5883,14 +5883,18 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIn
if (!gltf_node_name.is_empty()) {
current_node->set_name(gltf_node_name);
}
// Add the node we generated and set the owner to the scene root.
p_scene_parent->add_child(current_node, true);
if (current_node != p_scene_root) {
// Note: p_scene_parent and p_scene_root must either both be null or both be valid.
if (p_scene_root == nullptr) {
// If the root node argument is null, this is the root node.
p_scene_root = current_node;
} else {
// Add the node we generated and set the owner to the scene root.
p_scene_parent->add_child(current_node, true);
Array args;
args.append(p_scene_root);
current_node->propagate_call(StringName("set_owner"), args);
current_node->set_transform(gltf_node->xform);
}
current_node->set_transform(gltf_node->xform);
p_state->scene_nodes.insert(p_node_index, current_node);
for (int i = 0; i < gltf_node->children.size(); ++i) {
@ -7219,13 +7223,20 @@ void GLTFDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"),
&GLTFDocument::write_to_filesystem);
BIND_ENUM_CONSTANT(ROOT_NODE_MODE_SINGLE_ROOT);
BIND_ENUM_CONSTANT(ROOT_NODE_MODE_KEEP_ROOT);
BIND_ENUM_CONSTANT(ROOT_NODE_MODE_MULTI_ROOT);
ClassDB::bind_method(D_METHOD("set_image_format", "image_format"), &GLTFDocument::set_image_format);
ClassDB::bind_method(D_METHOD("get_image_format"), &GLTFDocument::get_image_format);
ClassDB::bind_method(D_METHOD("set_lossy_quality", "lossy_quality"), &GLTFDocument::set_lossy_quality);
ClassDB::bind_method(D_METHOD("get_lossy_quality"), &GLTFDocument::get_lossy_quality);
ClassDB::bind_method(D_METHOD("set_root_node_mode", "root_node_mode"), &GLTFDocument::set_root_node_mode);
ClassDB::bind_method(D_METHOD("get_root_node_mode"), &GLTFDocument::get_root_node_mode);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_format"), "set_image_format", "get_image_format");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lossy_quality"), "set_lossy_quality", "get_lossy_quality");
ADD_PROPERTY(PropertyInfo(Variant::INT, "root_node_mode"), "set_root_node_mode", "get_root_node_mode");
ClassDB::bind_static_method("GLTFDocument", D_METHOD("register_gltf_document_extension", "extension", "first_priority"),
&GLTFDocument::register_gltf_document_extension, DEFVAL(false));
@ -7336,9 +7347,15 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_
}
Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
Node *single_root = memnew(Node3D);
for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) {
_generate_scene_node(p_state, p_state->root_nodes[root_i], single_root, single_root);
Node *single_root;
if (p_state->extensions_used.has("GODOT_single_root")) {
_generate_scene_node(p_state, 0, nullptr, nullptr);
single_root = p_state->scene_nodes[0];
} else {
single_root = memnew(Node3D);
for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) {
_generate_scene_node(p_state, p_state->root_nodes[root_i], single_root, single_root);
}
}
// Assign the scene name and single root name to each other
// if one is missing, or do nothing if both are already set.
@ -7406,6 +7423,19 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint
}
}
// Add the root node(s) and their descendants to the state.
if (_root_node_mode == RootNodeMode::ROOT_NODE_MODE_MULTI_ROOT) {
const int child_count = p_node->get_child_count();
if (child_count > 0) {
for (int i = 0; i < child_count; i++) {
_convert_scene_node(p_state, p_node->get_child(i), -1, -1);
}
p_state->scene_name = p_node->get_name();
return OK;
}
}
if (_root_node_mode == RootNodeMode::ROOT_NODE_MODE_SINGLE_ROOT) {
p_state->extensions_used.append("GODOT_single_root");
}
_convert_scene_node(p_state, p_node, -1, -1);
return OK;
}
@ -7598,3 +7628,11 @@ Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) {
}
return ret;
}
void GLTFDocument::set_root_node_mode(GLTFDocument::RootNodeMode p_root_node_mode) {
_root_node_mode = p_root_node_mode;
}
GLTFDocument::RootNodeMode GLTFDocument::get_root_node_mode() const {
return _root_node_mode;
}

View file

@ -40,12 +40,6 @@ class GLTFDocument : public Resource {
static Vector<Ref<GLTFDocumentExtension>> all_document_extensions;
Vector<Ref<GLTFDocumentExtension>> document_extensions;
private:
const float BAKE_FPS = 30.0f;
String _image_format = "PNG";
float _lossy_quality = 0.75f;
Ref<GLTFDocumentExtension> _image_save_extension;
public:
const int32_t JOINT_GROUP_SIZE = 4;
@ -71,6 +65,18 @@ public:
TEXTURE_TYPE_GENERIC = 0,
TEXTURE_TYPE_NORMAL = 1,
};
enum RootNodeMode {
ROOT_NODE_MODE_SINGLE_ROOT,
ROOT_NODE_MODE_KEEP_ROOT,
ROOT_NODE_MODE_MULTI_ROOT,
};
private:
const float BAKE_FPS = 30.0f;
String _image_format = "PNG";
float _lossy_quality = 0.75f;
Ref<GLTFDocumentExtension> _image_save_extension;
RootNodeMode _root_node_mode = RootNodeMode::ROOT_NODE_MODE_SINGLE_ROOT;
protected:
static void _bind_methods();
@ -84,6 +90,8 @@ public:
String get_image_format() const;
void set_lossy_quality(float p_lossy_quality);
float get_lossy_quality() const;
void set_root_node_mode(RootNodeMode p_root_node_mode);
RootNodeMode get_root_node_mode() const;
private:
void _build_parent_hierachy(Ref<GLTFState> p_state);
@ -379,4 +387,6 @@ public:
Error _parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file);
};
VARIANT_ENUM_CAST(GLTFDocument::RootNodeMode);
#endif // GLTF_DOCUMENT_H