Skip to content

Commit

Permalink
Merge pull request #60115 from V-Sekai/scene_scale
Browse files Browse the repository at this point in the history
  • Loading branch information
akien-mga authored Sep 6, 2022
2 parents 7a620e3 + befc4b7 commit a49ec43
Showing 1 changed file with 195 additions and 6 deletions.
201 changes: 195 additions & 6 deletions editor/import/resource_importer_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,185 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r
}
}

struct ScalableNodeCollection {
HashSet<Node3D *> node_3ds;
HashSet<Ref<ImporterMesh>> importer_meshes;
HashSet<Ref<Skin>> skins;
HashSet<Ref<Animation>> animations;
};

void _rescale_importer_mesh(Vector3 p_scale, Ref<ImporterMesh> 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<Material> mat;
int fmt_compress_flags = 0;
};

Vector<LocalSurfData> surf_data_by_mesh;

Vector<String> 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<Material> mat = p_mesh->get_surface_material(surf_idx);
{
Vector<Vector3> 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<Vector3> 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<Material> 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<Skin> 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<Animation> 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<Skeleton3D>(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<ImporterMesh> mesh : p_dictionary.importer_meshes) {
_rescale_importer_mesh(p_scale, mesh, false);
}
for (Ref<Skin> skin : p_dictionary.skins) {
_rescale_skin(p_scale, skin);
}
for (Ref<Animation> 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<Node3D>(p_node);
if (node_3d) {
p_dictionary.node_3ds.insert(node_3d);
ImporterMeshInstance3D *mesh_instance_3d = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (mesh_instance_3d) {
Ref<ImporterMesh> mesh = mesh_instance_3d->get_mesh();
if (mesh.is_valid()) {
p_dictionary.importer_meshes.insert(mesh);
}
Ref<Skin> skin = mesh_instance_3d->get_skin();
if (skin.is_valid()) {
p_dictionary.skins.insert(skin);
}
}
}
AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_node);
if (animation_player) {
List<StringName> animation_list;
animation_player->get_animation_list(&animation_list);

for (const StringName &E : animation_list) {
Ref<Animation> 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<Node3D>(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<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames) {
// Children first.
for (int i = 0; i < p_node->get_child_count(); i++) {
Expand Down Expand Up @@ -1678,6 +1857,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
script_ext_hint += "*." + E;
}

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, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
Expand Down Expand Up @@ -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<Node3D>(scene)) {
Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
}
if (apply_root) {
_apply_permanent_rotation_scale_to_node(scene);
Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale).inverse());
}
Dictionary subresources = p_options["_subresources"];

Dictionary node_data;
Expand Down Expand Up @@ -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<Node3D>(scene)) {
root_scale = p_options["nodes/root_scale"];
Object::cast_to<Node3D>(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 {
Expand Down

0 comments on commit a49ec43

Please sign in to comment.