diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 62cb6e41671..41061c3fc3d 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -368,6 +368,185 @@ static void _pre_gen_shape_list(Ref &mesh, Vector> &r } } +struct ScalableNodeCollection { + HashSet node_3ds; + HashSet> importer_meshes; + HashSet> skins; + HashSet> animations; +}; + +void _rescale_importer_mesh(Vector3 p_scale, Ref p_mesh, bool is_shadow = false) { + // MESH and SKIN data divide, to compensate for object position multiplying. + + const int surf_count = p_mesh->get_surface_count(); + const int blendshape_count = p_mesh->get_blend_shape_count(); + struct LocalSurfData { + Mesh::PrimitiveType prim = {}; + Array arr; + Array bsarr; + Dictionary lods; + String name; + Ref mat; + int fmt_compress_flags = 0; + }; + + Vector surf_data_by_mesh; + + Vector blendshape_names; + for (int bsidx = 0; bsidx < blendshape_count; bsidx++) { + blendshape_names.append(p_mesh->get_blend_shape_name(bsidx)); + } + + for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) { + Mesh::PrimitiveType prim = p_mesh->get_surface_primitive_type(surf_idx); + const int fmt_compress_flags = p_mesh->get_surface_format(surf_idx); + Array arr = p_mesh->get_surface_arrays(surf_idx); + String name = p_mesh->get_surface_name(surf_idx); + Dictionary lods = Dictionary(); + Ref mat = p_mesh->get_surface_material(surf_idx); + { + Vector vertex_array = arr[ArrayMesh::ARRAY_VERTEX]; + for (int vert_arr_i = 0; vert_arr_i < vertex_array.size(); vert_arr_i++) { + vertex_array.write[vert_arr_i] = vertex_array[vert_arr_i] * p_scale; + } + arr[ArrayMesh::ARRAY_VERTEX] = vertex_array; + } + Array blendshapes; + for (int bsidx = 0; bsidx < blendshape_count; bsidx++) { + Array current_bsarr = p_mesh->get_surface_blend_shape_arrays(surf_idx, bsidx); + Vector current_bs_vertex_array = current_bsarr[ArrayMesh::ARRAY_VERTEX]; + int current_bs_vert_arr_len = current_bs_vertex_array.size(); + for (int32_t bs_vert_arr_i = 0; bs_vert_arr_i < current_bs_vert_arr_len; bs_vert_arr_i++) { + current_bs_vertex_array.write[bs_vert_arr_i] = current_bs_vertex_array[bs_vert_arr_i] * p_scale; + } + current_bsarr[ArrayMesh::ARRAY_VERTEX] = current_bs_vertex_array; + blendshapes.push_back(current_bsarr); + } + + LocalSurfData surf_data_dictionary = LocalSurfData(); + surf_data_dictionary.prim = prim; + surf_data_dictionary.arr = arr; + surf_data_dictionary.bsarr = blendshapes; + surf_data_dictionary.lods = lods; + surf_data_dictionary.fmt_compress_flags = fmt_compress_flags; + surf_data_dictionary.name = name; + surf_data_dictionary.mat = mat; + + surf_data_by_mesh.push_back(surf_data_dictionary); + } + + p_mesh->clear(); + + for (int bsidx = 0; bsidx < blendshape_count; bsidx++) { + p_mesh->add_blend_shape(blendshape_names[bsidx]); + } + + for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) { + const Mesh::PrimitiveType prim = surf_data_by_mesh[surf_idx].prim; + const Array arr = surf_data_by_mesh[surf_idx].arr; + const Array bsarr = surf_data_by_mesh[surf_idx].bsarr; + const Dictionary lods = surf_data_by_mesh[surf_idx].lods; + const int fmt_compress_flags = surf_data_by_mesh[surf_idx].fmt_compress_flags; + const String name = surf_data_by_mesh[surf_idx].name; + const Ref mat = surf_data_by_mesh[surf_idx].mat; + + p_mesh->add_surface(prim, arr, bsarr, lods, mat, name, fmt_compress_flags); + } + + if (!is_shadow && p_mesh->get_shadow_mesh() != p_mesh && p_mesh->get_shadow_mesh().is_valid()) { + _rescale_importer_mesh(p_scale, p_mesh->get_shadow_mesh(), true); + } +} + +void _rescale_skin(Vector3 p_scale, Ref p_skin) { + // MESH and SKIN data divide, to compensate for object position multiplying. + for (int i = 0; i < p_skin->get_bind_count(); i++) { + Transform3D transform = p_skin->get_bind_pose(i); + p_skin->set_bind_pose(i, Transform3D(transform.basis, p_scale * transform.origin)); + } +} + +void _rescale_animation(Vector3 p_scale, Ref p_animation) { + for (int track_idx = 0; track_idx < p_animation->get_track_count(); track_idx++) { + if (p_animation->track_get_type(track_idx) == Animation::TYPE_POSITION_3D) { + for (int key_idx = 0; key_idx < p_animation->track_get_key_count(track_idx); key_idx++) { + Vector3 value = p_animation->track_get_key_value(track_idx, key_idx); + value = p_scale * value; + p_animation->track_set_key_value(track_idx, key_idx, value); + } + } + } +} + +void _apply_basis_to_scalable_node_collection(ScalableNodeCollection &p_dictionary, Vector3 p_scale) { + for (Node3D *node_3d : p_dictionary.node_3ds) { + if (node_3d) { + node_3d->set_position(p_scale * node_3d->get_position()); + + Skeleton3D *skeleton_3d = Object::cast_to(node_3d); + if (skeleton_3d) { + for (int i = 0; i < skeleton_3d->get_bone_count(); i++) { + Transform3D rest = skeleton_3d->get_bone_rest(i); + skeleton_3d->set_bone_rest(i, Transform3D(rest.basis, p_scale * rest.origin)); + skeleton_3d->set_bone_pose_position(i, p_scale * rest.origin); + } + } + } + } + for (Ref mesh : p_dictionary.importer_meshes) { + _rescale_importer_mesh(p_scale, mesh, false); + } + for (Ref skin : p_dictionary.skins) { + _rescale_skin(p_scale, skin); + } + for (Ref animation : p_dictionary.animations) { + _rescale_animation(p_scale, animation); + } +} + +void _populate_scalable_nodes_collection(Node *p_node, ScalableNodeCollection &p_dictionary) { + if (!p_node) { + return; + } + Node3D *node_3d = Object::cast_to(p_node); + if (node_3d) { + p_dictionary.node_3ds.insert(node_3d); + ImporterMeshInstance3D *mesh_instance_3d = Object::cast_to(p_node); + if (mesh_instance_3d) { + Ref mesh = mesh_instance_3d->get_mesh(); + if (mesh.is_valid()) { + p_dictionary.importer_meshes.insert(mesh); + } + Ref skin = mesh_instance_3d->get_skin(); + if (skin.is_valid()) { + p_dictionary.skins.insert(skin); + } + } + } + AnimationPlayer *animation_player = Object::cast_to(p_node); + if (animation_player) { + List animation_list; + animation_player->get_animation_list(&animation_list); + + for (const StringName &E : animation_list) { + Ref animation = animation_player->get_animation(E); + p_dictionary.animations.insert(animation); + } + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child = p_node->get_child(i); + _populate_scalable_nodes_collection(child, p_dictionary); + } +} + +void _apply_permanent_rotation_scale_to_node(Node *p_node) { + Transform3D transform = Object::cast_to(p_node)->get_transform(); + ScalableNodeCollection scalable_node_collection; + _populate_scalable_nodes_collection(p_node, scalable_node_collection); + _apply_basis_to_scalable_node_collection(scalable_node_collection, transform.basis.get_scale()); +} + Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap, Vector>> &r_collision_map, Pair *r_occluder_arrays, List> &r_node_renames) { // Children first. for (int i = 0; i < p_node->get_child_count(); i++) { @@ -1678,6 +1857,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, Listpush_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, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true)); @@ -2144,6 +2324,21 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p return err; } + bool apply_root = true; + if (p_options.has("nodes/apply_root_scale")) { + apply_root = p_options["nodes/apply_root_scale"]; + } + real_t root_scale = 1; + if (p_options.has("nodes/root_scale")) { + root_scale = p_options["nodes/root_scale"]; + } + if (Object::cast_to(scene)) { + Object::cast_to(scene)->scale(Vector3(root_scale, root_scale, root_scale)); + } + if (apply_root) { + _apply_permanent_rotation_scale_to_node(scene); + Object::cast_to(scene)->scale(Vector3(root_scale, root_scale, root_scale).inverse()); + } Dictionary subresources = p_options["_subresources"]; Dictionary node_data; @@ -2199,12 +2394,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p scene->set_script(Variant(root_script)); } - float root_scale = 1.0; - if (Object::cast_to(scene)) { - root_scale = p_options["nodes/root_scale"]; - Object::cast_to(scene)->scale(Vector3(root_scale, root_scale, root_scale)); - } - if (p_options["nodes/root_name"] != "Scene Root") { scene->set_name(p_options["nodes/root_name"]); } else {