Merge pull request #79316 from aaronfranke/gltf-export
Add export settings to the export dialog for GLTF
This commit is contained in:
commit
0f0106c101
7 changed files with 435 additions and 168 deletions
|
@ -84,7 +84,7 @@
|
|||
<param index="1" name="path" type="String" />
|
||||
<description>
|
||||
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>
|
||||
</method>
|
||||
</methods>
|
||||
|
|
|
@ -32,12 +32,14 @@
|
|||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "../gltf_document.h"
|
||||
#include "editor_scene_exporter_gltf_settings.h"
|
||||
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_scale.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 {
|
||||
return "ConvertGLTF2";
|
||||
|
@ -48,59 +50,72 @@ bool SceneExporterGLTFPlugin::has_main_screen() const {
|
|||
}
|
||||
|
||||
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();
|
||||
int idx = menu->get_item_count();
|
||||
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::_gltf2_dialog_action(String p_file) {
|
||||
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::_export_scene_as_gltf(const String &p_file_path) {
|
||||
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;
|
||||
}
|
||||
List<String> deps;
|
||||
Ref<GLTFDocument> doc;
|
||||
doc.instantiate();
|
||||
Ref<GLTFState> state;
|
||||
state.instantiate();
|
||||
state->set_copyright(_export_settings->get_copyright());
|
||||
int32_t flags = 0;
|
||||
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) {
|
||||
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) {
|
||||
ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err)));
|
||||
}
|
||||
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
|
||||
|
|
|
@ -33,18 +33,23 @@
|
|||
|
||||
#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"
|
||||
|
||||
class EditorFileDialog;
|
||||
class EditorInspector;
|
||||
|
||||
class SceneExporterGLTFPlugin : public 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:
|
||||
virtual String get_name() const override;
|
||||
|
|
176
modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
Normal file
176
modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
Normal file
|
@ -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
modules/gltf/editor/editor_scene_exporter_gltf_settings.h
Normal file
64
modules/gltf/editor/editor_scene_exporter_gltf_settings.h
Normal file
|
@ -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
|
|
@ -3658,141 +3658,143 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
|
|||
|
||||
mr["metallicFactor"] = base_material->get_metallic();
|
||||
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();
|
||||
}
|
||||
}
|
||||
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->generate_mipmaps();
|
||||
orm_texture->set_image(orm_image);
|
||||
GLTFTextureIndex orm_texture_index = -1;
|
||||
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) {
|
||||
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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
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->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;
|
||||
if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) {
|
||||
if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING) && _image_format != "None") {
|
||||
Dictionary nt;
|
||||
Ref<ImageTexture> tex;
|
||||
tex.instantiate();
|
||||
|
@ -3845,7 +3847,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
|
|||
d["emissiveFactor"] = arr;
|
||||
}
|
||||
|
||||
if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
|
||||
if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && _image_format != "None") {
|
||||
Dictionary et;
|
||||
Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
|
||||
GLTFTextureIndex gltf_texture_index = -1;
|
||||
|
@ -7336,6 +7338,10 @@ void GLTFDocument::unregister_all_gltf_document_extensions() {
|
|||
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) {
|
||||
Error err = _encode_buffer_glb(p_state, "");
|
||||
if (r_err) {
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
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_all_gltf_document_extensions();
|
||||
static Vector<Ref<GLTFDocumentExtension>> get_all_gltf_document_extensions();
|
||||
|
||||
void set_naming_version(int p_version);
|
||||
int get_naming_version() const;
|
||||
|
|
Loading…
Reference in a new issue