feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#include "collada.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
//#define DEBUG_DEFAULT_ANIMATION
|
||||
//#define DEBUG_COLLADA
|
||||
|
|
@ -1808,10 +1808,10 @@ void Collada::_parse_animation(XMLParser &p_parser) {
|
|||
}
|
||||
}
|
||||
|
||||
if (target.contains("/")) { //transform component
|
||||
if (target.contains_char('/')) { //transform component
|
||||
track.target = target.get_slicec('/', 0);
|
||||
track.param = target.get_slicec('/', 1);
|
||||
if (track.param.contains(".")) {
|
||||
if (track.param.contains_char('.')) {
|
||||
track.component = track.param.get_slice(".", 1).to_upper();
|
||||
}
|
||||
track.param = track.param.get_slice(".", 0);
|
||||
|
|
|
|||
|
|
@ -31,10 +31,7 @@
|
|||
#ifndef COLLADA_H
|
||||
#define COLLADA_H
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/xml_parser.h"
|
||||
#include "core/templates/rb_map.h"
|
||||
#include "scene/resources/material.h"
|
||||
|
||||
class Collada {
|
||||
public:
|
||||
|
|
@ -359,7 +356,7 @@ public:
|
|||
for (int i = 0; i < children.size(); i++) {
|
||||
memdelete(children[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeSkeleton : public Node {
|
||||
|
|
|
|||
|
|
@ -30,20 +30,17 @@
|
|||
|
||||
#include "editor_import_collada.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "editor/import/3d/collada.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/light_3d.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/path_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/3d/importer_mesh.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
struct ColladaImport {
|
||||
|
|
@ -1263,7 +1260,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
|
|||
//bleh, must ignore invalid
|
||||
|
||||
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
|
||||
mesh = Ref<ImporterMesh>(memnew(ImporterMesh));
|
||||
mesh.instantiate();
|
||||
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
|
||||
String name = meshdata.name;
|
||||
if (name.is_empty()) {
|
||||
|
|
@ -1290,7 +1287,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
|
|||
}
|
||||
}
|
||||
|
||||
if (!mesh.is_null()) {
|
||||
if (mesh.is_valid()) {
|
||||
mi->set_mesh(mesh);
|
||||
if (!use_mesh_builtin_materials) {
|
||||
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
|
||||
|
|
@ -1799,10 +1796,6 @@ void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) {
|
|||
/*************************************** SCENE ***********************************/
|
||||
/*********************************************************************************/
|
||||
|
||||
uint32_t EditorSceneFormatImporterCollada::get_import_flags() const {
|
||||
return IMPORT_SCENE | IMPORT_ANIMATION;
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporterCollada::get_extensions(List<String> *r_extensions) const {
|
||||
r_extensions->push_back("dae");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class EditorSceneFormatImporterCollada : public EditorSceneFormatImporter {
|
|||
GDCLASS(EditorSceneFormatImporterCollada, EditorSceneFormatImporter);
|
||||
|
||||
public:
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "post_import_plugin_skeleton_renamer.h"
|
||||
|
||||
#include "editor/import/3d/scene_import_settings.h"
|
||||
#include "scene/3d/bone_attachment_3d.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
|
|
@ -39,7 +38,7 @@
|
|||
|
||||
void PostImportPluginSkeletonRenamer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
|
||||
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/rename_bones"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/rename_bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/unique_node/make_unique"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::STRING, "retarget/bone_renamer/unique_node/skeleton_name"), "GeneralSkeleton"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@
|
|||
|
||||
#include "post_import_plugin_skeleton_rest_fixer.h"
|
||||
|
||||
#include "editor/import/3d/scene_import_settings.h"
|
||||
#include "scene/3d/bone_attachment_3d.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/retarget_modifier_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/bone_map.h"
|
||||
|
|
@ -42,19 +42,29 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImpo
|
|||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/reset_all_bone_poses_after_import"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
|
||||
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "retarget/rest_fixer/retarget_method", PROPERTY_HINT_ENUM, "None,Overwrite Axis,Use Retarget Modifier", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/keep_global_rest_on_leftovers"), true));
|
||||
String skeleton_bones_must_be_renamed_warning = String(
|
||||
"The skeleton modifier option uses SkeletonProfile as a list of bone names and retargets by name matching. Without renaming, retargeting by modifier will not work and the track path of the animation will be broken and it will be not playbacked correctly."); // TODO: translate.
|
||||
r_options->push_back(ResourceImporter::ImportOption(
|
||||
PropertyInfo(
|
||||
Variant::STRING, U"retarget/rest_fixer/\u26A0_validation_warning/skeleton_bones_must_be_renamed",
|
||||
PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY),
|
||||
Variant(skeleton_bones_must_be_renamed_warning)));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/use_global_pose"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::STRING, "retarget/rest_fixer/original_skeleton_name"), "OriginalSkeleton"));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
|
||||
// TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
|
||||
// get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
|
||||
// r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/filter", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::STRING_NAME, PROPERTY_HINT_ENUM, "Hips,Spine,Chest")), Array()));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/fix_silhouette/filter", PROPERTY_HINT_ARRAY_TYPE, "StringName"), Array()));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/fix_silhouette/filter", PROPERTY_HINT_ARRAY_TYPE, vformat("%s:", Variant::STRING_NAME)), Array()));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/base_height_adjustment", PROPERTY_HINT_RANGE, "-1,1,0.01"), 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
Variant PostImportPluginSkeletonRestFixer::get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
Variant PostImportPluginSkeletonRestFixer::get_internal_option_visibility(InternalImportCategory p_category, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
|
||||
if (p_option.begins_with("retarget/rest_fixer/fix_silhouette/")) {
|
||||
if (!bool(p_options["retarget/rest_fixer/fix_silhouette/enable"])) {
|
||||
|
|
@ -63,7 +73,11 @@ Variant PostImportPluginSkeletonRestFixer::get_internal_option_visibility(Intern
|
|||
}
|
||||
}
|
||||
} else if (p_option == "retarget/rest_fixer/keep_global_rest_on_leftovers") {
|
||||
return bool(p_options["retarget/rest_fixer/overwrite_axis"]);
|
||||
return int(p_options["retarget/rest_fixer/retarget_method"]) == 1;
|
||||
} else if (p_option == "retarget/rest_fixer/original_skeleton_name" || p_option == "retarget/rest_fixer/use_global_pose") {
|
||||
return int(p_options["retarget/rest_fixer/retarget_method"]) == 2;
|
||||
} else if (p_option.begins_with("retarget/") && p_option.ends_with("skeleton_bones_must_be_renamed")) {
|
||||
return int(p_options["retarget/rest_fixer/retarget_method"]) == 2 && bool(p_options["retarget/bone_renamer/rename_bones"]) == false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -78,7 +92,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
}
|
||||
BoneMap *bone_map = Object::cast_to<BoneMap>(map);
|
||||
Ref<SkeletonProfile> profile = bone_map->get_profile();
|
||||
if (!profile.is_valid()) {
|
||||
if (profile.is_null()) {
|
||||
return;
|
||||
}
|
||||
Skeleton3D *src_skeleton = Object::cast_to<Skeleton3D>(p_node);
|
||||
|
|
@ -147,7 +161,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
src_skeleton->set_bone_pose_position(src_idx, src_skeleton->get_bone_pose_position(src_idx) * scl);
|
||||
}
|
||||
|
||||
// Fix animation.
|
||||
// Fix animation by changing node transform.
|
||||
bones_to_process = src_skeleton->get_parentless_bones();
|
||||
{
|
||||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
|
|
@ -224,6 +238,10 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
if (String(name).contains_char('/')) {
|
||||
continue; // Avoid animation library which may be created by importer dynamically.
|
||||
}
|
||||
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
|
||||
|
|
@ -454,8 +472,13 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
}
|
||||
}
|
||||
|
||||
// Overwrite axis.
|
||||
if (bool(p_options["retarget/rest_fixer/overwrite_axis"])) {
|
||||
bool is_using_modifier = int(p_options["retarget/rest_fixer/retarget_method"]) == 2;
|
||||
bool is_using_global_pose = bool(p_options["retarget/rest_fixer/use_global_pose"]);
|
||||
Skeleton3D *orig_skeleton = nullptr;
|
||||
Skeleton3D *profile_skeleton = nullptr;
|
||||
|
||||
// Retarget in some way.
|
||||
if (int(p_options["retarget/rest_fixer/retarget_method"]) > 0) {
|
||||
LocalVector<Transform3D> old_skeleton_rest;
|
||||
LocalVector<Transform3D> old_skeleton_global_rest;
|
||||
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
|
||||
|
|
@ -463,11 +486,151 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
|
||||
}
|
||||
|
||||
// Build structure for modifier.
|
||||
if (is_using_modifier) {
|
||||
orig_skeleton = src_skeleton;
|
||||
|
||||
// Duplicate src_skeleton to modify animation tracks, it will memdelele after that animation track modification.
|
||||
src_skeleton = memnew(Skeleton3D);
|
||||
for (int i = 0; i < orig_skeleton->get_bone_count(); i++) {
|
||||
src_skeleton->add_bone(orig_skeleton->get_bone_name(i));
|
||||
src_skeleton->set_bone_rest(i, orig_skeleton->get_bone_rest(i));
|
||||
src_skeleton->set_bone_pose(i, orig_skeleton->get_bone_pose(i));
|
||||
}
|
||||
for (int i = 0; i < orig_skeleton->get_bone_count(); i++) {
|
||||
src_skeleton->set_bone_parent(i, orig_skeleton->get_bone_parent(i));
|
||||
}
|
||||
src_skeleton->set_motion_scale(orig_skeleton->get_motion_scale());
|
||||
|
||||
// Rename orig_skeleton (previous src_skeleton), since it is not animated by animation track with GeneralSkeleton.
|
||||
String original_skeleton_name = String(p_options["retarget/rest_fixer/original_skeleton_name"]);
|
||||
String skel_name = orig_skeleton->get_name();
|
||||
ERR_FAIL_COND_MSG(original_skeleton_name.is_empty(), "Original skeleton name cannot be empty.");
|
||||
ERR_FAIL_COND_MSG(original_skeleton_name == skel_name, "Original skeleton name must be different from unique skeleton name.");
|
||||
|
||||
// Rename profile skeleton to be general skeleton.
|
||||
profile_skeleton = memnew(Skeleton3D);
|
||||
bool is_unique = orig_skeleton->is_unique_name_in_owner();
|
||||
if (is_unique) {
|
||||
orig_skeleton->set_unique_name_in_owner(false);
|
||||
}
|
||||
orig_skeleton->set_name(original_skeleton_name);
|
||||
profile_skeleton->set_name(skel_name);
|
||||
if (is_unique) {
|
||||
profile_skeleton->set_unique_name_in_owner(true);
|
||||
}
|
||||
// Build profile skeleton bones.
|
||||
int len = profile->get_bone_size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
profile_skeleton->add_bone(profile->get_bone_name(i));
|
||||
profile_skeleton->set_bone_rest(i, profile->get_reference_pose(i));
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
int target_parent = profile_skeleton->find_bone(profile->get_bone_parent(i));
|
||||
if (target_parent >= 0) {
|
||||
profile_skeleton->set_bone_parent(i, target_parent);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
Vector3 origin;
|
||||
int found = orig_skeleton->find_bone(profile->get_bone_name(i));
|
||||
String parent_name = profile->get_bone_parent(i);
|
||||
if (found >= 0) {
|
||||
origin = orig_skeleton->get_bone_global_rest(found).origin;
|
||||
if (profile->get_bone_name(i) != profile->get_root_bone()) {
|
||||
int src_parent = -1;
|
||||
while (src_parent < 0 && !parent_name.is_empty()) {
|
||||
src_parent = orig_skeleton->find_bone(parent_name);
|
||||
parent_name = profile->get_bone_parent(profile->find_bone(parent_name));
|
||||
}
|
||||
if (src_parent >= 0) {
|
||||
Transform3D parent_grest = orig_skeleton->get_bone_global_rest(src_parent);
|
||||
origin = origin - parent_grest.origin;
|
||||
}
|
||||
}
|
||||
}
|
||||
int target_parent = profile_skeleton->find_bone(profile->get_bone_parent(i));
|
||||
if (target_parent >= 0) {
|
||||
origin = profile_skeleton->get_bone_global_rest(target_parent).basis.get_rotation_quaternion().xform_inv(origin);
|
||||
}
|
||||
profile_skeleton->set_bone_rest(i, Transform3D(profile_skeleton->get_bone_rest(i).basis, origin));
|
||||
}
|
||||
profile_skeleton->set_motion_scale(orig_skeleton->get_motion_scale());
|
||||
profile_skeleton->reset_bone_poses();
|
||||
// Make structure with modifier.
|
||||
Node *owner = p_node->get_owner();
|
||||
|
||||
Node *pr = orig_skeleton->get_parent();
|
||||
pr->add_child(profile_skeleton);
|
||||
profile_skeleton->set_owner(owner);
|
||||
|
||||
RetargetModifier3D *mod = memnew(RetargetModifier3D);
|
||||
profile_skeleton->add_child(mod);
|
||||
mod->set_owner(owner);
|
||||
mod->set_name("RetargetModifier3D");
|
||||
|
||||
orig_skeleton->set_owner(nullptr);
|
||||
orig_skeleton->reparent(mod, false);
|
||||
orig_skeleton->set_owner(owner);
|
||||
orig_skeleton->set_unique_name_in_owner(true);
|
||||
|
||||
mod->set_use_global_pose(is_using_global_pose);
|
||||
mod->set_profile(profile);
|
||||
|
||||
// Fix skeleton name in animation.
|
||||
// Mapped skeleton is animated by %GenerarSkeleton:RenamedBoneName.
|
||||
// Unmapped skeleton is animated by %OriginalSkeleton:OriginalBoneName.
|
||||
if (is_using_modifier) {
|
||||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
String general_skeleton_pathname = UNIQUE_NODE_PREFIX + profile_skeleton->get_name();
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
if (anim->track_get_path(i).get_name_count() == 0) {
|
||||
return;
|
||||
}
|
||||
if (anim->track_get_path(i).get_name(0) == general_skeleton_pathname) {
|
||||
bool replace = false;
|
||||
if (anim->track_get_path(i).get_subname_count() > 0) {
|
||||
int found = profile_skeleton->find_bone(anim->track_get_path(i).get_concatenated_subnames());
|
||||
if (found < 0) {
|
||||
replace = true;
|
||||
}
|
||||
} else {
|
||||
replace = true;
|
||||
}
|
||||
if (replace) {
|
||||
String path_string = UNIQUE_NODE_PREFIX + original_skeleton_name;
|
||||
if (anim->track_get_path(i).get_name_count() > 1) {
|
||||
Vector<StringName> names = anim->track_get_path(i).get_names();
|
||||
names.remove_at(0);
|
||||
for (int j = 0; j < names.size(); j++) {
|
||||
path_string += "/" + names[i].operator String();
|
||||
}
|
||||
}
|
||||
if (anim->track_get_path(i).get_subname_count() > 0) {
|
||||
path_string = path_string + String(":") + anim->track_get_path(i).get_concatenated_subnames();
|
||||
}
|
||||
anim->track_set_path(i, path_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool keep_global_rest_leftovers = bool(p_options["retarget/rest_fixer/keep_global_rest_on_leftovers"]);
|
||||
|
||||
// Scan hierarchy and populate a whitelist of unmapped bones without mapped descendants.
|
||||
// When both is_using_modifier and is_using_global_pose are enabled, this array is used for detecting warning.
|
||||
Vector<int> keep_bone_rest;
|
||||
if (keep_global_rest_leftovers) {
|
||||
if (is_using_modifier || keep_global_rest_leftovers) {
|
||||
Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
|
||||
while (bones_to_process.size() > 0) {
|
||||
int src_idx = bones_to_process[0];
|
||||
|
|
@ -482,13 +645,13 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
// Scan descendants for mapped bones.
|
||||
bool found_mapped = false;
|
||||
|
||||
Vector<int> decendants_to_process = src_skeleton->get_bone_children(src_idx);
|
||||
while (decendants_to_process.size() > 0) {
|
||||
int desc_idx = decendants_to_process[0];
|
||||
decendants_to_process.erase(desc_idx);
|
||||
Vector<int> descendants_to_process = src_skeleton->get_bone_children(src_idx);
|
||||
while (descendants_to_process.size() > 0) {
|
||||
int desc_idx = descendants_to_process[0];
|
||||
descendants_to_process.erase(desc_idx);
|
||||
Vector<int> desc_children = src_skeleton->get_bone_children(desc_idx);
|
||||
for (const int &desc_child : desc_children) {
|
||||
decendants_to_process.push_back(desc_child);
|
||||
descendants_to_process.push_back(desc_child);
|
||||
}
|
||||
|
||||
StringName desc_bone_name = is_renamed ? StringName(src_skeleton->get_bone_name(desc_idx)) : bone_map->find_profile_bone_name(src_skeleton->get_bone_name(desc_idx));
|
||||
|
|
@ -526,12 +689,14 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
if (src_parent_idx >= 0) {
|
||||
src_pg = src_skeleton->get_bone_global_rest(src_parent_idx).basis;
|
||||
}
|
||||
|
||||
int prof_idx = profile->find_bone(src_bone_name);
|
||||
if (prof_idx >= 0) {
|
||||
tgt_rot = src_pg.inverse() * prof_skeleton->get_bone_global_rest(prof_idx).basis; // Mapped bone uses reference pose.
|
||||
// Mapped bone uses reference pose.
|
||||
// It is fine to change rest here even though is_using_modifier is enabled, since next process is aborted with unmapped bones.
|
||||
tgt_rot = src_pg.inverse() * prof_skeleton->get_bone_global_rest(prof_idx).basis;
|
||||
} else if (keep_global_rest_leftovers && keep_bone_rest.has(src_idx)) {
|
||||
tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis; // Non-Mapped bone without mapped children keeps global rest.
|
||||
// Non-Mapped bones without mapped children keeps global rest.
|
||||
tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -548,7 +713,8 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
src_skeleton->set_bone_rest(src_idx, Transform3D(tgt_rot, diff.xform(src_skeleton->get_bone_rest(src_idx).origin)));
|
||||
}
|
||||
|
||||
// Fix animation.
|
||||
// Fix animation by changing rest.
|
||||
bool warning_detected = false;
|
||||
{
|
||||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
|
|
@ -573,7 +739,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
ERR_CONTINUE(!node);
|
||||
|
||||
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
|
||||
if (!track_skeleton || track_skeleton != src_skeleton) {
|
||||
if (!track_skeleton ||
|
||||
(is_using_modifier && track_skeleton != profile_skeleton && track_skeleton != orig_skeleton) ||
|
||||
(!is_using_modifier && track_skeleton != src_skeleton)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -584,6 +752,16 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
|
||||
int bone_idx = src_skeleton->find_bone(bn);
|
||||
|
||||
if (is_using_modifier) {
|
||||
int prof_idx = profile->find_bone(bn);
|
||||
if (prof_idx < 0) {
|
||||
if (keep_bone_rest.has(bone_idx)) {
|
||||
warning_detected = true;
|
||||
}
|
||||
continue; // If is_using_modifier, the original skeleton rest is not changed.
|
||||
}
|
||||
}
|
||||
|
||||
Transform3D old_rest = old_skeleton_rest[bone_idx];
|
||||
Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
|
||||
Transform3D old_pg;
|
||||
|
|
@ -629,6 +807,13 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
}
|
||||
}
|
||||
}
|
||||
if (is_using_global_pose && warning_detected) {
|
||||
// TODO:
|
||||
// Theoretically, if A and its conversion are calculated correctly taking into account the difference in the number of bones,
|
||||
// there is no need to disable use_global_pose, but this is probably a fairly niche case.
|
||||
WARN_PRINT_ED("Animated extra bone between mapped bones detected, consider disabling Use Global Pose option to prevent that the pose origin be overridden by the RetargetModifier3D.");
|
||||
}
|
||||
|
||||
if (p_options.has("retarget/rest_fixer/reset_all_bone_poses_after_import") && !bool(p_options["retarget/rest_fixer/reset_all_bone_poses_after_import"])) {
|
||||
// If Reset All Bone Poses After Import is disabled, preserve the original bone pose, adjusted for the new bone rolls.
|
||||
for (int bone_idx = 0; bone_idx < src_skeleton->get_bone_count(); bone_idx++) {
|
||||
|
|
@ -654,6 +839,11 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
}
|
||||
}
|
||||
|
||||
if (is_using_modifier) {
|
||||
memdelete(src_skeleton);
|
||||
src_skeleton = profile_skeleton;
|
||||
}
|
||||
|
||||
is_rest_changed = true;
|
||||
}
|
||||
|
||||
|
|
@ -681,7 +871,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
ERR_CONTINUE(!node);
|
||||
|
||||
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
|
||||
if (!track_skeleton || track_skeleton != src_skeleton) {
|
||||
if (!track_skeleton ||
|
||||
(is_using_modifier && track_skeleton != profile_skeleton && track_skeleton != orig_skeleton) ||
|
||||
(!is_using_modifier && track_skeleton != src_skeleton)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -696,7 +888,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
}
|
||||
}
|
||||
|
||||
if (is_rest_changed) {
|
||||
if (!is_using_modifier && is_rest_changed) {
|
||||
// Fix skin.
|
||||
{
|
||||
HashSet<Ref<Skin>> mutated_skins;
|
||||
|
|
@ -766,6 +958,14 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
|
||||
src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
|
||||
}
|
||||
if (orig_skeleton) {
|
||||
for (int i = 0; i < orig_skeleton->get_bone_count(); i++) {
|
||||
Transform3D fixed_rest = orig_skeleton->get_bone_rest(i);
|
||||
orig_skeleton->set_bone_pose_position(i, fixed_rest.origin);
|
||||
orig_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
|
||||
orig_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class PostImportPluginSkeletonRestFixer : public EditorScenePostImportPlugin {
|
|||
|
||||
public:
|
||||
virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) override;
|
||||
virtual Variant get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
|
||||
virtual Variant get_internal_option_visibility(InternalImportCategory p_category, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
|
||||
virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) override;
|
||||
|
||||
PostImportPluginSkeletonRestFixer();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "post_import_plugin_skeleton_track_organizer.h"
|
||||
|
||||
#include "editor/import/3d/scene_import_settings.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/bone_map.h"
|
||||
|
|
@ -39,7 +38,7 @@ void PostImportPluginSkeletonTrackOrganizer::get_internal_import_options(Interna
|
|||
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/except_bone_transform"), false));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/unimportant_positions"), true));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/unmapped_bones"), false));
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "retarget/remove_tracks/unmapped_bones", PROPERTY_HINT_ENUM, "None,Remove,Separate Library"), 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +51,7 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
|
|||
}
|
||||
BoneMap *bone_map = Object::cast_to<BoneMap>(map);
|
||||
Ref<SkeletonProfile> profile = bone_map->get_profile();
|
||||
if (!profile.is_valid()) {
|
||||
if (profile.is_null()) {
|
||||
return;
|
||||
}
|
||||
Skeleton3D *src_skeleton = Object::cast_to<Skeleton3D>(p_node);
|
||||
|
|
@ -61,9 +60,9 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
|
|||
}
|
||||
bool remove_except_bone = bool(p_options["retarget/remove_tracks/except_bone_transform"]);
|
||||
bool remove_positions = bool(p_options["retarget/remove_tracks/unimportant_positions"]);
|
||||
bool remove_unmapped_bones = bool(p_options["retarget/remove_tracks/unmapped_bones"]);
|
||||
int separate_unmapped_bones = int(p_options["retarget/remove_tracks/unmapped_bones"]);
|
||||
|
||||
if (!remove_positions && !remove_unmapped_bones) {
|
||||
if (!remove_positions && separate_unmapped_bones == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -72,10 +71,16 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
|
|||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
|
||||
Ref<AnimationLibrary> unmapped_al;
|
||||
unmapped_al.instantiate();
|
||||
|
||||
for (const StringName &name : anims) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
Vector<int> remove_indices;
|
||||
Vector<int> mapped_bone_indices;
|
||||
Vector<int> unmapped_bone_indices;
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
String track_path = String(anim->track_get_path(i).get_concatenated_names());
|
||||
Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path));
|
||||
|
|
@ -96,16 +101,19 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
|
|||
StringName bn = anim->track_get_path(i).get_subname(0);
|
||||
if (bn) {
|
||||
int prof_idx = profile->find_bone(bone_map->find_profile_bone_name(bn));
|
||||
if (remove_unmapped_bones && prof_idx < 0) {
|
||||
remove_indices.push_back(i);
|
||||
if (prof_idx < 0) {
|
||||
unmapped_bone_indices.push_back(i);
|
||||
continue;
|
||||
}
|
||||
if (remove_positions && anim->track_get_type(i) == Animation::TYPE_POSITION_3D && prof_idx >= 0) {
|
||||
StringName prof_bn = profile->get_bone_name(prof_idx);
|
||||
if (prof_bn == profile->get_root_bone() || prof_bn == profile->get_scale_base_bone()) {
|
||||
mapped_bone_indices.push_back(i);
|
||||
continue;
|
||||
}
|
||||
remove_indices.push_back(i);
|
||||
} else {
|
||||
mapped_bone_indices.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -114,11 +122,34 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
|
|||
}
|
||||
}
|
||||
|
||||
if (separate_unmapped_bones == 2 && !unmapped_bone_indices.is_empty()) {
|
||||
Ref<Animation> unmapped_anim = anim->duplicate();
|
||||
Vector<int> to_delete;
|
||||
to_delete.append_array(mapped_bone_indices);
|
||||
to_delete.append_array(remove_indices);
|
||||
to_delete.sort();
|
||||
to_delete.reverse();
|
||||
for (int E : to_delete) {
|
||||
unmapped_anim->remove_track(E);
|
||||
}
|
||||
unmapped_al->add_animation(name, unmapped_anim);
|
||||
}
|
||||
|
||||
if (separate_unmapped_bones >= 1) {
|
||||
remove_indices.append_array(unmapped_bone_indices);
|
||||
remove_indices.sort();
|
||||
}
|
||||
remove_indices.reverse();
|
||||
for (int i = 0; i < remove_indices.size(); i++) {
|
||||
anim->remove_track(remove_indices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (unmapped_al->get_animation_list_size() == 0) {
|
||||
unmapped_al.unref();
|
||||
} else if (separate_unmapped_bones == 2) {
|
||||
ap->add_animation_library("unmapped_bones", unmapped_al);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,16 +33,11 @@
|
|||
#include "core/io/file_access.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/resources/3d/importer_mesh.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
uint32_t EditorOBJImporter::get_import_flags() const {
|
||||
return IMPORT_SCENE;
|
||||
}
|
||||
|
||||
static Error _parse_material_library(const String &p_path, HashMap<String, Ref<StandardMaterial3D>> &material_map, List<String> *r_missing_deps) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
||||
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path));
|
||||
|
|
@ -202,12 +197,12 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
|
|||
return OK;
|
||||
}
|
||||
|
||||
static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) {
|
||||
static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_generate_lods, bool p_generate_shadow_mesh, bool p_generate_lightmap_uv2, float p_generate_lightmap_uv2_texel_size, const PackedByteArray &p_src_lightmap_cache, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, Vector<Vector<uint8_t>> &r_lightmap_caches, List<String> *r_missing_deps) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
||||
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
|
||||
|
||||
// Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree)
|
||||
// This should only match, if it's indeed a COFF file header
|
||||
// Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree).
|
||||
// This should only match if it's indeed a COFF file header.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types
|
||||
const int first_bytes = f->get_16();
|
||||
static const Vector<int> coff_header_machines{
|
||||
|
|
@ -246,6 +241,8 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
bool smoothing = true;
|
||||
const uint32_t no_smoothing_smooth_group = (uint32_t)-1;
|
||||
|
||||
bool uses_uvs = false;
|
||||
|
||||
while (true) {
|
||||
String l = f->get_line().strip_edges();
|
||||
while (l.length() && l[l.length() - 1] == '\\') {
|
||||
|
|
@ -320,26 +317,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
idx = 1 ^ idx;
|
||||
}
|
||||
|
||||
if (face[idx].size() == 3) {
|
||||
int norm = face[idx][2].to_int() - 1;
|
||||
if (norm < 0) {
|
||||
norm += normals.size() + 1;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(norm, normals.size(), ERR_FILE_CORRUPT);
|
||||
surf_tool->set_normal(normals[norm]);
|
||||
if (generate_tangents && uvs.is_empty()) {
|
||||
// We can't generate tangents without UVs, so create dummy tangents.
|
||||
Vector3 tan = Vector3(normals[norm].z, -normals[norm].x, normals[norm].y).cross(normals[norm].normalized()).normalized();
|
||||
surf_tool->set_tangent(Plane(tan.x, tan.y, tan.z, 1.0));
|
||||
}
|
||||
} else {
|
||||
// No normals, use a dummy tangent since normals and tangents will be generated.
|
||||
if (generate_tangents && uvs.is_empty()) {
|
||||
// We can't generate tangents without UVs, so create dummy tangents.
|
||||
surf_tool->set_tangent(Plane(1.0, 0.0, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
// Check UVs before faces as we may need to generate dummy tangents if there are no UVs.
|
||||
if (face[idx].size() >= 2 && !face[idx][1].is_empty()) {
|
||||
int uv = face[idx][1].to_int() - 1;
|
||||
if (uv < 0) {
|
||||
|
|
@ -347,6 +325,27 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
}
|
||||
ERR_FAIL_INDEX_V(uv, uvs.size(), ERR_FILE_CORRUPT);
|
||||
surf_tool->set_uv(uvs[uv]);
|
||||
uses_uvs = true;
|
||||
}
|
||||
|
||||
if (face[idx].size() == 3) {
|
||||
int norm = face[idx][2].to_int() - 1;
|
||||
if (norm < 0) {
|
||||
norm += normals.size() + 1;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(norm, normals.size(), ERR_FILE_CORRUPT);
|
||||
surf_tool->set_normal(normals[norm]);
|
||||
if (generate_tangents && !uses_uvs) {
|
||||
// We can't generate tangents without UVs, so create dummy tangents.
|
||||
Vector3 tan = Vector3(normals[norm].z, -normals[norm].x, normals[norm].y).cross(normals[norm].normalized()).normalized();
|
||||
surf_tool->set_tangent(Plane(tan.x, tan.y, tan.z, 1.0));
|
||||
}
|
||||
} else {
|
||||
// No normals, use a dummy tangent since normals and tangents will be generated.
|
||||
if (generate_tangents && !uses_uvs) {
|
||||
// We can't generate tangents without UVs, so create dummy tangents.
|
||||
surf_tool->set_tangent(Plane(1.0, 0.0, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
int vtx = face[idx][0].to_int() - 1;
|
||||
|
|
@ -407,7 +406,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
surf_tool->generate_normals();
|
||||
}
|
||||
|
||||
if (generate_tangents && uvs.size()) {
|
||||
if (generate_tangents && uses_uvs) {
|
||||
surf_tool->generate_tangents();
|
||||
}
|
||||
|
||||
|
|
@ -426,10 +425,11 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
|
||||
Array array = surf_tool->commit_to_arrays();
|
||||
|
||||
if (mesh_flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && generate_tangents) {
|
||||
// Compression is enabled, so let's validate that the normals and tangents are correct.
|
||||
if (mesh_flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && generate_tangents && uses_uvs) {
|
||||
// Compression is enabled, so let's validate that the normals and generated tangents are correct.
|
||||
Vector<Vector3> norms = array[Mesh::ARRAY_NORMAL];
|
||||
Vector<float> tangents = array[Mesh::ARRAY_TANGENT];
|
||||
ERR_FAIL_COND_V(tangents.is_empty(), ERR_FILE_CORRUPT);
|
||||
for (int vert = 0; vert < norms.size(); vert++) {
|
||||
Vector3 tan = Vector3(tangents[vert * 4 + 0], tangents[vert * 4 + 1], tangents[vert * 4 + 2]);
|
||||
if (abs(tan.dot(norms[vert])) > 0.0001) {
|
||||
|
|
@ -440,6 +440,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
}
|
||||
|
||||
mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, array, TypedArray<Array>(), Dictionary(), material, name, mesh_flags);
|
||||
|
||||
print_verbose("OBJ: Added surface :" + mesh->get_surface_name(mesh->get_surface_count() - 1));
|
||||
|
||||
if (!current_material.is_empty()) {
|
||||
|
|
@ -454,6 +455,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
|
||||
surf_tool->clear();
|
||||
surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
|
||||
uses_uvs = false;
|
||||
}
|
||||
|
||||
if (l.begins_with("o ") || f->eof_reached()) {
|
||||
|
|
@ -502,6 +504,43 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
}
|
||||
}
|
||||
|
||||
if (p_generate_lightmap_uv2) {
|
||||
Vector<uint8_t> lightmap_cache;
|
||||
mesh->lightmap_unwrap_cached(Transform3D(), p_generate_lightmap_uv2_texel_size, p_src_lightmap_cache, lightmap_cache);
|
||||
|
||||
if (!lightmap_cache.is_empty()) {
|
||||
if (r_lightmap_caches.is_empty()) {
|
||||
r_lightmap_caches.push_back(lightmap_cache);
|
||||
} else {
|
||||
// MD5 is stored at the beginning of the cache data.
|
||||
const String new_md5 = String::md5(lightmap_cache.ptr());
|
||||
|
||||
for (int i = 0; i < r_lightmap_caches.size(); i++) {
|
||||
const String md5 = String::md5(r_lightmap_caches[i].ptr());
|
||||
if (new_md5 < md5) {
|
||||
r_lightmap_caches.insert(i, lightmap_cache);
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_md5 == md5) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_generate_lods) {
|
||||
// Use normal merge/split angles that match the defaults used for 3D scene importing.
|
||||
mesh->generate_lods(60.0f, {});
|
||||
}
|
||||
|
||||
if (p_generate_shadow_mesh) {
|
||||
mesh->create_shadow_mesh();
|
||||
}
|
||||
|
||||
mesh->optimize_indices();
|
||||
|
||||
if (p_single_mesh && mesh->get_surface_count() > 0) {
|
||||
r_meshes.push_back(mesh);
|
||||
}
|
||||
|
|
@ -512,7 +551,10 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
|
|||
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
|
||||
List<Ref<ImporterMesh>> meshes;
|
||||
|
||||
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, r_missing_deps);
|
||||
// LOD, shadow mesh and lightmap UV2 generation are handled by ResourceImporterScene in this case,
|
||||
// so disable it within the OBJ mesh import.
|
||||
Vector<Vector<uint8_t>> mesh_lightmap_caches;
|
||||
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, false, false, 0.2, PackedByteArray(), Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, mesh_lightmap_caches, r_missing_deps);
|
||||
|
||||
if (err != OK) {
|
||||
if (r_err) {
|
||||
|
|
@ -581,20 +623,51 @@ String ResourceImporterOBJ::get_preset_name(int p_idx) const {
|
|||
|
||||
void ResourceImporterOBJ::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_tangents"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_lods"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_shadow_mesh"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_lightmap_uv2", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "generate_lightmap_uv2_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "scale_mesh"), Vector3(1, 1, 1)));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "offset_mesh"), Vector3(0, 0, 0)));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimize_mesh"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_disable_mesh_compression"), false));
|
||||
}
|
||||
|
||||
bool ResourceImporterOBJ::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
if (p_option == "generate_lightmap_uv2_texel_size" && !p_options["generate_lightmap_uv2"]) {
|
||||
// Only display the lightmap texel size import option when lightmap UV2 generation is enabled.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
||||
Error ResourceImporterOBJ::import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
||||
List<Ref<ImporterMesh>> meshes;
|
||||
|
||||
Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], nullptr);
|
||||
Vector<uint8_t> src_lightmap_cache;
|
||||
Vector<Vector<uint8_t>> mesh_lightmap_caches;
|
||||
|
||||
Error err;
|
||||
{
|
||||
src_lightmap_cache = FileAccess::get_file_as_bytes(p_source_file + ".unwrap_cache", &err);
|
||||
if (err != OK) {
|
||||
src_lightmap_cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["generate_lods"], p_options["generate_shadow_mesh"], p_options["generate_lightmap_uv2"], p_options["generate_lightmap_uv2_texel_size"], src_lightmap_cache, p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], mesh_lightmap_caches, nullptr);
|
||||
|
||||
if (mesh_lightmap_caches.size()) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
|
||||
if (f.is_valid()) {
|
||||
f->store_32(mesh_lightmap_caches.size());
|
||||
for (int i = 0; i < mesh_lightmap_caches.size(); i++) {
|
||||
String md5 = String::md5(mesh_lightmap_caches[i].ptr());
|
||||
f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size());
|
||||
}
|
||||
}
|
||||
}
|
||||
err = OK;
|
||||
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class EditorOBJImporter : public EditorSceneFormatImporter {
|
|||
GDCLASS(EditorOBJImporter, EditorSceneFormatImporter);
|
||||
|
||||
public:
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override;
|
||||
|
||||
|
|
@ -61,10 +60,7 @@ public:
|
|||
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
|
||||
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
|
||||
|
||||
virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
|
||||
|
||||
// Threaded import can currently cause deadlocks, see GH-48265.
|
||||
virtual bool can_import_threaded() const override { return false; }
|
||||
virtual Error import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
|
||||
|
||||
ResourceImporterOBJ();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/io/dir_access.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "editor/editor_interface.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/import/3d/scene_import_settings.h"
|
||||
|
|
@ -43,7 +44,6 @@
|
|||
#include "scene/3d/occluder_instance_3d.h"
|
||||
#include "scene/3d/physics/area_3d.h"
|
||||
#include "scene/3d/physics/collision_shape_3d.h"
|
||||
#include "scene/3d/physics/physics_body_3d.h"
|
||||
#include "scene/3d/physics/static_body_3d.h"
|
||||
#include "scene/3d/physics/vehicle_body_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
|
|
@ -56,16 +56,6 @@
|
|||
#include "scene/resources/bone_map.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
#include "scene/resources/resource_format_text.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
uint32_t EditorSceneFormatImporter::get_import_flags() const {
|
||||
uint32_t ret;
|
||||
if (GDVIRTUAL_CALL(_get_import_flags, ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ERR_FAIL_V(0);
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporter::get_extensions(List<String> *r_extensions) const {
|
||||
Vector<String> arr;
|
||||
|
|
@ -92,18 +82,33 @@ Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_f
|
|||
ERR_FAIL_V(nullptr);
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporter::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
|
||||
GDVIRTUAL_CALL(_get_import_options, p_path);
|
||||
void EditorSceneFormatImporter::add_import_option(const String &p_name, const Variant &p_default_value) {
|
||||
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option() can only be called from get_import_options().");
|
||||
add_import_option_advanced(p_default_value.get_type(), p_name, p_default_value);
|
||||
}
|
||||
|
||||
Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) {
|
||||
void EditorSceneFormatImporter::add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) {
|
||||
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option_advanced() can only be called from get_import_options().");
|
||||
current_option_list->push_back(ResourceImporter::ImportOption(PropertyInfo(p_type, p_name, p_hint, p_hint_string, p_usage_flags), p_default_value));
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporter::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
|
||||
current_option_list = r_options;
|
||||
GDVIRTUAL_CALL(_get_import_options, p_path);
|
||||
current_option_list = nullptr;
|
||||
}
|
||||
|
||||
Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) {
|
||||
Variant ret;
|
||||
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_for_animation, p_option, ret);
|
||||
// For compatibility with the old API, pass the import type as a boolean.
|
||||
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_scene_import_type == "AnimationLibrary", p_option, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporter::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_get_import_flags);
|
||||
ClassDB::bind_method(D_METHOD("add_import_option", "name", "value"), &EditorSceneFormatImporter::add_import_option);
|
||||
ClassDB::bind_method(D_METHOD("add_import_option_advanced", "type", "name", "default_value", "hint", "hint_string", "usage_flags"), &EditorSceneFormatImporter::add_import_option_advanced, DEFVAL(PROPERTY_HINT_NONE), DEFVAL(""), DEFVAL(PROPERTY_USAGE_DEFAULT));
|
||||
|
||||
GDVIRTUAL_BIND(_get_extensions);
|
||||
GDVIRTUAL_BIND(_import_scene, "path", "flags", "options");
|
||||
GDVIRTUAL_BIND(_get_import_options, "path");
|
||||
|
|
@ -172,13 +177,16 @@ void EditorScenePostImportPlugin::get_internal_import_options(InternalImportCate
|
|||
GDVIRTUAL_CALL(_get_internal_import_options, p_category);
|
||||
current_option_list = nullptr;
|
||||
}
|
||||
Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
|
||||
Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
current_options = &p_options;
|
||||
Variant ret;
|
||||
GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_for_animation, p_option, ret);
|
||||
// For compatibility with the old API, pass the import type as a boolean.
|
||||
GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_scene_import_type == "AnimationLibrary", p_option, ret);
|
||||
current_options = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant EditorScenePostImportPlugin::get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
current_options = &p_options;
|
||||
Variant ret;
|
||||
|
|
@ -198,10 +206,10 @@ void EditorScenePostImportPlugin::get_import_options(const String &p_path, List<
|
|||
GDVIRTUAL_CALL(_get_import_options, p_path);
|
||||
current_option_list = nullptr;
|
||||
}
|
||||
Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
current_options = &p_options;
|
||||
Variant ret;
|
||||
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_for_animation, p_option, ret);
|
||||
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_scene_import_type == "AnimationLibrary", p_option, ret);
|
||||
current_options = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -245,11 +253,22 @@ void EditorScenePostImportPlugin::_bind_methods() {
|
|||
/////////////////////////////////////////////////////////
|
||||
|
||||
String ResourceImporterScene::get_importer_name() const {
|
||||
return animation_importer ? "animation_library" : "scene";
|
||||
// For compatibility with 4.2 and earlier we need to keep the "scene" and "animation_library" names.
|
||||
// However this is arbitrary so for new import types we can use any string.
|
||||
if (_scene_import_type == "PackedScene") {
|
||||
return "scene";
|
||||
} else if (_scene_import_type == "AnimationLibrary") {
|
||||
return "animation_library";
|
||||
}
|
||||
return _scene_import_type;
|
||||
}
|
||||
|
||||
String ResourceImporterScene::get_visible_name() const {
|
||||
return animation_importer ? "Animation Library" : "Scene";
|
||||
// This is displayed on the UI. Friendly names here are nice but not vital, so fall back to the type.
|
||||
if (_scene_import_type == "PackedScene") {
|
||||
return "Scene";
|
||||
}
|
||||
return _scene_import_type.capitalize();
|
||||
}
|
||||
|
||||
void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
|
@ -257,11 +276,14 @@ void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions
|
|||
}
|
||||
|
||||
String ResourceImporterScene::get_save_extension() const {
|
||||
return animation_importer ? "res" : "scn";
|
||||
if (_scene_import_type == "PackedScene") {
|
||||
return "scn";
|
||||
}
|
||||
return "res";
|
||||
}
|
||||
|
||||
String ResourceImporterScene::get_resource_type() const {
|
||||
return animation_importer ? "AnimationLibrary" : "PackedScene";
|
||||
return _scene_import_type;
|
||||
}
|
||||
|
||||
int ResourceImporterScene::get_format_version() const {
|
||||
|
|
@ -269,27 +291,28 @@ int ResourceImporterScene::get_format_version() const {
|
|||
}
|
||||
|
||||
bool ResourceImporterScene::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
if (animation_importer) {
|
||||
if (_scene_import_type == "PackedScene") {
|
||||
if (p_option.begins_with("animation/")) {
|
||||
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (_scene_import_type == "AnimationLibrary") {
|
||||
if (p_option == "animation/import") { // Option ignored, animation always imported.
|
||||
return false;
|
||||
}
|
||||
} else if (p_option.begins_with("animation/")) {
|
||||
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
|
||||
return false;
|
||||
if (p_option == "nodes/root_type" || p_option == "nodes/root_name" || p_option.begins_with("meshes/") || p_option.begins_with("skins/")) {
|
||||
return false; // Nothing to do here for animations.
|
||||
}
|
||||
}
|
||||
|
||||
if (animation_importer && (p_option == "nodes/root_type" || p_option == "nodes/root_name" || p_option.begins_with("meshes/") || p_option.begins_with("skins/"))) {
|
||||
return false; // Nothing to do here for animations.
|
||||
}
|
||||
|
||||
if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) != 2) {
|
||||
// Only display the lightmap texel size import option when using the Static Lightmaps light baking mode.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < post_importer_plugins.size(); i++) {
|
||||
Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, animation_importer, p_option, p_options);
|
||||
Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, _scene_import_type, p_option, p_options);
|
||||
if (ret.get_type() == Variant::BOOL) {
|
||||
if (!ret) {
|
||||
return false;
|
||||
|
|
@ -298,7 +321,7 @@ bool ResourceImporterScene::get_option_visibility(const String &p_path, const St
|
|||
}
|
||||
|
||||
for (Ref<EditorSceneFormatImporter> importer : scene_importers) {
|
||||
Variant ret = importer->get_option_visibility(p_path, animation_importer, p_option, p_options);
|
||||
Variant ret = importer->get_option_visibility(p_path, _scene_import_type, p_option, p_options);
|
||||
if (ret.get_type() == Variant::BOOL) {
|
||||
if (!ret) {
|
||||
return false;
|
||||
|
|
@ -427,7 +450,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
|
|||
}
|
||||
|
||||
static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
|
||||
ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value.");
|
||||
ERR_FAIL_COND_MSG(mesh.is_null(), "Cannot generate shape list with null mesh value.");
|
||||
if (!p_convex) {
|
||||
Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape();
|
||||
r_shape_list.push_back(shape);
|
||||
|
|
@ -618,10 +641,10 @@ void _apply_permanent_scale_to_descendants(Node *p_root_node, Vector3 p_scale) {
|
|||
_apply_scale_to_scalable_node_collection(scalable_node_collection, p_scale);
|
||||
}
|
||||
|
||||
Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames) {
|
||||
Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames, const HashMap<StringName, Variant> &p_options) {
|
||||
// Children first.
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
Node *r = _pre_fix_node(p_node->get_child(i), p_root, r_collision_map, r_occluder_arrays, r_node_renames);
|
||||
Node *r = _pre_fix_node(p_node->get_child(i), p_root, r_collision_map, r_occluder_arrays, r_node_renames, p_options);
|
||||
if (!r) {
|
||||
i--; // Was erased.
|
||||
}
|
||||
|
|
@ -630,6 +653,9 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
|
|||
String name = p_node->get_name();
|
||||
NodePath original_path = p_root->get_path_to(p_node); // Used to detect renames due to import hints.
|
||||
|
||||
Ref<Resource> original_meta = memnew(Resource); // Create temp resource to hold original meta
|
||||
original_meta->merge_meta_from(p_node);
|
||||
|
||||
bool isroot = p_node == p_root;
|
||||
|
||||
if (!isroot && _teststr(name, "noimp")) {
|
||||
|
|
@ -646,7 +672,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
|
|||
if (m.is_valid()) {
|
||||
for (int i = 0; i < m->get_surface_count(); i++) {
|
||||
Ref<BaseMaterial3D> mat = m->get_surface_material(i);
|
||||
if (!mat.is_valid()) {
|
||||
if (mat.is_null()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -728,6 +754,14 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
|
|||
}
|
||||
}
|
||||
|
||||
bool use_node_type_suffixes = true;
|
||||
if (p_options.has("nodes/use_node_type_suffixes")) {
|
||||
use_node_type_suffixes = p_options["nodes/use_node_type_suffixes"];
|
||||
}
|
||||
if (!use_node_type_suffixes) {
|
||||
return p_node;
|
||||
}
|
||||
|
||||
if (_teststr(name, "colonly") || _teststr(name, "convcolonly")) {
|
||||
if (isroot) {
|
||||
return p_node;
|
||||
|
|
@ -968,7 +1002,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
|
|||
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
|
||||
|
||||
Ref<ImporterMesh> mesh = mi->get_mesh();
|
||||
if (!mesh.is_null()) {
|
||||
if (mesh.is_valid()) {
|
||||
Vector<Ref<Shape3D>> shapes;
|
||||
if (r_collision_map.has(mesh)) {
|
||||
shapes = r_collision_map[mesh];
|
||||
|
|
@ -1003,6 +1037,8 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
|
|||
print_verbose(vformat("Fix: Renamed %s to %s", original_path, new_path));
|
||||
r_node_renames.push_back({ original_path, p_node });
|
||||
}
|
||||
// If we created new node instead, merge meta values from the original node.
|
||||
p_node->merge_meta_from(*original_meta);
|
||||
}
|
||||
|
||||
return p_node;
|
||||
|
|
@ -1552,7 +1588,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
col->set_transform(get_collision_shapes_transform(node_settings));
|
||||
col->set_position(p_applied_root_scale * col->get_position());
|
||||
const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
|
||||
if (!pmo.is_null()) {
|
||||
if (pmo.is_valid()) {
|
||||
col->set_physics_material_override(pmo);
|
||||
}
|
||||
base = col;
|
||||
|
|
@ -1569,7 +1605,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
rigid_body->add_child(mi, true);
|
||||
mi->set_owner(rigid_body->get_owner());
|
||||
const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
|
||||
if (!pmo.is_null()) {
|
||||
if (pmo.is_valid()) {
|
||||
rigid_body->set_physics_material_override(pmo);
|
||||
}
|
||||
base = rigid_body;
|
||||
|
|
@ -1585,7 +1621,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
memdelete(p_node);
|
||||
p_node = col;
|
||||
const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
|
||||
if (!pmo.is_null()) {
|
||||
if (pmo.is_valid()) {
|
||||
col->set_physics_material_override(pmo);
|
||||
}
|
||||
base = col;
|
||||
|
|
@ -1981,29 +2017,29 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
|
|||
decomposition_default.instantiate();
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/advanced", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/precision", PROPERTY_HINT_RANGE, "1,10,1"), 5));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/max_concavity", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_max_concavity()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/symmetry_planes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_symmetry_planes_clipping_bias()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/revolution_axes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_revolution_axes_clipping_bias()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/min_volume_per_convex_hull", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_min_volume_per_convex_hull()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/resolution", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_resolution()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_num_vertices_per_convex_hull", PROPERTY_HINT_RANGE, "5,512,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_max_num_vertices_per_convex_hull()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/plane_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_plane_downsampling()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/convexhull_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_convex_hull_downsampling()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/normalize_mesh", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_normalize_mesh()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/mode", PROPERTY_HINT_ENUM, "Voxel,Tetrahedron", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), static_cast<int>(decomposition_default->get_mode())));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/convexhull_approximation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_convex_hull_approximation()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_convex_hulls", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_max_convex_hulls()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/project_hull_vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_project_hull_vertices()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/max_concavity", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT), decomposition_default->get_max_concavity()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/symmetry_planes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT), decomposition_default->get_symmetry_planes_clipping_bias()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/revolution_axes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT), decomposition_default->get_revolution_axes_clipping_bias()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/min_volume_per_convex_hull", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_min_volume_per_convex_hull()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/resolution", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_resolution()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_num_vertices_per_convex_hull", PROPERTY_HINT_RANGE, "5,512,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_max_num_vertices_per_convex_hull()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/plane_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_plane_downsampling()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/convexhull_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_convex_hull_downsampling()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/normalize_mesh", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_normalize_mesh()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/mode", PROPERTY_HINT_ENUM, "Voxel,Tetrahedron", PROPERTY_USAGE_DEFAULT), static_cast<int>(decomposition_default->get_mode())));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/convexhull_approximation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_convex_hull_approximation()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_convex_hulls", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_max_convex_hulls()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/project_hull_vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_project_hull_vertices()));
|
||||
|
||||
// Primitives: Box, Sphere, Cylinder, Capsule.
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Vector3(2.0, 2.0, 2.0)));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/height", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1.0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/radius", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1.0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Vector3()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Vector3()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), Vector3(2.0, 2.0, 2.0)));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/height", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), 1.0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/radius", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), 1.0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), Vector3()));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), Vector3()));
|
||||
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/occluder", PROPERTY_HINT_ENUM, "Disabled,Mesh + Occluder,Occluder Only", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "occluder/simplification_distance", PROPERTY_HINT_RANGE, "0.0,2.0,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0.1f));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "occluder/simplification_distance", PROPERTY_HINT_RANGE, "0.0,2.0,0.01", PROPERTY_USAGE_DEFAULT), 0.1f));
|
||||
} break;
|
||||
case INTERNAL_IMPORT_CATEGORY_MESH: {
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
|
||||
|
|
@ -2011,7 +2047,6 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
|
|||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/shadow_meshes", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lightmap_uv", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_split_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), 25.0f));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_merge_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), 60.0f));
|
||||
} break;
|
||||
case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
|
||||
|
|
@ -2281,8 +2316,9 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: If there are more than 2 or equal get_internal_option_visibility method, visibility state is broken.
|
||||
for (int i = 0; i < post_importer_plugins.size(); i++) {
|
||||
Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), animation_importer, p_option, p_options);
|
||||
Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), _scene_import_type, p_option, p_options);
|
||||
if (ret.get_type() == Variant::BOOL) {
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2332,12 +2368,12 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
|
|||
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), ""));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_name"), ""));
|
||||
|
||||
List<String> script_extentions;
|
||||
ResourceLoader::get_recognized_extensions_for_type("Script", &script_extentions);
|
||||
List<String> script_extensions;
|
||||
ResourceLoader::get_recognized_extensions_for_type("Script", &script_extensions);
|
||||
|
||||
String script_ext_hint;
|
||||
|
||||
for (const String &E : script_extentions) {
|
||||
for (const String &E : script_extensions) {
|
||||
if (!script_ext_hint.is_empty()) {
|
||||
script_ext_hint += ",";
|
||||
}
|
||||
|
|
@ -2348,6 +2384,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
|
|||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/import_as_skeleton_bones"), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/use_node_type_suffixes"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true));
|
||||
|
|
@ -2432,13 +2469,14 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
|
|||
mesh_node->set_transform(src_mesh_node->get_transform());
|
||||
mesh_node->set_skin(src_mesh_node->get_skin());
|
||||
mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
|
||||
mesh_node->merge_meta_from(src_mesh_node);
|
||||
|
||||
if (src_mesh_node->get_mesh().is_valid()) {
|
||||
Ref<ArrayMesh> mesh;
|
||||
if (!src_mesh_node->get_mesh()->has_mesh()) {
|
||||
//do mesh processing
|
||||
|
||||
bool generate_lods = p_generate_lods;
|
||||
float split_angle = 25.0f;
|
||||
float merge_angle = 60.0f;
|
||||
bool create_shadow_meshes = p_create_shadow_meshes;
|
||||
bool bake_lightmaps = p_light_bake_mode == LIGHT_BAKE_STATIC_LIGHTMAPS;
|
||||
|
|
@ -2486,10 +2524,6 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
|
|||
}
|
||||
}
|
||||
|
||||
if (mesh_settings.has("lods/normal_split_angle")) {
|
||||
split_angle = mesh_settings["lods/normal_split_angle"];
|
||||
}
|
||||
|
||||
if (mesh_settings.has("lods/normal_merge_angle")) {
|
||||
merge_angle = mesh_settings["lods/normal_merge_angle"];
|
||||
}
|
||||
|
|
@ -2540,13 +2574,15 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
|
|||
|
||||
if (generate_lods) {
|
||||
Array skin_pose_transform_array = _get_skinned_pose_transforms(src_mesh_node);
|
||||
src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle, skin_pose_transform_array);
|
||||
src_mesh_node->get_mesh()->generate_lods(merge_angle, skin_pose_transform_array);
|
||||
}
|
||||
|
||||
if (create_shadow_meshes) {
|
||||
src_mesh_node->get_mesh()->create_shadow_mesh();
|
||||
}
|
||||
|
||||
src_mesh_node->get_mesh()->optimize_indices();
|
||||
|
||||
if (!save_to_file.is_empty()) {
|
||||
Ref<Mesh> existing = ResourceCache::get_ref(save_to_file);
|
||||
if (existing.is_valid()) {
|
||||
|
|
@ -2572,6 +2608,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
|
|||
for (int i = 0; i < mesh->get_surface_count(); i++) {
|
||||
mesh_node->set_surface_override_material(i, src_mesh_node->get_surface_material(i));
|
||||
}
|
||||
mesh->merge_meta_from(*src_mesh_node->get_mesh());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2590,6 +2627,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
|
|||
|
||||
mesh_node->set_layer_mask(src_mesh_node->get_layer_mask());
|
||||
mesh_node->set_cast_shadows_setting(src_mesh_node->get_cast_shadows_setting());
|
||||
mesh_node->set_visible(src_mesh_node->is_visible());
|
||||
mesh_node->set_visibility_range_begin(src_mesh_node->get_visibility_range_begin());
|
||||
mesh_node->set_visibility_range_begin_margin(src_mesh_node->get_visibility_range_begin_margin());
|
||||
mesh_node->set_visibility_range_end(src_mesh_node->get_visibility_range_end());
|
||||
|
|
@ -2781,6 +2819,15 @@ void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, Ani
|
|||
}
|
||||
}
|
||||
|
||||
void ResourceImporterScene::_generate_editor_preview_for_scene(const String &p_path, Node *p_scene) {
|
||||
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_COND_MSG(p_path.is_empty(), "Path is empty, cannot generate preview.");
|
||||
ERR_FAIL_NULL_MSG(p_scene, "Scene is null, cannot generate preview.");
|
||||
EditorInterface::get_singleton()->make_scene_preview(p_path, p_scene, 1024);
|
||||
}
|
||||
|
||||
Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options) {
|
||||
Ref<EditorSceneFormatImporter> importer;
|
||||
String ext = p_source_file.get_extension().to_lower();
|
||||
|
|
@ -2805,7 +2852,7 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM
|
|||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
|
||||
ERR_FAIL_COND_V(importer.is_null(), nullptr);
|
||||
ERR_FAIL_COND_V(p_options.is_empty(), nullptr);
|
||||
|
||||
Error err = OK;
|
||||
|
|
@ -2819,7 +2866,7 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM
|
|||
|
||||
HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
|
||||
List<Pair<NodePath, Node *>> node_renames;
|
||||
_pre_fix_node(scene, scene, collision_map, nullptr, node_renames);
|
||||
_pre_fix_node(scene, scene, collision_map, nullptr, node_renames, p_options);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
|
@ -2830,8 +2877,7 @@ Error ResourceImporterScene::_check_resource_save_paths(const Dictionary &p_data
|
|||
const Dictionary &settings = p_data[keys[i]];
|
||||
|
||||
if (bool(settings.get("save_to_file/enabled", false)) && settings.has("save_to_file/path")) {
|
||||
const String &save_path = settings["save_to_file/path"];
|
||||
|
||||
const String save_path = ResourceUID::ensure_path(settings["save_to_file/path"]);
|
||||
ERR_FAIL_COND_V(!save_path.is_empty() && !DirAccess::exists(save_path.get_base_dir()), ERR_FILE_BAD_PATH);
|
||||
}
|
||||
}
|
||||
|
|
@ -2839,7 +2885,7 @@ Error ResourceImporterScene::_check_resource_save_paths(const Dictionary &p_data
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
||||
Error ResourceImporterScene::import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
||||
const String &src_path = p_source_file;
|
||||
|
||||
Ref<EditorSceneFormatImporter> importer;
|
||||
|
|
@ -2864,18 +2910,16 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_UNRECOGNIZED);
|
||||
ERR_FAIL_COND_V(importer.is_null(), ERR_FILE_UNRECOGNIZED);
|
||||
ERR_FAIL_COND_V(p_options.is_empty(), ERR_BUG);
|
||||
|
||||
int import_flags = 0;
|
||||
|
||||
if (animation_importer) {
|
||||
if (_scene_import_type == "AnimationLibrary") {
|
||||
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
|
||||
import_flags |= EditorSceneFormatImporter::IMPORT_DISCARD_MESHES_AND_MATERIALS;
|
||||
} else {
|
||||
if (bool(p_options["animation/import"])) {
|
||||
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
|
||||
}
|
||||
} else if (bool(p_options["animation/import"])) {
|
||||
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
|
||||
}
|
||||
|
||||
if (bool(p_options["skins/use_named_skins"])) {
|
||||
|
|
@ -2894,38 +2938,22 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
|
||||
Dictionary subresources = p_options["_subresources"];
|
||||
|
||||
Dictionary node_data;
|
||||
if (subresources.has("nodes")) {
|
||||
node_data = subresources["nodes"];
|
||||
}
|
||||
|
||||
Dictionary material_data;
|
||||
if (subresources.has("materials")) {
|
||||
material_data = subresources["materials"];
|
||||
}
|
||||
|
||||
Dictionary animation_data;
|
||||
if (subresources.has("animations")) {
|
||||
animation_data = subresources["animations"];
|
||||
}
|
||||
|
||||
Dictionary mesh_data;
|
||||
if (subresources.has("meshes")) {
|
||||
mesh_data = subresources["meshes"];
|
||||
}
|
||||
|
||||
Error err = OK;
|
||||
|
||||
// Check whether any of the meshes or animations have nonexistent save paths
|
||||
// and if they do, fail the import immediately.
|
||||
err = _check_resource_save_paths(mesh_data);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
if (subresources.has("meshes")) {
|
||||
err = _check_resource_save_paths(subresources["meshes"]);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = _check_resource_save_paths(animation_data);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
if (subresources.has("animations")) {
|
||||
err = _check_resource_save_paths(subresources["animations"]);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> missing_deps; // for now, not much will be done with this
|
||||
|
|
@ -2959,12 +2987,33 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
Pair<PackedVector3Array, PackedInt32Array> occluder_arrays;
|
||||
List<Pair<NodePath, Node *>> node_renames;
|
||||
|
||||
_pre_fix_node(scene, scene, collision_map, &occluder_arrays, node_renames);
|
||||
_pre_fix_node(scene, scene, collision_map, &occluder_arrays, node_renames, p_options);
|
||||
|
||||
for (int i = 0; i < post_importer_plugins.size(); i++) {
|
||||
post_importer_plugins.write[i]->pre_process(scene, p_options);
|
||||
}
|
||||
|
||||
// data in _subresources may be modified by pre_process(), so wait until now to check.
|
||||
Dictionary node_data;
|
||||
if (subresources.has("nodes")) {
|
||||
node_data = subresources["nodes"];
|
||||
}
|
||||
|
||||
Dictionary material_data;
|
||||
if (subresources.has("materials")) {
|
||||
material_data = subresources["materials"];
|
||||
}
|
||||
|
||||
Dictionary animation_data;
|
||||
if (subresources.has("animations")) {
|
||||
animation_data = subresources["animations"];
|
||||
}
|
||||
|
||||
Dictionary mesh_data;
|
||||
if (subresources.has("meshes")) {
|
||||
mesh_data = subresources["meshes"];
|
||||
}
|
||||
|
||||
float fps = 30;
|
||||
if (p_options.has(SNAME("animation/fps"))) {
|
||||
fps = (float)p_options[SNAME("animation/fps")];
|
||||
|
|
@ -3050,14 +3099,18 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
progress.step(TTR("Running Custom Script..."), 2);
|
||||
|
||||
String post_import_script_path = p_options["import_script/path"];
|
||||
|
||||
Ref<EditorScenePostImport> post_import_script;
|
||||
|
||||
if (!post_import_script_path.is_empty()) {
|
||||
if (post_import_script_path.is_relative_path()) {
|
||||
post_import_script_path = p_source_file.get_base_dir().path_join(post_import_script_path);
|
||||
}
|
||||
Ref<Script> scr = ResourceLoader::load(post_import_script_path);
|
||||
if (!scr.is_valid()) {
|
||||
if (scr.is_null()) {
|
||||
EditorNode::add_io_error(TTR("Couldn't load post-import script:") + " " + post_import_script_path);
|
||||
} else {
|
||||
post_import_script = Ref<EditorScenePostImport>(memnew(EditorScenePostImport));
|
||||
post_import_script.instantiate();
|
||||
post_import_script->set_script(scr);
|
||||
if (!post_import_script->get_script_instance()) {
|
||||
EditorNode::add_io_error(TTR("Invalid/broken script for post-import (check console):") + " " + post_import_script_path);
|
||||
|
|
@ -3067,6 +3120,19 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
}
|
||||
}
|
||||
|
||||
// Apply RESET animation before serializing.
|
||||
if (_scene_import_type == "PackedScene") {
|
||||
int scene_child_count = scene->get_child_count();
|
||||
for (int i = 0; i < scene_child_count; i++) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i));
|
||||
if (ap) {
|
||||
if (ap->can_apply_reset()) {
|
||||
ap->apply_reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (post_import_script.is_valid()) {
|
||||
post_import_script->init(p_source_file);
|
||||
scene = post_import_script->post_import(scene);
|
||||
|
|
@ -3085,11 +3151,11 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
progress.step(TTR("Saving..."), 104);
|
||||
|
||||
int flags = 0;
|
||||
if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
|
||||
if (EditorSettings::get_singleton() && EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
|
||||
flags |= ResourceSaver::FLAG_COMPRESS;
|
||||
}
|
||||
|
||||
if (animation_importer) {
|
||||
if (_scene_import_type == "AnimationLibrary") {
|
||||
Ref<AnimationLibrary> library;
|
||||
for (int i = 0; i < scene->get_child_count(); i++) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i));
|
||||
|
|
@ -3103,20 +3169,22 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
|||
}
|
||||
}
|
||||
|
||||
if (!library.is_valid()) {
|
||||
if (library.is_null()) {
|
||||
library.instantiate(); // Will be empty
|
||||
}
|
||||
|
||||
print_verbose("Saving animation to: " + p_save_path + ".res");
|
||||
err = ResourceSaver::save(library, p_save_path + ".res", flags); //do not take over, let the changed files reload themselves
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save animation to file '" + p_save_path + ".res'.");
|
||||
|
||||
} else {
|
||||
} else if (_scene_import_type == "PackedScene") {
|
||||
Ref<PackedScene> packer = memnew(PackedScene);
|
||||
packer->pack(scene);
|
||||
print_verbose("Saving scene to: " + p_save_path + ".scn");
|
||||
err = ResourceSaver::save(packer, p_save_path + ".scn", flags); //do not take over, let the changed files reload themselves
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'.");
|
||||
_generate_editor_preview_for_scene(p_source_file, scene);
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown scene import type: " + _scene_import_type);
|
||||
}
|
||||
|
||||
memdelete(scene);
|
||||
|
|
@ -3138,20 +3206,20 @@ bool ResourceImporterScene::has_advanced_options() const {
|
|||
}
|
||||
|
||||
void ResourceImporterScene::show_advanced_options(const String &p_path) {
|
||||
SceneImportSettingsDialog::get_singleton()->open_settings(p_path, animation_importer);
|
||||
SceneImportSettingsDialog::get_singleton()->open_settings(p_path, _scene_import_type);
|
||||
}
|
||||
|
||||
ResourceImporterScene::ResourceImporterScene(bool p_animation_import, bool p_singleton) {
|
||||
ResourceImporterScene::ResourceImporterScene(const String &p_scene_import_type, bool p_singleton) {
|
||||
// This should only be set through the EditorNode.
|
||||
if (p_singleton) {
|
||||
if (p_animation_import) {
|
||||
if (p_scene_import_type == "AnimationLibrary") {
|
||||
animation_singleton = this;
|
||||
} else {
|
||||
} else if (p_scene_import_type == "PackedScene") {
|
||||
scene_singleton = this;
|
||||
}
|
||||
}
|
||||
|
||||
animation_importer = p_animation_import;
|
||||
_scene_import_type = p_scene_import_type;
|
||||
}
|
||||
|
||||
ResourceImporterScene::~ResourceImporterScene() {
|
||||
|
|
@ -3202,10 +3270,6 @@ void ResourceImporterScene::get_scene_importer_extensions(List<String> *p_extens
|
|||
|
||||
///////////////////////////////////////
|
||||
|
||||
uint32_t EditorSceneFormatImporterESCN::get_import_flags() const {
|
||||
return IMPORT_SCENE;
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) const {
|
||||
r_extensions->push_back("escn");
|
||||
}
|
||||
|
|
@ -3213,7 +3277,7 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c
|
|||
Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
|
||||
Error error;
|
||||
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
|
||||
ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
|
||||
ERR_FAIL_COND_V_MSG(ps.is_null(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
|
||||
Node *scene = ps->instantiate();
|
||||
TypedArray<Node> nodes = scene->find_children("*", "MeshInstance3D");
|
||||
for (int32_t node_i = 0; node_i < nodes.size(); node_i++) {
|
||||
|
|
|
|||
|
|
@ -39,25 +39,25 @@
|
|||
#include "scene/resources/3d/capsule_shape_3d.h"
|
||||
#include "scene/resources/3d/cylinder_shape_3d.h"
|
||||
#include "scene/resources/3d/importer_mesh.h"
|
||||
#include "scene/resources/3d/skin.h"
|
||||
#include "scene/resources/3d/sphere_shape_3d.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
|
||||
class Material;
|
||||
class AnimationPlayer;
|
||||
|
||||
class ImporterMesh;
|
||||
class Material;
|
||||
|
||||
class EditorSceneFormatImporter : public RefCounted {
|
||||
GDCLASS(EditorSceneFormatImporter, RefCounted);
|
||||
|
||||
List<ResourceImporter::ImportOption> *current_option_list = nullptr;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, const Dictionary &p_options);
|
||||
Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, const Dictionary &p_options);
|
||||
|
||||
GDVIRTUAL0RC(uint32_t, _get_import_flags)
|
||||
GDVIRTUAL0RC(Vector<String>, _get_extensions)
|
||||
GDVIRTUAL3R(Object *, _import_scene, String, uint32_t, Dictionary)
|
||||
GDVIRTUAL1(_get_import_options, String)
|
||||
|
|
@ -74,11 +74,12 @@ public:
|
|||
IMPORT_FORCE_DISABLE_MESH_COMPRESSION = 64,
|
||||
};
|
||||
|
||||
virtual uint32_t get_import_flags() const;
|
||||
void add_import_option(const String &p_name, const Variant &p_default_value);
|
||||
void add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT);
|
||||
virtual void get_extensions(List<String> *r_extensions) const;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr);
|
||||
virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options);
|
||||
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options);
|
||||
virtual Variant get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options);
|
||||
virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {}
|
||||
|
||||
EditorSceneFormatImporter() {}
|
||||
|
|
@ -140,13 +141,13 @@ public:
|
|||
void add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT);
|
||||
|
||||
virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options);
|
||||
virtual Variant get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const;
|
||||
virtual Variant get_internal_option_visibility(InternalImportCategory p_category, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const;
|
||||
virtual Variant get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const;
|
||||
|
||||
virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options);
|
||||
|
||||
virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options);
|
||||
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const;
|
||||
virtual Variant get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const;
|
||||
|
||||
virtual void pre_process(Node *p_scene, const HashMap<StringName, Variant> &p_options);
|
||||
virtual void post_process(Node *p_scene, const HashMap<StringName, Variant> &p_options);
|
||||
|
|
@ -236,8 +237,9 @@ class ResourceImporterScene : public ResourceImporter {
|
|||
};
|
||||
|
||||
void _optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions);
|
||||
void _generate_editor_preview_for_scene(const String &p_path, Node *p_scene);
|
||||
|
||||
bool animation_importer = false;
|
||||
String _scene_import_type = "PackedScene";
|
||||
|
||||
public:
|
||||
static ResourceImporterScene *get_scene_singleton() { return scene_singleton; }
|
||||
|
|
@ -253,6 +255,9 @@ public:
|
|||
|
||||
static void clean_up_importer_plugins();
|
||||
|
||||
String get_scene_import_type() const { return _scene_import_type; }
|
||||
void set_scene_import_type(const String &p_type) { _scene_import_type = p_type; }
|
||||
|
||||
virtual String get_importer_name() const override;
|
||||
virtual String get_visible_name() const override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
|
|
@ -285,7 +290,7 @@ public:
|
|||
virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; }
|
||||
|
||||
void _pre_fix_global(Node *p_scene, const HashMap<StringName, Variant> &p_options) const;
|
||||
Node *_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames);
|
||||
Node *_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames, const HashMap<StringName, Variant> &p_options);
|
||||
Node *_pre_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps);
|
||||
Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale);
|
||||
Node *_post_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps, bool p_remove_immutable_tracks);
|
||||
|
|
@ -296,14 +301,12 @@ public:
|
|||
void _compress_animations(AnimationPlayer *anim, int p_page_size_kb);
|
||||
|
||||
Node *pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options);
|
||||
virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
|
||||
virtual Error import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
|
||||
|
||||
virtual bool has_advanced_options() const override;
|
||||
virtual void show_advanced_options(const String &p_path) override;
|
||||
|
||||
virtual bool can_import_threaded() const override { return false; }
|
||||
|
||||
ResourceImporterScene(bool p_animation_import = false, bool p_singleton = false);
|
||||
ResourceImporterScene(const String &p_scene_import_type = "PackedScene", bool p_singleton = false);
|
||||
~ResourceImporterScene();
|
||||
|
||||
template <typename M>
|
||||
|
|
@ -317,7 +320,6 @@ class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter {
|
|||
GDCLASS(EditorSceneFormatImporterESCN, EditorSceneFormatImporter);
|
||||
|
||||
public:
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,9 +37,11 @@
|
|||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/gui/editor_file_dialog.h"
|
||||
#include "editor/plugins/skeleton_3d_editor_plugin.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/gui/subviewport_container.h"
|
||||
#include "scene/resources/3d/importer_mesh.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
|
|
@ -117,7 +119,9 @@ class SceneImportSettingsData : public Object {
|
|||
ERR_FAIL_NULL(settings);
|
||||
if (r_option.name == "rest_pose/load_pose") {
|
||||
if (!settings->has("rest_pose/load_pose") || int((*settings)["rest_pose/load_pose"]) != 2) {
|
||||
(*settings)["rest_pose/external_animation_library"] = Variant();
|
||||
if (settings->has("rest_pose/external_animation_library")) {
|
||||
(*settings)["rest_pose/external_animation_library"] = Variant();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (r_option.name == "rest_pose/selected_animation") {
|
||||
|
|
@ -134,7 +138,10 @@ class SceneImportSettingsData : public Object {
|
|||
}
|
||||
} break;
|
||||
case 2: {
|
||||
Object *res = (*settings)["rest_pose/external_animation_library"];
|
||||
Object *res = nullptr;
|
||||
if (settings->has("rest_pose/external_animation_library")) {
|
||||
res = (*settings)["rest_pose/external_animation_library"];
|
||||
}
|
||||
Ref<Animation> anim(res);
|
||||
Ref<AnimationLibrary> library(res);
|
||||
if (anim.is_valid()) {
|
||||
|
|
@ -362,6 +369,7 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
|
|||
mesh_node->set_transform(src_mesh_node->get_transform());
|
||||
mesh_node->set_skin(src_mesh_node->get_skin());
|
||||
mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
|
||||
mesh_node->set_visible(src_mesh_node->is_visible());
|
||||
if (src_mesh_node->get_mesh().is_valid()) {
|
||||
Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh();
|
||||
mesh_node->set_mesh(editor_mesh->get_mesh());
|
||||
|
|
@ -414,7 +422,9 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
|
|||
animation_player->connect(SceneStringName(animation_finished), callable_mp(this, &SceneImportSettingsDialog::_animation_finished));
|
||||
} else if (Object::cast_to<Skeleton3D>(p_node)) {
|
||||
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
|
||||
skeletons.push_back(Object::cast_to<Skeleton3D>(p_node));
|
||||
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
|
||||
skeleton->connect(SceneStringName(tree_entered), callable_mp(this, &SceneImportSettingsDialog::_skeleton_tree_entered).bind(skeleton));
|
||||
skeletons.push_back(skeleton);
|
||||
} else {
|
||||
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
|
||||
}
|
||||
|
|
@ -467,6 +477,32 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
|
|||
}
|
||||
|
||||
AABB aabb = accum_xform.xform(mesh_node->get_mesh()->get_aabb());
|
||||
|
||||
if (first_aabb) {
|
||||
contents_aabb = aabb;
|
||||
first_aabb = false;
|
||||
} else {
|
||||
contents_aabb.merge_with(aabb);
|
||||
}
|
||||
}
|
||||
|
||||
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
|
||||
if (skeleton) {
|
||||
Ref<ArrayMesh> bones_mesh = Skeleton3DGizmoPlugin::get_bones_mesh(skeleton, -1, true);
|
||||
|
||||
bones_mesh_preview->set_mesh(bones_mesh);
|
||||
|
||||
Transform3D accum_xform;
|
||||
Node3D *base = skeleton;
|
||||
while (base) {
|
||||
accum_xform = base->get_transform() * accum_xform;
|
||||
base = Object::cast_to<Node3D>(base->get_parent());
|
||||
}
|
||||
|
||||
bones_mesh_preview->set_transform(accum_xform * skeleton->get_transform());
|
||||
|
||||
AABB aabb = accum_xform.xform(bones_mesh->get_aabb());
|
||||
|
||||
if (first_aabb) {
|
||||
contents_aabb = aabb;
|
||||
first_aabb = false;
|
||||
|
|
@ -672,26 +708,26 @@ void SceneImportSettingsDialog::update_view() {
|
|||
update_view_timer->start();
|
||||
}
|
||||
|
||||
void SceneImportSettingsDialog::open_settings(const String &p_path, bool p_for_animation) {
|
||||
void SceneImportSettingsDialog::open_settings(const String &p_path, const String &p_scene_import_type) {
|
||||
if (scene) {
|
||||
_cleanup();
|
||||
memdelete(scene);
|
||||
scene = nullptr;
|
||||
}
|
||||
|
||||
editing_animation = p_for_animation;
|
||||
editing_animation = p_scene_import_type == "AnimationLibrary";
|
||||
scene_import_settings_data->settings = nullptr;
|
||||
scene_import_settings_data->path = p_path;
|
||||
|
||||
// Visibility.
|
||||
data_mode->set_tab_hidden(1, p_for_animation);
|
||||
data_mode->set_tab_hidden(2, p_for_animation);
|
||||
if (p_for_animation) {
|
||||
data_mode->set_tab_hidden(1, editing_animation);
|
||||
data_mode->set_tab_hidden(2, editing_animation);
|
||||
if (editing_animation) {
|
||||
data_mode->set_current_tab(0);
|
||||
}
|
||||
|
||||
action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_EXTRACT_MATERIALS), p_for_animation);
|
||||
action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_CHOOSE_MESH_SAVE_PATHS), p_for_animation);
|
||||
action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_EXTRACT_MATERIALS), editing_animation);
|
||||
action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_CHOOSE_MESH_SAVE_PATHS), editing_animation);
|
||||
|
||||
base_path = p_path;
|
||||
|
||||
|
|
@ -765,7 +801,7 @@ void SceneImportSettingsDialog::open_settings(const String &p_path, bool p_for_a
|
|||
// Start with the root item (Scene) selected.
|
||||
scene_tree->get_root()->select(0);
|
||||
|
||||
if (p_for_animation) {
|
||||
if (editing_animation) {
|
||||
set_title(vformat(TTR("Advanced Import Settings for AnimationLibrary '%s'"), base_path.get_file()));
|
||||
} else {
|
||||
set_title(vformat(TTR("Advanced Import Settings for Scene '%s'"), base_path.get_file()));
|
||||
|
|
@ -789,6 +825,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
|
|||
selecting = true;
|
||||
scene_import_settings_data->hide_options = false;
|
||||
|
||||
bones_mesh_preview->hide();
|
||||
if (p_type == "Node") {
|
||||
node_selected->hide(); // Always hide just in case.
|
||||
mesh_preview->hide();
|
||||
|
|
@ -828,6 +865,7 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
|
|||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
|
||||
} else if (Object::cast_to<Skeleton3D>(nd.node)) {
|
||||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
|
||||
bones_mesh_preview->show();
|
||||
} else {
|
||||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
|
||||
scene_import_settings_data->hide_options = editing_animation;
|
||||
|
|
@ -847,6 +885,8 @@ void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, cons
|
|||
|
||||
scene_import_settings_data->settings = &ad.settings;
|
||||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;
|
||||
|
||||
_animation_update_skeleton_visibility();
|
||||
} else if (p_type == "Mesh") {
|
||||
node_selected->hide();
|
||||
if (Object::cast_to<Node3D>(scene)) {
|
||||
|
|
@ -981,11 +1021,11 @@ void SceneImportSettingsDialog::_play_animation() {
|
|||
if (animation_player->has_animation(id)) {
|
||||
if (animation_player->is_playing()) {
|
||||
animation_player->pause();
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
set_process(false);
|
||||
} else {
|
||||
animation_player->play(id);
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
|
||||
set_process(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -994,7 +1034,7 @@ void SceneImportSettingsDialog::_play_animation() {
|
|||
void SceneImportSettingsDialog::_stop_current_animation() {
|
||||
animation_pingpong = false;
|
||||
animation_player->stop();
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_slider->set_value_no_signal(0.0);
|
||||
set_process(false);
|
||||
}
|
||||
|
|
@ -1006,7 +1046,7 @@ void SceneImportSettingsDialog::_reset_animation(const String &p_animation_name)
|
|||
if (animation_player != nullptr && animation_player->is_playing()) {
|
||||
animation_player->stop();
|
||||
}
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
|
||||
_reset_bone_transforms();
|
||||
set_process(false);
|
||||
|
|
@ -1028,7 +1068,7 @@ void SceneImportSettingsDialog::_reset_animation(const String &p_animation_name)
|
|||
animation_player->play(p_animation_name);
|
||||
} else {
|
||||
animation_player->stop(true);
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_player->set_assigned_animation(p_animation_name);
|
||||
animation_player->seek(0.0, true);
|
||||
animation_slider->set_value_no_signal(0.0);
|
||||
|
|
@ -1043,18 +1083,23 @@ void SceneImportSettingsDialog::_animation_slider_value_changed(double p_value)
|
|||
}
|
||||
if (animation_player->is_playing()) {
|
||||
animation_player->stop();
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
set_process(false);
|
||||
}
|
||||
animation_player->seek(p_value * animation_map[selected_id].animation->get_length(), true);
|
||||
}
|
||||
|
||||
void SceneImportSettingsDialog::_skeleton_tree_entered(Skeleton3D *p_skeleton) {
|
||||
bones_mesh_preview->set_skeleton_path(p_skeleton->get_path());
|
||||
bones_mesh_preview->set_skin(p_skeleton->register_skin(p_skeleton->create_skin_from_rest_transforms()));
|
||||
}
|
||||
|
||||
void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
|
||||
Animation::LoopMode loop_mode = animation_loop_mode;
|
||||
|
||||
switch (loop_mode) {
|
||||
case Animation::LOOP_NONE: {
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_slider->set_value_no_signal(1.0);
|
||||
set_process(false);
|
||||
} break;
|
||||
|
|
@ -1074,6 +1119,14 @@ void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
|
|||
}
|
||||
}
|
||||
|
||||
void SceneImportSettingsDialog::_animation_update_skeleton_visibility() {
|
||||
if (animation_toggle_skeleton_visibility->is_pressed()) {
|
||||
bones_mesh_preview->show();
|
||||
} else {
|
||||
bones_mesh_preview->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneImportSettingsDialog::_material_tree_selected() {
|
||||
if (selecting) {
|
||||
return;
|
||||
|
|
@ -1172,6 +1225,20 @@ void SceneImportSettingsDialog::_viewport_input(const Ref<InputEvent> &p_input)
|
|||
}
|
||||
_update_camera();
|
||||
}
|
||||
Ref<InputEventMagnifyGesture> mg = p_input;
|
||||
if (mg.is_valid()) {
|
||||
real_t mg_factor = mg->get_factor();
|
||||
if (mg_factor == 0.0) {
|
||||
mg_factor = 1.0;
|
||||
}
|
||||
(*zoom) /= mg_factor;
|
||||
if ((*zoom) < 0.1) {
|
||||
(*zoom) = 0.1;
|
||||
} else if ((*zoom) > 10.0) {
|
||||
(*zoom) = 10.0;
|
||||
}
|
||||
_update_camera();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneImportSettingsDialog::_re_import() {
|
||||
|
|
@ -1262,20 +1329,22 @@ void SceneImportSettingsDialog::_notification(int p_what) {
|
|||
case NOTIFICATION_THEME_CHANGED: {
|
||||
action_menu->begin_bulk_theme_override();
|
||||
action_menu->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), "Button"));
|
||||
action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button"));
|
||||
action_menu->add_theme_style_override(SceneStringName(hover), get_theme_stylebox(SceneStringName(hover), "Button"));
|
||||
action_menu->add_theme_style_override(SceneStringName(pressed), get_theme_stylebox(SceneStringName(pressed), "Button"));
|
||||
action_menu->end_bulk_theme_override();
|
||||
|
||||
if (animation_player != nullptr && animation_player->is_playing()) {
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
|
||||
} else {
|
||||
animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
|
||||
}
|
||||
animation_stop_button->set_icon(get_editor_theme_icon(SNAME("Stop")));
|
||||
animation_stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
|
||||
|
||||
light_1_switch->set_icon(theme_cache.light_1_icon);
|
||||
light_2_switch->set_icon(theme_cache.light_2_icon);
|
||||
light_rotate_switch->set_icon(theme_cache.rotate_icon);
|
||||
light_1_switch->set_button_icon(theme_cache.light_1_icon);
|
||||
light_2_switch->set_button_icon(theme_cache.light_2_icon);
|
||||
light_rotate_switch->set_button_icon(theme_cache.rotate_icon);
|
||||
|
||||
animation_toggle_skeleton_visibility->set_button_icon(get_editor_theme_icon(SNAME("SkeletonPreview")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PROCESS: {
|
||||
|
|
@ -1648,13 +1717,14 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
|
|||
animation_hbox->add_child(animation_play_button);
|
||||
animation_play_button->set_flat(true);
|
||||
animation_play_button->set_focus_mode(Control::FOCUS_NONE);
|
||||
animation_play_button->set_shortcut(ED_SHORTCUT("scene_import_settings/play_selected_animation", TTR("Selected Animation Play/Pause"), Key::SPACE));
|
||||
animation_play_button->set_shortcut(ED_SHORTCUT("scene_import_settings/play_selected_animation", TTRC("Selected Animation Play/Pause"), Key::SPACE));
|
||||
animation_play_button->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_play_animation));
|
||||
|
||||
animation_stop_button = memnew(Button);
|
||||
animation_hbox->add_child(animation_stop_button);
|
||||
animation_stop_button->set_flat(true);
|
||||
animation_stop_button->set_focus_mode(Control::FOCUS_NONE);
|
||||
animation_stop_button->set_tooltip_text(TTR("Selected Animation Stop"));
|
||||
animation_stop_button->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_stop_current_animation));
|
||||
|
||||
animation_slider = memnew(HSlider);
|
||||
|
|
@ -1667,6 +1737,15 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
|
|||
animation_slider->set_focus_mode(Control::FOCUS_NONE);
|
||||
animation_slider->connect(SceneStringName(value_changed), callable_mp(this, &SceneImportSettingsDialog::_animation_slider_value_changed));
|
||||
|
||||
animation_toggle_skeleton_visibility = memnew(Button);
|
||||
animation_hbox->add_child(animation_toggle_skeleton_visibility);
|
||||
animation_toggle_skeleton_visibility->set_toggle_mode(true);
|
||||
animation_toggle_skeleton_visibility->set_theme_type_variation("FlatButton");
|
||||
animation_toggle_skeleton_visibility->set_focus_mode(Control::FOCUS_NONE);
|
||||
animation_toggle_skeleton_visibility->set_tooltip_text(TTR("Toggle Animation Skeleton Visibility"));
|
||||
|
||||
animation_toggle_skeleton_visibility->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_animation_update_skeleton_visibility));
|
||||
|
||||
base_viewport->set_use_own_world_3d(true);
|
||||
|
||||
HBoxContainer *viewport_hbox = memnew(HBoxContainer);
|
||||
|
|
@ -1794,6 +1873,13 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
|
|||
collider_mat->set_albedo(Color(0.5, 0.5, 1.0));
|
||||
}
|
||||
|
||||
{
|
||||
bones_mesh_preview = memnew(MeshInstance3D);
|
||||
bones_mesh_preview->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
|
||||
bones_mesh_preview->set_skeleton_path(NodePath());
|
||||
base_viewport->add_child(bones_mesh_preview);
|
||||
}
|
||||
|
||||
inspector = memnew(EditorInspector);
|
||||
inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
|
||||
inspector->connect(SNAME("property_edited"), callable_mp(this, &SceneImportSettingsDialog::_inspector_property_edited));
|
||||
|
|
|
|||
|
|
@ -37,13 +37,11 @@
|
|||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/skeleton_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/panel_container.h"
|
||||
#include "scene/gui/slider.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/3d/primitive_meshes.h"
|
||||
|
|
@ -109,10 +107,12 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
|
|||
HSlider *animation_slider = nullptr;
|
||||
Button *animation_play_button = nullptr;
|
||||
Button *animation_stop_button = nullptr;
|
||||
Button *animation_toggle_skeleton_visibility = nullptr;
|
||||
Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE;
|
||||
bool animation_pingpong = false;
|
||||
bool previous_import_as_skeleton = false;
|
||||
bool previous_rest_as_reset = false;
|
||||
MeshInstance3D *bones_mesh_preview = nullptr;
|
||||
|
||||
Ref<StandardMaterial3D> collider_mat;
|
||||
|
||||
|
|
@ -187,9 +187,11 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
|
|||
void _reset_animation(const String &p_animation_name = "");
|
||||
void _animation_slider_value_changed(double p_value);
|
||||
void _animation_finished(const StringName &p_name);
|
||||
void _animation_update_skeleton_visibility();
|
||||
void _material_tree_selected();
|
||||
void _mesh_tree_selected();
|
||||
void _scene_tree_selected();
|
||||
void _skeleton_tree_entered(Skeleton3D *p_skeleton);
|
||||
void _cleanup();
|
||||
void _on_light_1_switch_pressed();
|
||||
void _on_light_2_switch_pressed();
|
||||
|
|
@ -243,7 +245,7 @@ public:
|
|||
bool is_editing_animation() const { return editing_animation; }
|
||||
void request_generate_collider();
|
||||
void update_view();
|
||||
void open_settings(const String &p_path, bool p_for_animation = false);
|
||||
void open_settings(const String &p_path, const String &p_scene_import_type = "PackedScene");
|
||||
static SceneImportSettingsDialog *get_singleton();
|
||||
Node *get_selected_node();
|
||||
SceneImportSettingsDialog();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue