Merge pull request #81851 from aaronfranke/gltf-single-root
GLTF: Add root node export options and GODOT_single_root extension
This commit is contained in:
commit
dc14f02892
5 changed files with 77 additions and 14 deletions
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue