Improved 3D Scene Importer
* Added option for importers to show an Advanced settings dialog * Created advanced settings dialog for Scene Importer * Cleaned up importers (remove many old/unused options) * Added the ability to customize every node, material, mesh and animation individually * Saving to animations and meshes to files is now a manual process, making it more predictable * Added the ability for materials to be replaced by external files (or to be made external, up to you). * When doubleclicking an impoted scene in the filesystem dock, it automatically shows the import settings instead of asking to open it. WARNING: Lightmap UV unwrap is not working, it needs to be re-made.
This commit is contained in:
parent
07f076fa4f
commit
97a3a66220
25 changed files with 2650 additions and 692 deletions
|
@ -115,6 +115,9 @@ public:
|
|||
ImportOption() {}
|
||||
};
|
||||
|
||||
virtual bool has_advanced_options() const { return false; }
|
||||
virtual void show_advanced_options(const String &p_path) {}
|
||||
|
||||
virtual int get_preset_count() const { return 0; }
|
||||
virtual String get_preset_name(int p_idx) const { return String(); }
|
||||
|
||||
|
|
|
@ -1668,7 +1668,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
|
|||
return err;
|
||||
}
|
||||
|
||||
void EditorFileSystem::_reimport_file(const String &p_file) {
|
||||
void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName, Variant> *p_custom_options, const String &p_custom_importer) {
|
||||
EditorFileSystemDirectory *fs = nullptr;
|
||||
int cpos = -1;
|
||||
bool found = _find_file(p_file, &fs, cpos);
|
||||
|
@ -1677,23 +1677,32 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
|
|||
//try to obtain existing params
|
||||
|
||||
Map<StringName, Variant> params;
|
||||
String importer_name;
|
||||
String importer_name; //empty by default though
|
||||
|
||||
if (p_custom_importer != String()) {
|
||||
importer_name = p_custom_importer;
|
||||
}
|
||||
if (p_custom_options != nullptr) {
|
||||
params = *p_custom_options;
|
||||
}
|
||||
|
||||
if (FileAccess::exists(p_file + ".import")) {
|
||||
//use existing
|
||||
Ref<ConfigFile> cf;
|
||||
cf.instance();
|
||||
Error err = cf->load(p_file + ".import");
|
||||
if (err == OK) {
|
||||
if (cf->has_section("params")) {
|
||||
List<String> sk;
|
||||
cf->get_section_keys("params", &sk);
|
||||
for (List<String>::Element *E = sk.front(); E; E = E->next()) {
|
||||
params[E->get()] = cf->get_value("params", E->get());
|
||||
if (p_custom_options == nullptr) {
|
||||
Ref<ConfigFile> cf;
|
||||
cf.instance();
|
||||
Error err = cf->load(p_file + ".import");
|
||||
if (err == OK) {
|
||||
if (cf->has_section("params")) {
|
||||
List<String> sk;
|
||||
cf->get_section_keys("params", &sk);
|
||||
for (List<String>::Element *E = sk.front(); E; E = E->next()) {
|
||||
params[E->get()] = cf->get_value("params", E->get());
|
||||
}
|
||||
}
|
||||
if (p_custom_importer != String() && cf->has_section("remap")) {
|
||||
importer_name = cf->get_value("remap", "importer");
|
||||
}
|
||||
}
|
||||
if (cf->has_section("remap")) {
|
||||
importer_name = cf->get_value("remap", "importer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1887,6 +1896,10 @@ void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<Str
|
|||
}
|
||||
}
|
||||
|
||||
void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const Map<StringName, Variant> &p_custom_params) {
|
||||
_reimport_file(p_file, &p_custom_params, p_importer);
|
||||
}
|
||||
|
||||
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
|
||||
{
|
||||
// Ensure that ProjectSettings::IMPORTED_FILES_PATH exists.
|
||||
|
|
|
@ -203,7 +203,7 @@ class EditorFileSystem : public Node {
|
|||
|
||||
void _update_extensions();
|
||||
|
||||
void _reimport_file(const String &p_file);
|
||||
void _reimport_file(const String &p_file, const Map<StringName, Variant> *p_custom_options = nullptr, const String &p_custom_importer = String());
|
||||
Error _reimport_group(const String &p_group_file, const Vector<String> &p_files);
|
||||
|
||||
bool _test_for_reimport(const String &p_path, bool p_only_imported_files);
|
||||
|
@ -257,6 +257,8 @@ public:
|
|||
|
||||
void reimport_files(const Vector<String> &p_files);
|
||||
|
||||
void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const Map<StringName, Variant> &p_custom_params);
|
||||
|
||||
void update_script_classes();
|
||||
|
||||
bool is_group_file(const String &p_path) const;
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
#include "editor/import/resource_importer_texture.h"
|
||||
#include "editor/import/resource_importer_texture_atlas.h"
|
||||
#include "editor/import/resource_importer_wav.h"
|
||||
#include "editor/import/scene_import_settings.h"
|
||||
#include "editor/import/scene_importer_mesh_node_3d.h"
|
||||
#include "editor/import_dock.h"
|
||||
#include "editor/multi_node_edit.h"
|
||||
|
@ -6179,6 +6180,9 @@ EditorNode::EditorNode() {
|
|||
project_settings = memnew(ProjectSettingsEditor(&editor_data));
|
||||
gui_base->add_child(project_settings);
|
||||
|
||||
scene_import_settings = memnew(SceneImportSettings);
|
||||
gui_base->add_child(scene_import_settings);
|
||||
|
||||
export_template_manager = memnew(ExportTemplateManager);
|
||||
gui_base->add_child(export_template_manager);
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ class Button;
|
|||
class VSplitContainer;
|
||||
class Window;
|
||||
class SubViewport;
|
||||
class SceneImportSettings;
|
||||
|
||||
class EditorNode : public Node {
|
||||
GDCLASS(EditorNode, Node);
|
||||
|
@ -410,6 +411,7 @@ private:
|
|||
EditorResourcePreview *resource_preview;
|
||||
EditorFolding editor_folding;
|
||||
|
||||
SceneImportSettings *scene_import_settings;
|
||||
struct BottomPanelItem {
|
||||
String name;
|
||||
Control *control = nullptr;
|
||||
|
|
|
@ -945,7 +945,25 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
|
|||
}
|
||||
} else if (fpath != "Favorites") {
|
||||
if (ResourceLoader::get_resource_type(fpath) == "PackedScene") {
|
||||
editor->open_request(fpath);
|
||||
bool is_imported = false;
|
||||
|
||||
{
|
||||
List<String> importer_exts;
|
||||
ResourceImporterScene::get_singleton()->get_recognized_extensions(&importer_exts);
|
||||
String extension = fpath.get_extension();
|
||||
for (List<String>::Element *E = importer_exts.front(); E; E = E->next()) {
|
||||
if (extension.nocasecmp_to(E->get())) {
|
||||
is_imported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_imported) {
|
||||
ResourceImporterScene::get_singleton()->show_advanced_options(fpath);
|
||||
} else {
|
||||
editor->open_request(fpath);
|
||||
}
|
||||
} else {
|
||||
editor->load_resource(fpath);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,9 @@ struct ColladaImport {
|
|||
Vector<int> valid_animated_properties;
|
||||
Map<String, bool> bones_with_animation;
|
||||
|
||||
Set<String> mesh_unique_names;
|
||||
Set<String> material_unique_names;
|
||||
|
||||
Error _populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent);
|
||||
Error _create_scene_skeletons(Collada::Node *p_node);
|
||||
Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
|
||||
|
@ -326,12 +329,25 @@ Error ColladaImport::_create_material(const String &p_target) {
|
|||
|
||||
Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
|
||||
|
||||
String base_name;
|
||||
if (src_mat.name != "") {
|
||||
material->set_name(src_mat.name);
|
||||
base_name = src_mat.name;
|
||||
} else if (effect.name != "") {
|
||||
material->set_name(effect.name);
|
||||
base_name = effect.name;
|
||||
} else {
|
||||
base_name = "Material";
|
||||
}
|
||||
|
||||
String name = base_name;
|
||||
int counter = 2;
|
||||
while (material_unique_names.has(name)) {
|
||||
name = base_name + itos(counter++);
|
||||
}
|
||||
|
||||
material_unique_names.insert(name);
|
||||
|
||||
material->set_name(name);
|
||||
|
||||
// DIFFUSE
|
||||
|
||||
if (effect.diffuse.texture != "") {
|
||||
|
@ -1128,7 +1144,22 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
|
|||
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
|
||||
mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
|
||||
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
|
||||
mesh->set_name(meshdata.name);
|
||||
String name = meshdata.name;
|
||||
if (name == "") {
|
||||
name = "Mesh";
|
||||
}
|
||||
int counter = 2;
|
||||
while (mesh_unique_names.has(name)) {
|
||||
name = meshdata.name;
|
||||
if (name == "") {
|
||||
name = "Mesh";
|
||||
}
|
||||
name += itos(counter++);
|
||||
}
|
||||
|
||||
mesh_unique_names.insert(name);
|
||||
|
||||
mesh->set_name(name);
|
||||
Error err = _create_mesh_surfaces(morphs.size() == 0, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, morph, morphs, p_use_compression, use_mesh_builtin_materials);
|
||||
ERR_FAIL_COND_V_MSG(err, err, "Cannot create mesh surface.");
|
||||
|
||||
|
@ -1645,16 +1676,23 @@ void EditorSceneImporterCollada::get_extensions(List<String> *r_extensions) cons
|
|||
}
|
||||
|
||||
Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
|
||||
if (r_err) {
|
||||
*r_err = OK;
|
||||
}
|
||||
ColladaImport state;
|
||||
uint32_t flags = Collada::IMPORT_FLAG_SCENE;
|
||||
if (p_flags & IMPORT_ANIMATION) {
|
||||
flags |= Collada::IMPORT_FLAG_ANIMATION;
|
||||
}
|
||||
|
||||
state.use_mesh_builtin_materials = !(p_flags & IMPORT_MATERIALS_IN_INSTANCES);
|
||||
state.use_mesh_builtin_materials = true;
|
||||
state.bake_fps = p_bake_fps;
|
||||
|
||||
Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & EditorSceneImporter::IMPORT_USE_COMPRESSION);
|
||||
Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, 0);
|
||||
|
||||
if (r_err) {
|
||||
*r_err = err;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Cannot load scene from file '" + p_path + "'.");
|
||||
|
||||
|
@ -1674,7 +1712,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
|
|||
}
|
||||
|
||||
if (p_flags & IMPORT_ANIMATION) {
|
||||
state.create_animations(p_flags & IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
|
||||
state.create_animations(true, true);
|
||||
AnimationPlayer *ap = memnew(AnimationPlayer);
|
||||
for (int i = 0; i < state.animations.size(); i++) {
|
||||
String name;
|
||||
|
@ -1684,12 +1722,6 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
|
|||
name = state.animations[i]->get_name();
|
||||
}
|
||||
|
||||
if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
|
||||
if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
|
||||
state.animations.write[i]->set_loop(true);
|
||||
}
|
||||
}
|
||||
|
||||
ap->add_animation(name, state.animations[i]);
|
||||
}
|
||||
state.scene->add_child(ap);
|
||||
|
@ -1707,7 +1739,7 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
|
|||
Error err = state.load(p_path, Collada::IMPORT_FLAG_ANIMATION, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS);
|
||||
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'.");
|
||||
|
||||
state.create_animations(p_flags & EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
|
||||
state.create_animations(true, true);
|
||||
if (state.scene) {
|
||||
memdelete(state.scene);
|
||||
}
|
||||
|
@ -1716,12 +1748,6 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
|
|||
return Ref<Animation>();
|
||||
}
|
||||
Ref<Animation> anim = state.animations[0];
|
||||
String base = p_path.get_basename().to_lower();
|
||||
if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
|
||||
if (base.begins_with("loop") || base.ends_with("loop") || base.begins_with("cycle") || base.ends_with("cycle")) {
|
||||
anim->set_loop(true);
|
||||
}
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
|
|
@ -427,7 +427,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
|||
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
|
||||
List<Ref<Mesh>> meshes;
|
||||
|
||||
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
|
||||
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, 0, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
|
||||
|
||||
if (err != OK) {
|
||||
if (r_err) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -39,7 +39,9 @@
|
|||
#include "scene/resources/skin.h"
|
||||
|
||||
class Material;
|
||||
class AnimationPlayer;
|
||||
|
||||
class EditorSceneImporterMesh;
|
||||
class EditorSceneImporter : public Reference {
|
||||
GDCLASS(EditorSceneImporter, Reference);
|
||||
|
||||
|
@ -53,15 +55,9 @@ public:
|
|||
enum ImportFlags {
|
||||
IMPORT_SCENE = 1,
|
||||
IMPORT_ANIMATION = 2,
|
||||
IMPORT_ANIMATION_DETECT_LOOP = 4,
|
||||
IMPORT_ANIMATION_OPTIMIZE = 8,
|
||||
IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS = 16,
|
||||
IMPORT_ANIMATION_KEEP_VALUE_TRACKS = 32,
|
||||
IMPORT_GENERATE_TANGENT_ARRAYS = 256,
|
||||
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
|
||||
IMPORT_MATERIALS_IN_INSTANCES = 1024,
|
||||
IMPORT_USE_COMPRESSION = 2048,
|
||||
IMPORT_USE_NAMED_SKIN_BINDS = 4096,
|
||||
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4,
|
||||
IMPORT_GENERATE_TANGENT_ARRAYS = 8,
|
||||
IMPORT_USE_NAMED_SKIN_BINDS = 16,
|
||||
|
||||
};
|
||||
|
||||
|
@ -76,17 +72,15 @@ public:
|
|||
class EditorScenePostImport : public Reference {
|
||||
GDCLASS(EditorScenePostImport, Reference);
|
||||
|
||||
String source_folder;
|
||||
String source_file;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
String get_source_folder() const;
|
||||
String get_source_file() const;
|
||||
virtual Node *post_import(Node *p_scene);
|
||||
virtual void init(const String &p_source_folder, const String &p_source_file);
|
||||
virtual void init(const String &p_source_file);
|
||||
EditorScenePostImport();
|
||||
};
|
||||
|
||||
|
@ -97,31 +91,35 @@ class ResourceImporterScene : public ResourceImporter {
|
|||
|
||||
static ResourceImporterScene *singleton;
|
||||
|
||||
enum Presets {
|
||||
PRESET_SEPARATE_MATERIALS,
|
||||
PRESET_SEPARATE_MESHES,
|
||||
PRESET_SEPARATE_ANIMATIONS,
|
||||
|
||||
PRESET_SINGLE_SCENE,
|
||||
|
||||
PRESET_SEPARATE_MESHES_AND_MATERIALS,
|
||||
PRESET_SEPARATE_MESHES_AND_ANIMATIONS,
|
||||
PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS,
|
||||
PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS,
|
||||
|
||||
PRESET_MULTIPLE_SCENES,
|
||||
PRESET_MULTIPLE_SCENES_AND_MATERIALS,
|
||||
PRESET_MAX
|
||||
};
|
||||
|
||||
enum LightBakeMode {
|
||||
LIGHT_BAKE_DISABLED,
|
||||
LIGHT_BAKE_ENABLE,
|
||||
LIGHT_BAKE_LIGHTMAPS
|
||||
LIGHT_BAKE_DYNAMIC,
|
||||
LIGHT_BAKE_STATIC,
|
||||
LIGHT_BAKE_STATIC_LIGHTMAPS
|
||||
};
|
||||
|
||||
enum MeshPhysicsMode {
|
||||
MESH_PHYSICS_DISABLED,
|
||||
MESH_PHYSICS_MESH_AND_STATIC_COLLIDER,
|
||||
MESH_PHYSICS_RIGID_BODY_AND_MESH,
|
||||
MESH_PHYSICS_STATIC_COLLIDER_ONLY,
|
||||
MESH_PHYSICS_AREA_ONLY,
|
||||
};
|
||||
|
||||
enum NavMeshMode {
|
||||
NAVMESH_DISABLED,
|
||||
NAVMESH_MESH_AND_NAVMESH,
|
||||
NAVMESH_NAVMESH_ONLY,
|
||||
};
|
||||
|
||||
enum MeshOverride {
|
||||
MESH_OVERRIDE_DEFAULT,
|
||||
MESH_OVERRIDE_ENABLE,
|
||||
MESH_OVERRIDE_DISABLE,
|
||||
};
|
||||
|
||||
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
|
||||
void _generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes);
|
||||
void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache);
|
||||
|
||||
public:
|
||||
static ResourceImporterScene *get_singleton() { return singleton; }
|
||||
|
@ -141,26 +139,39 @@ public:
|
|||
virtual int get_preset_count() const override;
|
||||
virtual String get_preset_name(int p_idx) const override;
|
||||
|
||||
enum InternalImportCategory {
|
||||
INTERNAL_IMPORT_CATEGORY_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_MESH,
|
||||
INTERNAL_IMPORT_CATEGORY_MATERIAL,
|
||||
INTERNAL_IMPORT_CATEGORY_ANIMATION,
|
||||
INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_MAX
|
||||
};
|
||||
|
||||
void get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const;
|
||||
bool get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
|
||||
|
||||
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
|
||||
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
|
||||
virtual int get_import_order() const override { return 100; } //after everything
|
||||
|
||||
void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes);
|
||||
Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map);
|
||||
Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
|
||||
|
||||
void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_animations_as_text, bool p_keep_animations, bool p_make_materials, bool p_materials_as_text, bool p_keep_materials, bool p_make_meshes, bool p_meshes_as_text, Map<Ref<Animation>, Ref<Animation>> &p_animations, Map<Ref<Material>, Ref<Material>> &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh>> &p_meshes);
|
||||
|
||||
Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode);
|
||||
|
||||
void _create_clips(Node *scene, const Array &p_clips, bool p_bake_all);
|
||||
void _filter_anim_tracks(Ref<Animation> anim, Set<String> &keep);
|
||||
void _filter_tracks(Node *scene, const String &p_text);
|
||||
void _optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
|
||||
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
|
||||
void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
|
||||
void _optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
|
||||
|
||||
Node *pre_import(const String &p_source_file);
|
||||
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
|
||||
|
||||
Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
|
||||
Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
|
||||
|
||||
virtual bool has_advanced_options() const override;
|
||||
virtual void show_advanced_options(const String &p_path) override;
|
||||
|
||||
ResourceImporterScene();
|
||||
};
|
||||
|
||||
|
|
1199
editor/import/scene_import_settings.cpp
Normal file
1199
editor/import/scene_import_settings.cpp
Normal file
File diff suppressed because it is too large
Load diff
199
editor/import/scene_import_settings.h
Normal file
199
editor/import/scene_import_settings.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*************************************************************************/
|
||||
/* scene_import_settings.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 SCENEIMPORTSETTINGS_H
|
||||
#define SCENEIMPORTSETTINGS_H
|
||||
|
||||
#include "editor/editor_file_dialog.h"
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
#include "scene/3d/light_3d.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/item_list.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/split_container.h"
|
||||
#include "scene/gui/subviewport_container.h"
|
||||
#include "scene/gui/tab_container.h"
|
||||
#include "scene/gui/tree.h"
|
||||
#include "scene/resources/primitive_meshes.h"
|
||||
|
||||
class SceneImportSettingsData;
|
||||
|
||||
class SceneImportSettings : public ConfirmationDialog {
|
||||
GDCLASS(SceneImportSettings, ConfirmationDialog)
|
||||
|
||||
static SceneImportSettings *singleton;
|
||||
|
||||
enum Actions {
|
||||
ACTION_EXTRACT_MATERIALS,
|
||||
ACTION_CHOOSE_MESH_SAVE_PATHS,
|
||||
ACTION_CHOOSE_ANIMATION_SAVE_PATHS,
|
||||
};
|
||||
|
||||
Node *scene = nullptr;
|
||||
|
||||
HSplitContainer *tree_split;
|
||||
HSplitContainer *property_split;
|
||||
TabContainer *data_mode;
|
||||
Tree *scene_tree;
|
||||
Tree *mesh_tree;
|
||||
Tree *material_tree;
|
||||
|
||||
EditorInspector *inspector;
|
||||
|
||||
SubViewport *base_viewport;
|
||||
|
||||
Camera3D *camera;
|
||||
bool first_aabb = false;
|
||||
AABB contents_aabb;
|
||||
|
||||
DirectionalLight3D *light;
|
||||
Ref<ArrayMesh> selection_mesh;
|
||||
MeshInstance3D *node_selected;
|
||||
|
||||
MeshInstance3D *mesh_preview;
|
||||
Ref<SphereMesh> material_preview;
|
||||
|
||||
float cam_rot_x;
|
||||
float cam_rot_y;
|
||||
float cam_zoom;
|
||||
|
||||
void _update_scene();
|
||||
|
||||
struct MaterialData {
|
||||
bool has_import_id;
|
||||
Ref<Material> material;
|
||||
TreeItem *scene_node;
|
||||
TreeItem *mesh_node;
|
||||
TreeItem *material_node;
|
||||
|
||||
float cam_rot_x = -Math_PI / 4;
|
||||
float cam_rot_y = -Math_PI / 4;
|
||||
float cam_zoom = 1;
|
||||
|
||||
Map<StringName, Variant> settings;
|
||||
};
|
||||
Map<String, MaterialData> material_map;
|
||||
|
||||
struct MeshData {
|
||||
bool has_import_id;
|
||||
Ref<Mesh> mesh;
|
||||
TreeItem *scene_node;
|
||||
TreeItem *mesh_node;
|
||||
|
||||
float cam_rot_x = -Math_PI / 4;
|
||||
float cam_rot_y = -Math_PI / 4;
|
||||
float cam_zoom = 1;
|
||||
Map<StringName, Variant> settings;
|
||||
};
|
||||
Map<String, MeshData> mesh_map;
|
||||
|
||||
struct AnimationData {
|
||||
Ref<Animation> animation;
|
||||
TreeItem *scene_node;
|
||||
Map<StringName, Variant> settings;
|
||||
};
|
||||
Map<String, AnimationData> animation_map;
|
||||
|
||||
struct NodeData {
|
||||
Node *node;
|
||||
TreeItem *scene_node;
|
||||
Map<StringName, Variant> settings;
|
||||
};
|
||||
Map<String, NodeData> node_map;
|
||||
|
||||
void _fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent);
|
||||
void _fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent);
|
||||
void _fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent);
|
||||
void _fill_scene(Node *p_node, TreeItem *p_parent_item);
|
||||
|
||||
Set<Ref<Mesh>> mesh_set;
|
||||
Set<Ref<Material>> material_set;
|
||||
|
||||
String selected_type;
|
||||
String selected_id;
|
||||
|
||||
bool selecting = false;
|
||||
|
||||
void _update_camera();
|
||||
void _select(Tree *p_from, String p_type, String p_id);
|
||||
void _material_tree_selected();
|
||||
void _mesh_tree_selected();
|
||||
void _scene_tree_selected();
|
||||
|
||||
void _viewport_input(const Ref<InputEvent> &p_input);
|
||||
|
||||
Map<StringName, Variant> defaults;
|
||||
|
||||
SceneImportSettingsData *scene_import_settings_data;
|
||||
|
||||
void _re_import();
|
||||
|
||||
String base_path;
|
||||
|
||||
MenuButton *action_menu;
|
||||
|
||||
ConfirmationDialog *external_paths;
|
||||
Tree *external_path_tree;
|
||||
EditorFileDialog *save_path;
|
||||
OptionButton *external_extension_type;
|
||||
|
||||
EditorFileDialog *item_save_path;
|
||||
|
||||
void _menu_callback(int p_id);
|
||||
void _save_dir_callback(const String &p_path);
|
||||
|
||||
int current_action;
|
||||
|
||||
Vector<TreeItem *> save_path_items;
|
||||
|
||||
TreeItem *save_path_item = nullptr;
|
||||
void _save_path_changed(const String &p_path);
|
||||
void _browse_save_callback(Object *p_item, int p_column, int p_id);
|
||||
void _save_dir_confirm();
|
||||
|
||||
Dictionary base_subresource_settings;
|
||||
|
||||
void _load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void open_settings(const String &p_path);
|
||||
static SceneImportSettings *get_singleton();
|
||||
SceneImportSettings();
|
||||
~SceneImportSettings();
|
||||
};
|
||||
|
||||
#endif // SCENEIMPORTSETTINGS_H
|
|
@ -136,6 +136,11 @@ Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const
|
|||
return surfaces[p_surface].material;
|
||||
}
|
||||
|
||||
void EditorSceneImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
|
||||
ERR_FAIL_INDEX(p_surface, surfaces.size());
|
||||
surfaces.write[p_surface].material = p_material;
|
||||
}
|
||||
|
||||
void EditorSceneImporterMesh::generate_lods() {
|
||||
if (!SurfaceTool::simplify_func) {
|
||||
return;
|
||||
|
@ -219,11 +224,20 @@ bool EditorSceneImporterMesh::has_mesh() const {
|
|||
return mesh.is_valid();
|
||||
}
|
||||
|
||||
Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
|
||||
Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<Mesh> &p_base) {
|
||||
ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
|
||||
|
||||
if (mesh.is_null()) {
|
||||
mesh.instance();
|
||||
if (p_base.is_valid()) {
|
||||
mesh = p_base;
|
||||
}
|
||||
if (mesh.is_null()) {
|
||||
mesh.instance();
|
||||
}
|
||||
mesh->set_name(get_name());
|
||||
if (has_meta("import_id")) {
|
||||
mesh->set_meta("import_id", get_meta("import_id"));
|
||||
}
|
||||
for (int i = 0; i < blend_shapes.size(); i++) {
|
||||
mesh->add_blend_shape(blend_shapes[i]);
|
||||
}
|
||||
|
@ -251,6 +265,8 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
|
|||
}
|
||||
}
|
||||
|
||||
mesh->set_lightmap_size_hint(lightmap_size_hint);
|
||||
|
||||
if (shadow_mesh.is_valid()) {
|
||||
Ref<ArrayMesh> shadow = shadow_mesh->get_mesh();
|
||||
mesh->set_shadow_mesh(shadow);
|
||||
|
@ -436,6 +452,338 @@ Dictionary EditorSceneImporterMesh::_get_data() const {
|
|||
return data;
|
||||
}
|
||||
|
||||
Vector<Face3> EditorSceneImporterMesh::get_faces() const {
|
||||
Vector<Face3> faces;
|
||||
for (int i = 0; i < surfaces.size(); i++) {
|
||||
if (surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
|
||||
Vector<Vector3> vertices = surfaces[i].arrays[Mesh::ARRAY_VERTEX];
|
||||
Vector<int> indices = surfaces[i].arrays[Mesh::ARRAY_INDEX];
|
||||
if (indices.size()) {
|
||||
for (int j = 0; j < indices.size(); j += 3) {
|
||||
Face3 f;
|
||||
f.vertex[0] = vertices[indices[j + 0]];
|
||||
f.vertex[1] = vertices[indices[j + 1]];
|
||||
f.vertex[2] = vertices[indices[j + 2]];
|
||||
faces.push_back(f);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < vertices.size(); j += 3) {
|
||||
Face3 f;
|
||||
f.vertex[0] = vertices[j + 0];
|
||||
f.vertex[1] = vertices[j + 1];
|
||||
f.vertex[2] = vertices[j + 2];
|
||||
faces.push_back(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return faces;
|
||||
}
|
||||
|
||||
Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose() const {
|
||||
ERR_FAIL_COND_V(!Mesh::convex_composition_function, Vector<Ref<Shape3D>>());
|
||||
|
||||
const Vector<Face3> faces = get_faces();
|
||||
|
||||
Vector<Vector<Face3>> decomposed = Mesh::convex_composition_function(faces);
|
||||
|
||||
Vector<Ref<Shape3D>> ret;
|
||||
|
||||
for (int i = 0; i < decomposed.size(); i++) {
|
||||
Set<Vector3> points;
|
||||
for (int j = 0; j < decomposed[i].size(); j++) {
|
||||
points.insert(decomposed[i][j].vertex[0]);
|
||||
points.insert(decomposed[i][j].vertex[1]);
|
||||
points.insert(decomposed[i][j].vertex[2]);
|
||||
}
|
||||
|
||||
Vector<Vector3> convex_points;
|
||||
convex_points.resize(points.size());
|
||||
{
|
||||
Vector3 *w = convex_points.ptrw();
|
||||
int idx = 0;
|
||||
for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
|
||||
w[idx++] = E->get();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<ConvexPolygonShape3D> shape;
|
||||
shape.instance();
|
||||
shape->set_points(convex_points);
|
||||
ret.push_back(shape);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
|
||||
Vector<Face3> faces = get_faces();
|
||||
if (faces.size() == 0) {
|
||||
return Ref<Shape3D>();
|
||||
}
|
||||
|
||||
Vector<Vector3> face_points;
|
||||
face_points.resize(faces.size() * 3);
|
||||
|
||||
for (int i = 0; i < face_points.size(); i += 3) {
|
||||
Face3 f = faces.get(i / 3);
|
||||
face_points.set(i, f.vertex[0]);
|
||||
face_points.set(i + 1, f.vertex[1]);
|
||||
face_points.set(i + 2, f.vertex[2]);
|
||||
}
|
||||
|
||||
Ref<ConcavePolygonShape3D> shape = memnew(ConcavePolygonShape3D);
|
||||
shape->set_faces(face_points);
|
||||
return shape;
|
||||
}
|
||||
|
||||
Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
|
||||
Vector<Face3> faces = get_faces();
|
||||
if (faces.size() == 0) {
|
||||
return Ref<NavigationMesh>();
|
||||
}
|
||||
|
||||
Map<Vector3, int> unique_vertices;
|
||||
LocalVector<int> face_indices;
|
||||
|
||||
for (int i = 0; i < faces.size(); i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Vector3 v = faces[i].vertex[j];
|
||||
int idx;
|
||||
if (unique_vertices.has(v)) {
|
||||
idx = unique_vertices[v];
|
||||
} else {
|
||||
idx = unique_vertices.size();
|
||||
unique_vertices[v] = idx;
|
||||
}
|
||||
face_indices.push_back(idx);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Vector3> vertices;
|
||||
vertices.resize(unique_vertices.size());
|
||||
for (Map<Vector3, int>::Element *E = unique_vertices.front(); E; E = E->next()) {
|
||||
vertices.write[E->get()] = E->key();
|
||||
}
|
||||
|
||||
Ref<NavigationMesh> nm;
|
||||
nm.instance();
|
||||
nm->set_vertices(vertices);
|
||||
|
||||
Vector<int> v3;
|
||||
v3.resize(3);
|
||||
for (uint32_t i = 0; i < face_indices.size(); i += 3) {
|
||||
v3.write[0] = face_indices[i + 0];
|
||||
v3.write[1] = face_indices[i + 1];
|
||||
v3.write[2] = face_indices[i + 2];
|
||||
nm->add_polygon(v3);
|
||||
}
|
||||
|
||||
return nm;
|
||||
}
|
||||
|
||||
extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
|
||||
|
||||
struct EditorSceneImporterMeshLightmapSurface {
|
||||
Ref<Material> material;
|
||||
LocalVector<SurfaceTool::Vertex> vertices;
|
||||
Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX;
|
||||
uint32_t format = 0;
|
||||
String name;
|
||||
};
|
||||
|
||||
Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
|
||||
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
|
||||
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
|
||||
|
||||
Vector<float> vertices;
|
||||
Vector<float> normals;
|
||||
Vector<int> indices;
|
||||
Vector<float> uv;
|
||||
Vector<Pair<int, int>> uv_indices;
|
||||
|
||||
Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces;
|
||||
|
||||
// Keep only the scale
|
||||
Transform transform = p_base_transform;
|
||||
transform.origin = Vector3();
|
||||
transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
|
||||
|
||||
Basis normal_basis = transform.basis.inverse().transposed();
|
||||
|
||||
for (int i = 0; i < get_surface_count(); i++) {
|
||||
EditorSceneImporterMeshLightmapSurface s;
|
||||
s.primitive = get_surface_primitive_type(i);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(s.primitive != Mesh::PRIMITIVE_TRIANGLES, ERR_UNAVAILABLE, "Only triangles are supported for lightmap unwrap.");
|
||||
Array arrays = get_surface_arrays(i);
|
||||
s.material = get_surface_material(i);
|
||||
s.name = get_surface_name(i);
|
||||
|
||||
SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
|
||||
|
||||
Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
|
||||
int vc = rvertices.size();
|
||||
const Vector3 *r = rvertices.ptr();
|
||||
|
||||
Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
|
||||
|
||||
ERR_FAIL_COND_V_MSG(rnormals.size() == 0, ERR_UNAVAILABLE, "Normals are required for lightmap unwrap.");
|
||||
|
||||
const Vector3 *rn = rnormals.ptr();
|
||||
|
||||
int vertex_ofs = vertices.size() / 3;
|
||||
|
||||
vertices.resize((vertex_ofs + vc) * 3);
|
||||
normals.resize((vertex_ofs + vc) * 3);
|
||||
uv_indices.resize(vertex_ofs + vc);
|
||||
|
||||
for (int j = 0; j < vc; j++) {
|
||||
Vector3 v = transform.xform(r[j]);
|
||||
Vector3 n = normal_basis.xform(rn[j]).normalized();
|
||||
|
||||
vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
|
||||
vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
|
||||
vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
|
||||
normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
|
||||
normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
|
||||
normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
|
||||
uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
|
||||
}
|
||||
|
||||
Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
|
||||
int ic = rindices.size();
|
||||
|
||||
if (ic == 0) {
|
||||
for (int j = 0; j < vc / 3; j++) {
|
||||
if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
indices.push_back(vertex_ofs + j * 3 + 0);
|
||||
indices.push_back(vertex_ofs + j * 3 + 1);
|
||||
indices.push_back(vertex_ofs + j * 3 + 2);
|
||||
}
|
||||
|
||||
} else {
|
||||
const int *ri = rindices.ptr();
|
||||
|
||||
for (int j = 0; j < ic / 3; j++) {
|
||||
if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
|
||||
continue;
|
||||
}
|
||||
indices.push_back(vertex_ofs + ri[j * 3 + 0]);
|
||||
indices.push_back(vertex_ofs + ri[j * 3 + 1]);
|
||||
indices.push_back(vertex_ofs + ri[j * 3 + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
lightmap_surfaces.push_back(s);
|
||||
}
|
||||
|
||||
//unwrap
|
||||
|
||||
float *gen_uvs;
|
||||
int *gen_vertices;
|
||||
int *gen_indices;
|
||||
int gen_vertex_count;
|
||||
int gen_index_count;
|
||||
int size_x;
|
||||
int size_y;
|
||||
|
||||
bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
|
||||
|
||||
if (!ok) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
//remove surfaces
|
||||
clear();
|
||||
|
||||
//create surfacetools for each surface..
|
||||
Vector<Ref<SurfaceTool>> surfaces_tools;
|
||||
|
||||
for (int i = 0; i < lightmap_surfaces.size(); i++) {
|
||||
Ref<SurfaceTool> st;
|
||||
st.instance();
|
||||
st->begin(Mesh::PRIMITIVE_TRIANGLES);
|
||||
st->set_material(lightmap_surfaces[i].material);
|
||||
st->set_meta("name", lightmap_surfaces[i].name);
|
||||
surfaces_tools.push_back(st); //stay there
|
||||
}
|
||||
|
||||
print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
|
||||
//go through all indices
|
||||
for (int i = 0; i < gen_index_count; i += 3) {
|
||||
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
|
||||
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
|
||||
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
|
||||
|
||||
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
|
||||
|
||||
int surface = uv_indices[gen_vertices[gen_indices[i + 0]]].first;
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
|
||||
|
||||
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) {
|
||||
surfaces_tools.write[surface]->set_color(v.color);
|
||||
}
|
||||
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) {
|
||||
surfaces_tools.write[surface]->set_uv(v.uv);
|
||||
}
|
||||
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) {
|
||||
surfaces_tools.write[surface]->set_normal(v.normal);
|
||||
}
|
||||
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) {
|
||||
Plane t;
|
||||
t.normal = v.tangent;
|
||||
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
|
||||
surfaces_tools.write[surface]->set_tangent(t);
|
||||
}
|
||||
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) {
|
||||
surfaces_tools.write[surface]->set_bones(v.bones);
|
||||
}
|
||||
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
|
||||
surfaces_tools.write[surface]->set_weights(v.weights);
|
||||
}
|
||||
|
||||
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
|
||||
surfaces_tools.write[surface]->set_uv2(uv2);
|
||||
|
||||
surfaces_tools.write[surface]->add_vertex(v.vertex);
|
||||
}
|
||||
}
|
||||
|
||||
//generate surfaces
|
||||
|
||||
for (int i = 0; i < surfaces_tools.size(); i++) {
|
||||
surfaces_tools.write[i]->index();
|
||||
Array arrays = surfaces_tools.write[i]->commit_to_arrays();
|
||||
add_surface(surfaces_tools.write[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools.write[i]->get_material(), surfaces_tools.write[i]->get_meta("name"));
|
||||
}
|
||||
|
||||
set_lightmap_size_hint(Size2(size_x, size_y));
|
||||
|
||||
if (!r_used_cache) {
|
||||
//free stuff
|
||||
::free(gen_vertices);
|
||||
::free(gen_indices);
|
||||
::free(gen_uvs);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void EditorSceneImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
|
||||
lightmap_size_hint = p_size;
|
||||
}
|
||||
|
||||
Size2i EditorSceneImporterMesh::get_lightmap_size_hint() const {
|
||||
return lightmap_size_hint;
|
||||
}
|
||||
|
||||
void EditorSceneImporterMesh::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count);
|
||||
|
@ -462,5 +810,8 @@ void EditorSceneImporterMesh::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
|
||||
ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &EditorSceneImporterMesh::set_lightmap_size_hint);
|
||||
ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &EditorSceneImporterMesh::get_lightmap_size_hint);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
|
||||
}
|
||||
|
|
|
@ -32,7 +32,10 @@
|
|||
#define EDITOR_SCENE_IMPORTER_MESH_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "scene/resources/concave_polygon_shape_3d.h"
|
||||
#include "scene/resources/convex_polygon_shape_3d.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
#include "scene/resources/navigation_mesh.h"
|
||||
// The following classes are used by importers instead of ArrayMesh and MeshInstance3D
|
||||
// so the data is not registered (hence, quality loss), importing happens faster and
|
||||
// its easier to modify before saving
|
||||
|
@ -63,6 +66,8 @@ class EditorSceneImporterMesh : public Resource {
|
|||
|
||||
Ref<EditorSceneImporterMesh> shadow_mesh;
|
||||
|
||||
Size2i lightmap_size_hint;
|
||||
|
||||
protected:
|
||||
void _set_data(const Dictionary &p_data);
|
||||
Dictionary _get_data() const;
|
||||
|
@ -89,13 +94,24 @@ public:
|
|||
float get_surface_lod_size(int p_surface, int p_lod) const;
|
||||
Ref<Material> get_surface_material(int p_surface) const;
|
||||
|
||||
void set_surface_material(int p_surface, const Ref<Material> &p_material);
|
||||
|
||||
void generate_lods();
|
||||
|
||||
void create_shadow_mesh();
|
||||
Ref<EditorSceneImporterMesh> get_shadow_mesh() const;
|
||||
|
||||
Vector<Face3> get_faces() const;
|
||||
Vector<Ref<Shape3D>> convex_decompose() const;
|
||||
Ref<Shape3D> create_trimesh_shape() const;
|
||||
Ref<NavigationMesh> create_navigation_mesh();
|
||||
Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size);
|
||||
|
||||
void set_lightmap_size_hint(const Size2i &p_size);
|
||||
Size2i get_lightmap_size_hint() const;
|
||||
|
||||
bool has_mesh() const;
|
||||
Ref<ArrayMesh> get_mesh();
|
||||
Ref<ArrayMesh> get_mesh(const Ref<Mesh> &p_base = Ref<Mesh>());
|
||||
void clear();
|
||||
};
|
||||
#endif // EDITOR_SCENE_IMPORTER_MESH_H
|
||||
|
|
|
@ -156,6 +156,14 @@ void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
|
|||
|
||||
params->update();
|
||||
_update_preset_menu();
|
||||
|
||||
if (params->paths.size() == 1 && params->importer->has_advanced_options()) {
|
||||
advanced->show();
|
||||
advanced_spacer->show();
|
||||
} else {
|
||||
advanced->hide();
|
||||
advanced_spacer->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
|
||||
|
@ -258,6 +266,14 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
|
|||
preset->set_disabled(false);
|
||||
|
||||
imported->set_text(vformat(TTR("%d Files"), p_paths.size()));
|
||||
|
||||
if (params->paths.size() == 1 && params->importer->has_advanced_options()) {
|
||||
advanced->show();
|
||||
advanced_spacer->show();
|
||||
} else {
|
||||
advanced->hide();
|
||||
advanced_spacer->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDock::_update_preset_menu() {
|
||||
|
@ -422,6 +438,11 @@ void ImportDock::_reimport_and_restart() {
|
|||
EditorNode::get_singleton()->restart_editor();
|
||||
}
|
||||
|
||||
void ImportDock::_advanced_options() {
|
||||
if (params->paths.size() == 1 && params->importer.is_valid()) {
|
||||
params->importer->show_advanced_options(params->paths[0]);
|
||||
}
|
||||
}
|
||||
void ImportDock::_reimport() {
|
||||
for (int i = 0; i < params->paths.size(); i++) {
|
||||
Ref<ConfigFile> config;
|
||||
|
@ -531,10 +552,27 @@ ImportDock::ImportDock() {
|
|||
import->set_text(TTR("Reimport"));
|
||||
import->set_disabled(true);
|
||||
import->connect("pressed", callable_mp(this, &ImportDock::_reimport_attempt));
|
||||
if (!DisplayServer::get_singleton()->get_swap_cancel_ok()) {
|
||||
advanced_spacer = hb->add_spacer();
|
||||
advanced = memnew(Button);
|
||||
advanced->set_text(TTR("Advanced..."));
|
||||
hb->add_child(advanced);
|
||||
}
|
||||
hb->add_spacer();
|
||||
hb->add_child(import);
|
||||
hb->add_spacer();
|
||||
|
||||
if (DisplayServer::get_singleton()->get_swap_cancel_ok()) {
|
||||
advanced = memnew(Button);
|
||||
advanced->set_text(TTR("Advanced..."));
|
||||
hb->add_child(advanced);
|
||||
advanced_spacer = hb->add_spacer();
|
||||
}
|
||||
|
||||
advanced->hide();
|
||||
advanced_spacer->hide();
|
||||
advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options));
|
||||
|
||||
reimport_confirm = memnew(ConfirmationDialog);
|
||||
reimport_confirm->get_ok_button()->set_text(TTR("Save Scenes, Re-Import, and Restart"));
|
||||
add_child(reimport_confirm);
|
||||
|
|
|
@ -57,6 +57,9 @@ class ImportDock : public VBoxContainer {
|
|||
Label *label_warning;
|
||||
Button *import;
|
||||
|
||||
Control *advanced_spacer;
|
||||
Button *advanced;
|
||||
|
||||
ImportDockParameters *params;
|
||||
|
||||
void _preset_selected(int p_idx);
|
||||
|
@ -69,6 +72,7 @@ class ImportDock : public VBoxContainer {
|
|||
void _reimport_and_restart();
|
||||
void _reimport();
|
||||
|
||||
void _advanced_options();
|
||||
enum {
|
||||
ITEM_SET_AS_DEFAULT = 100,
|
||||
ITEM_LOAD_DEFAULT,
|
||||
|
|
|
@ -628,7 +628,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
|
|||
mesh_data_precached->mesh_node = fbx_node;
|
||||
|
||||
// mesh node, mesh id
|
||||
mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, (p_flags & IMPORT_USE_COMPRESSION) != 0);
|
||||
mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, 0);
|
||||
if (!state.MeshNodes.has(mesh_id)) {
|
||||
state.MeshNodes.insert(mesh_id, fbx_node);
|
||||
}
|
||||
|
|
|
@ -99,7 +99,9 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
|
|||
Ref<GLTFDocument> gltf_document;
|
||||
gltf_document.instance();
|
||||
Error err = gltf_document->parse(r_state, p_path);
|
||||
*r_err = err;
|
||||
if (r_err) {
|
||||
*r_err = err;
|
||||
}
|
||||
ERR_FAIL_COND_V(err != Error::OK, nullptr);
|
||||
|
||||
Node3D *root = memnew(Node3D);
|
||||
|
|
|
@ -313,7 +313,7 @@ BoxContainer::AlignMode BoxContainer::get_alignment() const {
|
|||
return align;
|
||||
}
|
||||
|
||||
void BoxContainer::add_spacer(bool p_begin) {
|
||||
Control *BoxContainer::add_spacer(bool p_begin) {
|
||||
Control *c = memnew(Control);
|
||||
c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events
|
||||
|
||||
|
@ -327,6 +327,8 @@ void BoxContainer::add_spacer(bool p_begin) {
|
|||
if (p_begin) {
|
||||
move_child(c, 0);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
BoxContainer::BoxContainer(bool p_vertical) {
|
||||
|
|
|
@ -55,7 +55,7 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void add_spacer(bool p_begin = false);
|
||||
Control *add_spacer(bool p_begin = false);
|
||||
|
||||
void set_alignment(AlignMode p_align);
|
||||
AlignMode get_alignment() const;
|
||||
|
|
|
@ -410,6 +410,14 @@ bool TreeItem::is_collapsed() {
|
|||
return collapsed;
|
||||
}
|
||||
|
||||
void TreeItem::uncollapse_tree() {
|
||||
TreeItem *t = this;
|
||||
while (t) {
|
||||
t->set_collapsed(false);
|
||||
t = t->parent;
|
||||
}
|
||||
}
|
||||
|
||||
void TreeItem::set_custom_minimum_height(int p_height) {
|
||||
custom_min_height = p_height;
|
||||
_changed_notify();
|
||||
|
@ -842,6 +850,8 @@ void TreeItem::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
|
||||
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
|
||||
ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height);
|
||||
|
||||
|
|
|
@ -229,6 +229,8 @@ public:
|
|||
void set_collapsed(bool p_collapsed);
|
||||
bool is_collapsed();
|
||||
|
||||
void uncollapse_tree();
|
||||
|
||||
void set_custom_minimum_height(int p_height);
|
||||
int get_custom_minimum_height() const;
|
||||
|
||||
|
|
|
@ -893,12 +893,13 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
|
|||
}
|
||||
|
||||
if (exclusive_child != nullptr) {
|
||||
/*
|
||||
Window *focus_target = exclusive_child;
|
||||
focus_target->grab_focus();
|
||||
while (focus_target->exclusive_child != nullptr) {
|
||||
focus_target = focus_target->exclusive_child;
|
||||
focus_target->grab_focus();
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!is_embedding_subwindows()) { //not embedding, no need for event
|
||||
return;
|
||||
|
|
|
@ -1059,6 +1059,10 @@ void SurfaceTool::set_material(const Ref<Material> &p_material) {
|
|||
material = p_material;
|
||||
}
|
||||
|
||||
Ref<Material> SurfaceTool::get_material() const {
|
||||
return material;
|
||||
}
|
||||
|
||||
void SurfaceTool::clear() {
|
||||
begun = false;
|
||||
primitive = Mesh::PRIMITIVE_LINES;
|
||||
|
@ -1088,6 +1092,10 @@ void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
|
|||
ERR_FAIL_COND(begun);
|
||||
last_custom_format[p_index] = p_format;
|
||||
}
|
||||
|
||||
Mesh::PrimitiveType SurfaceTool::get_primitive() const {
|
||||
return primitive;
|
||||
}
|
||||
SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
|
||||
return last_custom_format[p_index];
|
||||
|
@ -1174,6 +1182,7 @@ void SurfaceTool::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
|
||||
ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
|
||||
|
||||
|
|
|
@ -143,6 +143,8 @@ public:
|
|||
void set_custom_format(int p_index, CustomFormat p_format);
|
||||
CustomFormat get_custom_format(int p_index) const;
|
||||
|
||||
Mesh::PrimitiveType get_primitive() const;
|
||||
|
||||
void begin(Mesh::PrimitiveType p_primitive);
|
||||
|
||||
void set_color(Color p_color);
|
||||
|
@ -171,6 +173,7 @@ public:
|
|||
Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
|
||||
|
||||
void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
void clear();
|
||||
|
||||
|
|
Loading…
Reference in a new issue