浏览代码

Merge pull request #79316 from aaronfranke/gltf-export

Add export settings to the export dialog for GLTF
Rémi Verschelde 1 年之前
父节点
当前提交
0f0106c101

+ 1 - 1
modules/gltf/doc_classes/GLTFDocument.xml

@@ -84,7 +84,7 @@
 			<param index="1" name="path" type="String" />
 			<param index="1" name="path" type="String" />
 			<description>
 			<description>
 				Takes a [GLTFState] object through the [param state] parameter and writes a glTF file to the filesystem.
 				Takes a [GLTFState] object through the [param state] parameter and writes a glTF file to the filesystem.
-				[b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf file.
+				[b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf text file.
 			</description>
 			</description>
 		</method>
 		</method>
 	</methods>
 	</methods>

+ 48 - 33
modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp

@@ -32,12 +32,14 @@
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 
 
-#include "../gltf_document.h"
+#include "editor_scene_exporter_gltf_settings.h"
 
 
 #include "editor/editor_file_system.h"
 #include "editor/editor_file_system.h"
+#include "editor/editor_inspector.h"
 #include "editor/editor_node.h"
 #include "editor/editor_node.h"
+#include "editor/editor_scale.h"
 #include "editor/gui/editor_file_dialog.h"
 #include "editor/gui/editor_file_dialog.h"
-#include "scene/gui/popup_menu.h"
+#include "editor/import/scene_import_settings.h"
 
 
 String SceneExporterGLTFPlugin::get_name() const {
 String SceneExporterGLTFPlugin::get_name() const {
 	return "ConvertGLTF2";
 	return "ConvertGLTF2";
@@ -48,59 +50,72 @@ bool SceneExporterGLTFPlugin::has_main_screen() const {
 }
 }
 
 
 SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() {
 SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() {
-	file_export_lib = memnew(EditorFileDialog);
-	EditorNode::get_singleton()->get_gui_base()->add_child(file_export_lib);
-	file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action));
-	file_export_lib->set_title(TTR("Export Library"));
-	file_export_lib->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
-	file_export_lib->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
-	file_export_lib->clear_filters();
-	file_export_lib->add_filter("*.glb");
-	file_export_lib->add_filter("*.gltf");
-	file_export_lib->set_title(TTR("Export Scene to glTF 2.0 File"));
-
+	_gltf_document.instantiate();
+	// Set up the file dialog.
+	_file_dialog = memnew(EditorFileDialog);
+	_file_dialog->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_export_scene_as_gltf));
+	_file_dialog->set_title(TTR("Export Library"));
+	_file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+	_file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+	_file_dialog->clear_filters();
+	_file_dialog->add_filter("*.glb");
+	_file_dialog->add_filter("*.gltf");
+	_file_dialog->set_title(TTR("Export Scene to glTF 2.0 File"));
+	EditorNode::get_singleton()->get_gui_base()->add_child(_file_dialog);
+	// Set up the export settings menu.
+	_export_settings.instantiate();
+	_export_settings->generate_property_list(_gltf_document);
+	_settings_inspector = memnew(EditorInspector);
+	_settings_inspector->set_custom_minimum_size(Size2(350, 300) * EDSCALE);
+	_file_dialog->add_side_menu(_settings_inspector, TTR("Export Settings:"));
+	// Add a button to the Scene -> Export menu to pop up the settings dialog.
 	PopupMenu *menu = get_export_as_menu();
 	PopupMenu *menu = get_export_as_menu();
 	int idx = menu->get_item_count();
 	int idx = menu->get_item_count();
 	menu->add_item(TTR("glTF 2.0 Scene..."));
 	menu->add_item(TTR("glTF 2.0 Scene..."));
-	menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2));
+	menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::_popup_gltf_export_dialog));
+}
+
+void SceneExporterGLTFPlugin::_popup_gltf_export_dialog() {
+	Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root();
+	if (!root) {
+		EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
+		return;
+	}
+	// Set the file dialog's file name to the scene name.
+	String filename = String(root->get_scene_file_path().get_file().get_basename());
+	if (filename.is_empty()) {
+		filename = root->get_name();
+	}
+	_file_dialog->set_current_file(filename + String(".gltf"));
+	// Generate and refresh the export settings.
+	_export_settings->generate_property_list(_gltf_document);
+	_settings_inspector->edit(nullptr);
+	_settings_inspector->edit(_export_settings.ptr());
+	// Show the file dialog.
+	_file_dialog->popup_centered_ratio();
 }
 }
 
 
-void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) {
+void SceneExporterGLTFPlugin::_export_scene_as_gltf(const String &p_file_path) {
 	Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root();
 	Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root();
 	if (!root) {
 	if (!root) {
 		EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
 		EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
 		return;
 		return;
 	}
 	}
 	List<String> deps;
 	List<String> deps;
-	Ref<GLTFDocument> doc;
-	doc.instantiate();
 	Ref<GLTFState> state;
 	Ref<GLTFState> state;
 	state.instantiate();
 	state.instantiate();
+	state->set_copyright(_export_settings->get_copyright());
 	int32_t flags = 0;
 	int32_t flags = 0;
 	flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
 	flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
-	Error err = doc->append_from_scene(root, state, flags);
+	Error err = _gltf_document->append_from_scene(root, state, flags);
 	if (err != OK) {
 	if (err != OK) {
 		ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err)));
 		ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err)));
 	}
 	}
-	err = doc->write_to_filesystem(state, p_file);
+	err = _gltf_document->write_to_filesystem(state, p_file_path);
 	if (err != OK) {
 	if (err != OK) {
 		ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err)));
 		ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err)));
 	}
 	}
 	EditorFileSystem::get_singleton()->scan_changes();
 	EditorFileSystem::get_singleton()->scan_changes();
 }
 }
 
 
-void SceneExporterGLTFPlugin::convert_scene_to_gltf2() {
-	Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root();
-	if (!root) {
-		EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
-		return;
-	}
-	String filename = String(root->get_scene_file_path().get_file().get_basename());
-	if (filename.is_empty()) {
-		filename = root->get_name();
-	}
-	file_export_lib->set_current_file(filename + String(".gltf"));
-	file_export_lib->popup_centered_ratio();
-}
-
 #endif // TOOLS_ENABLED
 #endif // TOOLS_ENABLED

+ 9 - 4
modules/gltf/editor/editor_scene_exporter_gltf_plugin.h

@@ -33,18 +33,23 @@
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 
 
-#include "editor_scene_importer_gltf.h"
+#include "../gltf_document.h"
+#include "editor_scene_exporter_gltf_settings.h"
 
 
 #include "editor/editor_plugin.h"
 #include "editor/editor_plugin.h"
 
 
 class EditorFileDialog;
 class EditorFileDialog;
+class EditorInspector;
 
 
 class SceneExporterGLTFPlugin : public EditorPlugin {
 class SceneExporterGLTFPlugin : public EditorPlugin {
 	GDCLASS(SceneExporterGLTFPlugin, EditorPlugin);
 	GDCLASS(SceneExporterGLTFPlugin, EditorPlugin);
 
 
-	EditorFileDialog *file_export_lib = nullptr;
-	void _gltf2_dialog_action(String p_file);
-	void convert_scene_to_gltf2();
+	Ref<GLTFDocument> _gltf_document;
+	Ref<EditorSceneExporterGLTFSettings> _export_settings;
+	EditorInspector *_settings_inspector = nullptr;
+	EditorFileDialog *_file_dialog = nullptr;
+	void _popup_gltf_export_dialog();
+	void _export_scene_as_gltf(const String &p_file_path);
 
 
 public:
 public:
 	virtual String get_name() const override;
 	virtual String get_name() const override;

+ 176 - 0
modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp

@@ -0,0 +1,176 @@
+/**************************************************************************/
+/*  editor_scene_exporter_gltf_settings.cpp                               */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "editor_scene_exporter_gltf_settings.h"
+
+const uint32_t PROP_EDITOR_SCRIPT_VAR = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE;
+
+bool EditorSceneExporterGLTFSettings::_set(const StringName &p_name, const Variant &p_value) {
+	String name_str = String(p_name);
+	if (name_str.contains("/")) {
+		return _set_extension_setting(name_str, p_value);
+	}
+	if (p_name == StringName("image_format")) {
+		_document->set_image_format(p_value);
+		emit_signal("property_list_changed");
+		return true;
+	}
+	if (p_name == StringName("lossy_quality")) {
+		_document->set_lossy_quality(p_value);
+		return true;
+	}
+	if (p_name == StringName("root_node_mode")) {
+		_document->set_root_node_mode((GLTFDocument::RootNodeMode)(int64_t)p_value);
+		return true;
+	}
+	return false;
+}
+
+bool EditorSceneExporterGLTFSettings::_get(const StringName &p_name, Variant &r_ret) const {
+	String name_str = String(p_name);
+	if (name_str.contains("/")) {
+		return _get_extension_setting(name_str, r_ret);
+	}
+	if (p_name == StringName("image_format")) {
+		r_ret = _document->get_image_format();
+		return true;
+	}
+	if (p_name == StringName("lossy_quality")) {
+		r_ret = _document->get_lossy_quality();
+		return true;
+	}
+	if (p_name == StringName("root_node_mode")) {
+		r_ret = _document->get_root_node_mode();
+		return true;
+	}
+	return false;
+}
+
+void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_list) const {
+	for (PropertyInfo prop : _property_list) {
+		if (prop.name == "lossy_quality") {
+			String image_format = get("image_format");
+			bool is_image_format_lossy = image_format == "JPEG" || image_format.findn("Lossy") != -1;
+			prop.usage = is_image_format_lossy ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE;
+		}
+		p_list->push_back(prop);
+	}
+}
+
+bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) {
+	PackedStringArray split = String(p_name_str).split("/", true, 1);
+	if (!_config_name_to_extension_map.has(split[0])) {
+		return false;
+	}
+	Ref<GLTFDocumentExtension> extension = _config_name_to_extension_map[split[0]];
+	bool valid;
+	extension->set(split[1], p_value, &valid);
+	return valid;
+}
+
+bool EditorSceneExporterGLTFSettings::_get_extension_setting(const String &p_name_str, Variant &r_ret) const {
+	PackedStringArray split = String(p_name_str).split("/", true, 1);
+	if (!_config_name_to_extension_map.has(split[0])) {
+		return false;
+	}
+	Ref<GLTFDocumentExtension> extension = _config_name_to_extension_map[split[0]];
+	bool valid;
+	r_ret = extension->get(split[1], &valid);
+	return valid;
+}
+
+String get_friendly_config_prefix(Ref<GLTFDocumentExtension> p_extension) {
+	String config_prefix = p_extension->get_name();
+	if (!config_prefix.is_empty()) {
+		return config_prefix;
+	}
+	const String class_name = p_extension->get_class_name();
+	config_prefix = class_name.trim_prefix("GLTFDocumentExtension").capitalize();
+	if (!config_prefix.is_empty()) {
+		return config_prefix;
+	}
+	PackedStringArray supported_extensions = p_extension->get_supported_extensions();
+	if (supported_extensions.size() > 0) {
+		return supported_extensions[0];
+	}
+	return "Unknown GLTFDocumentExtension";
+}
+
+// Run this before popping up the export settings, because the extensions may have changed.
+void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document) {
+	_property_list.clear();
+	_document = p_document;
+	String image_format_hint_string = "None,PNG,JPEG";
+	// Add properties from all document extensions.
+	for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) {
+		const String config_prefix = get_friendly_config_prefix(extension);
+		_config_name_to_extension_map[config_prefix] = extension;
+		// If the extension allows saving in different image formats, add to the enum.
+		PackedStringArray saveable_image_formats = extension->get_saveable_image_formats();
+		for (int i = 0; i < saveable_image_formats.size(); i++) {
+			image_format_hint_string += "," + saveable_image_formats[i];
+		}
+		// Look through the extension's properties and find the relevant ones.
+		List<PropertyInfo> ext_prop_list;
+		extension->get_property_list(&ext_prop_list);
+		for (const PropertyInfo &prop : ext_prop_list) {
+			// We only want properties that will show up in the exporter
+			// settings list. Exclude Resource's properties, as they are
+			// not relevant to the exporter. Include any user-defined script
+			// variables exposed to the editor (PROP_EDITOR_SCRIPT_VAR).
+			if ((prop.usage & PROP_EDITOR_SCRIPT_VAR) == PROP_EDITOR_SCRIPT_VAR) {
+				PropertyInfo ext_prop = prop;
+				ext_prop.name = config_prefix + "/" + prop.name;
+				_property_list.push_back(ext_prop);
+			}
+		}
+	}
+	// Add top-level properties (in addition to what _bind_methods registers).
+	PropertyInfo image_format_prop = PropertyInfo(Variant::STRING, "image_format", PROPERTY_HINT_ENUM, image_format_hint_string);
+	_property_list.push_back(image_format_prop);
+	PropertyInfo lossy_quality_prop = PropertyInfo(Variant::FLOAT, "lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01");
+	_property_list.push_back(lossy_quality_prop);
+	PropertyInfo root_node_mode_prop = PropertyInfo(Variant::INT, "root_node_mode", PROPERTY_HINT_ENUM, "Single Root,Keep Root,Multi Root");
+	_property_list.push_back(root_node_mode_prop);
+}
+
+String EditorSceneExporterGLTFSettings::get_copyright() const {
+	return _copyright;
+}
+
+void EditorSceneExporterGLTFSettings::set_copyright(const String &p_copyright) {
+	_copyright = p_copyright;
+}
+
+void EditorSceneExporterGLTFSettings::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_copyright"), &EditorSceneExporterGLTFSettings::get_copyright);
+	ClassDB::bind_method(D_METHOD("set_copyright", "copyright"), &EditorSceneExporterGLTFSettings::set_copyright);
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "copyright", PROPERTY_HINT_PLACEHOLDER_TEXT, "Example: 2014 Godette"), "set_copyright", "get_copyright");
+}

+ 64 - 0
modules/gltf/editor/editor_scene_exporter_gltf_settings.h

@@ -0,0 +1,64 @@
+/**************************************************************************/
+/*  editor_scene_exporter_gltf_settings.h                                 */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H
+#define EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H
+
+#ifdef TOOLS_ENABLED
+
+#include "../gltf_document.h"
+
+class EditorSceneExporterGLTFSettings : public RefCounted {
+	GDCLASS(EditorSceneExporterGLTFSettings, RefCounted);
+	List<PropertyInfo> _property_list;
+	Ref<GLTFDocument> _document;
+	HashMap<String, Ref<GLTFDocumentExtension>> _config_name_to_extension_map;
+
+	String _copyright;
+
+protected:
+	static void _bind_methods();
+	bool _set(const StringName &p_name, const Variant &p_value);
+	bool _get(const StringName &p_name, Variant &r_ret) const;
+	void _get_property_list(List<PropertyInfo> *p_list) const;
+
+	bool _set_extension_setting(const String &p_name_str, const Variant &p_value);
+	bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const;
+
+public:
+	void generate_property_list(Ref<GLTFDocument> p_document);
+
+	String get_copyright() const;
+	void set_copyright(const String &p_copyright);
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H

+ 131 - 125
modules/gltf/gltf_document.cpp

@@ -3658,141 +3658,143 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
 
 
 		mr["metallicFactor"] = base_material->get_metallic();
 		mr["metallicFactor"] = base_material->get_metallic();
 		mr["roughnessFactor"] = base_material->get_roughness();
 		mr["roughnessFactor"] = base_material->get_roughness();
-		bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid();
-		bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid();
-		bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid();
-		if (has_ao || has_roughness || has_metalness) {
-			Dictionary mrt;
-			Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS);
-			BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel();
-			Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC);
-			BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel();
-			Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION);
-			BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel();
-			Ref<ImageTexture> orm_texture;
-			orm_texture.instantiate();
-			Ref<Image> orm_image;
-			orm_image.instantiate();
-			int32_t height = 0;
-			int32_t width = 0;
-			Ref<Image> ao_image;
-			if (has_ao) {
-				height = ao_texture->get_height();
-				width = ao_texture->get_width();
-				ao_image = ao_texture->get_image();
-				Ref<ImageTexture> img_tex = ao_image;
-				if (img_tex.is_valid()) {
-					ao_image = img_tex->get_image();
-				}
-				if (ao_image->is_compressed()) {
-					ao_image->decompress();
-				}
-			}
-			Ref<Image> roughness_image;
-			if (has_roughness) {
-				height = roughness_texture->get_height();
-				width = roughness_texture->get_width();
-				roughness_image = roughness_texture->get_image();
-				Ref<ImageTexture> img_tex = roughness_image;
-				if (img_tex.is_valid()) {
-					roughness_image = img_tex->get_image();
-				}
-				if (roughness_image->is_compressed()) {
-					roughness_image->decompress();
-				}
-			}
-			Ref<Image> metallness_image;
-			if (has_metalness) {
-				height = metallic_texture->get_height();
-				width = metallic_texture->get_width();
-				metallness_image = metallic_texture->get_image();
-				Ref<ImageTexture> img_tex = metallness_image;
-				if (img_tex.is_valid()) {
-					metallness_image = img_tex->get_image();
-				}
-				if (metallness_image->is_compressed()) {
-					metallness_image->decompress();
+		if (_image_format != "None") {
+			bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid();
+			bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid();
+			bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid();
+			if (has_ao || has_roughness || has_metalness) {
+				Dictionary mrt;
+				Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS);
+				BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel();
+				Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC);
+				BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel();
+				Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION);
+				BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel();
+				Ref<ImageTexture> orm_texture;
+				orm_texture.instantiate();
+				Ref<Image> orm_image;
+				orm_image.instantiate();
+				int32_t height = 0;
+				int32_t width = 0;
+				Ref<Image> ao_image;
+				if (has_ao) {
+					height = ao_texture->get_height();
+					width = ao_texture->get_width();
+					ao_image = ao_texture->get_image();
+					Ref<ImageTexture> img_tex = ao_image;
+					if (img_tex.is_valid()) {
+						ao_image = img_tex->get_image();
+					}
+					if (ao_image->is_compressed()) {
+						ao_image->decompress();
+					}
 				}
 				}
-			}
-			Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
-			if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
-				height = albedo_texture->get_height();
-				width = albedo_texture->get_width();
-			}
-			orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8);
-			if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) {
-				ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
-			}
-			if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) {
-				roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
-			}
-			if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) {
-				metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
-			}
-			for (int32_t h = 0; h < height; h++) {
-				for (int32_t w = 0; w < width; w++) {
-					Color c = Color(1.0f, 1.0f, 1.0f);
-					if (has_ao) {
-						if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) {
-							c.r = ao_image->get_pixel(w, h).r;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) {
-							c.r = ao_image->get_pixel(w, h).g;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) {
-							c.r = ao_image->get_pixel(w, h).b;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) {
-							c.r = ao_image->get_pixel(w, h).a;
-						}
+				Ref<Image> roughness_image;
+				if (has_roughness) {
+					height = roughness_texture->get_height();
+					width = roughness_texture->get_width();
+					roughness_image = roughness_texture->get_image();
+					Ref<ImageTexture> img_tex = roughness_image;
+					if (img_tex.is_valid()) {
+						roughness_image = img_tex->get_image();
 					}
 					}
-					if (has_roughness) {
-						if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) {
-							c.g = roughness_image->get_pixel(w, h).r;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) {
-							c.g = roughness_image->get_pixel(w, h).g;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) {
-							c.g = roughness_image->get_pixel(w, h).b;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) {
-							c.g = roughness_image->get_pixel(w, h).a;
-						}
+					if (roughness_image->is_compressed()) {
+						roughness_image->decompress();
+					}
+				}
+				Ref<Image> metallness_image;
+				if (has_metalness) {
+					height = metallic_texture->get_height();
+					width = metallic_texture->get_width();
+					metallness_image = metallic_texture->get_image();
+					Ref<ImageTexture> img_tex = metallness_image;
+					if (img_tex.is_valid()) {
+						metallness_image = img_tex->get_image();
+					}
+					if (metallness_image->is_compressed()) {
+						metallness_image->decompress();
 					}
 					}
-					if (has_metalness) {
-						if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) {
-							c.b = metallness_image->get_pixel(w, h).r;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) {
-							c.b = metallness_image->get_pixel(w, h).g;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) {
-							c.b = metallness_image->get_pixel(w, h).b;
-						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) {
-							c.b = metallness_image->get_pixel(w, h).a;
+				}
+				Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
+				if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
+					height = albedo_texture->get_height();
+					width = albedo_texture->get_width();
+				}
+				orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8);
+				if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) {
+					ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
+				}
+				if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) {
+					roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
+				}
+				if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) {
+					metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
+				}
+				for (int32_t h = 0; h < height; h++) {
+					for (int32_t w = 0; w < width; w++) {
+						Color c = Color(1.0f, 1.0f, 1.0f);
+						if (has_ao) {
+							if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) {
+								c.r = ao_image->get_pixel(w, h).r;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) {
+								c.r = ao_image->get_pixel(w, h).g;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) {
+								c.r = ao_image->get_pixel(w, h).b;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) {
+								c.r = ao_image->get_pixel(w, h).a;
+							}
 						}
 						}
+						if (has_roughness) {
+							if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) {
+								c.g = roughness_image->get_pixel(w, h).r;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) {
+								c.g = roughness_image->get_pixel(w, h).g;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) {
+								c.g = roughness_image->get_pixel(w, h).b;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) {
+								c.g = roughness_image->get_pixel(w, h).a;
+							}
+						}
+						if (has_metalness) {
+							if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) {
+								c.b = metallness_image->get_pixel(w, h).r;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) {
+								c.b = metallness_image->get_pixel(w, h).g;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) {
+								c.b = metallness_image->get_pixel(w, h).b;
+							} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) {
+								c.b = metallness_image->get_pixel(w, h).a;
+							}
+						}
+						orm_image->set_pixel(w, h, c);
 					}
 					}
-					orm_image->set_pixel(w, h, c);
 				}
 				}
-			}
-			orm_image->generate_mipmaps();
-			orm_texture->set_image(orm_image);
-			GLTFTextureIndex orm_texture_index = -1;
-			if (has_ao || has_roughness || has_metalness) {
-				orm_texture->set_name(material->get_name() + "_orm");
-				orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
-			}
-			if (has_ao) {
-				Dictionary occt;
-				occt["index"] = orm_texture_index;
-				d["occlusionTexture"] = occt;
-			}
-			if (has_roughness || has_metalness) {
-				mrt["index"] = orm_texture_index;
-				Dictionary extensions = _serialize_texture_transform_uv1(material);
-				if (!extensions.is_empty()) {
-					mrt["extensions"] = extensions;
-					p_state->use_khr_texture_transform = true;
+				orm_image->generate_mipmaps();
+				orm_texture->set_image(orm_image);
+				GLTFTextureIndex orm_texture_index = -1;
+				if (has_ao || has_roughness || has_metalness) {
+					orm_texture->set_name(material->get_name() + "_orm");
+					orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
+				}
+				if (has_ao) {
+					Dictionary occt;
+					occt["index"] = orm_texture_index;
+					d["occlusionTexture"] = occt;
+				}
+				if (has_roughness || has_metalness) {
+					mrt["index"] = orm_texture_index;
+					Dictionary extensions = _serialize_texture_transform_uv1(material);
+					if (!extensions.is_empty()) {
+						mrt["extensions"] = extensions;
+						p_state->use_khr_texture_transform = true;
+					}
+					mr["metallicRoughnessTexture"] = mrt;
 				}
 				}
-				mr["metallicRoughnessTexture"] = mrt;
 			}
 			}
 		}
 		}
 
 
 		d["pbrMetallicRoughness"] = mr;
 		d["pbrMetallicRoughness"] = mr;
-		if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) {
+		if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING) && _image_format != "None") {
 			Dictionary nt;
 			Dictionary nt;
 			Ref<ImageTexture> tex;
 			Ref<ImageTexture> tex;
 			tex.instantiate();
 			tex.instantiate();
@@ -3845,7 +3847,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
 			d["emissiveFactor"] = arr;
 			d["emissiveFactor"] = arr;
 		}
 		}
 
 
-		if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
+		if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && _image_format != "None") {
 			Dictionary et;
 			Dictionary et;
 			Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
 			Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
 			GLTFTextureIndex gltf_texture_index = -1;
 			GLTFTextureIndex gltf_texture_index = -1;
@@ -7336,6 +7338,10 @@ void GLTFDocument::unregister_all_gltf_document_extensions() {
 	all_document_extensions.clear();
 	all_document_extensions.clear();
 }
 }
 
 
+Vector<Ref<GLTFDocumentExtension>> GLTFDocument::get_all_gltf_document_extensions() {
+	return all_document_extensions;
+}
+
 PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) {
 PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) {
 	Error err = _encode_buffer_glb(p_state, "");
 	Error err = _encode_buffer_glb(p_state, "");
 	if (r_err) {
 	if (r_err) {

+ 1 - 0
modules/gltf/gltf_document.h

@@ -86,6 +86,7 @@ public:
 	static void register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority = false);
 	static void register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority = false);
 	static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension);
 	static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension);
 	static void unregister_all_gltf_document_extensions();
 	static void unregister_all_gltf_document_extensions();
+	static Vector<Ref<GLTFDocumentExtension>> get_all_gltf_document_extensions();
 
 
 	void set_naming_version(int p_version);
 	void set_naming_version(int p_version);
 	int get_naming_version() const;
 	int get_naming_version() const;