Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make MeshLibrary export do recursive depth-search for MeshInstance3D nodes #87923

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2026,8 +2026,11 @@ void EditorNode::_dialog_action(String p_file) {
} break;

case FILE_EXPORT_MESH_LIBRARY: {
bool merge_with_existing_library = file_export_lib_merge->is_pressed();
bool apply_mesh_instance_transforms = file_export_lib_apply_xforms->is_pressed();

Ref<MeshLibrary> ml;
if (file_export_lib_merge->is_pressed() && FileAccess::exists(p_file)) {
if (merge_with_existing_library && FileAccess::exists(p_file)) {
ml = ResourceLoader::load(p_file, "MeshLibrary");

if (ml.is_null()) {
Expand All @@ -2040,7 +2043,7 @@ void EditorNode::_dialog_action(String p_file) {
ml = Ref<MeshLibrary>(memnew(MeshLibrary));
}

MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, true, file_export_lib_apply_xforms->is_pressed());
MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, merge_with_existing_library, apply_mesh_instance_transforms);

Error err = ResourceSaver::save(ml, p_file);
if (err) {
Expand Down
190 changes: 88 additions & 102 deletions editor/plugins/mesh_library_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,108 +78,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
HashMap<int, MeshInstance3D *> mesh_instances;

for (int i = 0; i < p_scene->get_child_count(); i++) {
Node *child = p_scene->get_child(i);

if (!Object::cast_to<MeshInstance3D>(child)) {
if (child->get_child_count() > 0) {
child = child->get_child(0);
if (!Object::cast_to<MeshInstance3D>(child)) {
continue;
}

} else {
continue;
}
}

MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(child);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_null()) {
continue;
}

mesh = mesh->duplicate();
for (int j = 0; j < mesh->get_surface_count(); ++j) {
Ref<Material> mat = mi->get_surface_override_material(j);

if (mat.is_valid()) {
mesh->surface_set_material(j, mat);
}
}

int id = p_library->find_item_by_name(mi->get_name());
if (id < 0) {
id = p_library->get_last_unused_item_id();
p_library->create_item(id);
p_library->set_item_name(id, mi->get_name());
}

p_library->set_item_mesh(id, mesh);

if (p_apply_xforms) {
p_library->set_item_mesh_transform(id, mi->get_transform());
} else {
p_library->set_item_mesh_transform(id, Transform3D());
}

mesh_instances[id] = mi;

Vector<MeshLibrary::ShapeData> collisions;

for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
if (!Object::cast_to<StaticBody3D>(child2)) {
continue;
}

StaticBody3D *sb = Object::cast_to<StaticBody3D>(child2);
List<uint32_t> shapes;
sb->get_shape_owners(&shapes);

for (uint32_t &E : shapes) {
if (sb->is_shape_owner_disabled(E)) {
continue;
}

Transform3D shape_transform;
if (p_apply_xforms) {
shape_transform = mi->get_transform();
}
shape_transform *= sb->get_transform() * sb->shape_owner_get_transform(E);

for (int k = 0; k < sb->shape_owner_get_shape_count(E); k++) {
Ref<Shape3D> collision = sb->shape_owner_get_shape(E, k);
if (!collision.is_valid()) {
continue;
}
MeshLibrary::ShapeData shape_data;
shape_data.shape = collision;
shape_data.local_transform = shape_transform;
collisions.push_back(shape_data);
}
}
}

p_library->set_item_shapes(id, collisions);

Ref<NavigationMesh> navigation_mesh;
Transform3D navigation_mesh_transform;
for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
if (!Object::cast_to<NavigationRegion3D>(child2)) {
continue;
}
NavigationRegion3D *sb = Object::cast_to<NavigationRegion3D>(child2);
navigation_mesh = sb->get_navigation_mesh();
navigation_mesh_transform = sb->get_transform();
if (!navigation_mesh.is_null()) {
break;
}
}
if (!navigation_mesh.is_null()) {
p_library->set_item_navigation_mesh(id, navigation_mesh);
p_library->set_item_navigation_mesh_transform(id, navigation_mesh_transform);
}
_import_scene_parse_node(p_library, mesh_instances, p_scene->get_child(i), p_merge, p_apply_xforms);
}

//generate previews!
Expand Down Expand Up @@ -221,6 +120,93 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) {
menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), false);
}

void MeshLibraryEditor::_import_scene_parse_node(Ref<MeshLibrary> p_library, HashMap<int, MeshInstance3D *> &p_mesh_instances, Node *p_node, bool p_merge, bool p_apply_xforms) {
MeshInstance3D *mesh_instance_node = Object::cast_to<MeshInstance3D>(p_node);

if (!mesh_instance_node) {
// No MeshInstance so search deeper ...
for (int i = 0; i < p_node->get_child_count(); i++) {
_import_scene_parse_node(p_library, p_mesh_instances, p_node->get_child(i), p_merge, p_apply_xforms);
}
return;
}

Ref<Mesh> source_mesh = mesh_instance_node->get_mesh();
if (source_mesh.is_null()) {
return;
}

int item_id = p_library->find_item_by_name(mesh_instance_node->get_name());
if (item_id < 0) {
item_id = p_library->get_last_unused_item_id();
p_library->create_item(item_id);
p_library->set_item_name(item_id, mesh_instance_node->get_name());
} else if (!p_merge) {
WARN_PRINT(vformat("MeshLibrary export found a MeshInstance3D with a duplicated name '%s' in the exported scene that overrides a previously parsed MeshInstance3D item with the same name.", mesh_instance_node->get_name()));
}
p_mesh_instances[item_id] = mesh_instance_node;

Ref<Mesh> item_mesh = source_mesh->duplicate();
for (int i = 0; i < item_mesh->get_surface_count(); i++) {
Ref<Material> surface_override_material = mesh_instance_node->get_surface_override_material(i);
if (surface_override_material.is_valid()) {
item_mesh->surface_set_material(i, surface_override_material);
}
}
p_library->set_item_mesh(item_id, item_mesh);

Transform3D item_mesh_transform;
if (p_apply_xforms) {
item_mesh_transform = mesh_instance_node->get_transform();
}
p_library->set_item_mesh_transform(item_id, item_mesh_transform);

Vector<MeshLibrary::ShapeData> collisions;
for (int i = 0; i < mesh_instance_node->get_child_count(); i++) {
StaticBody3D *static_body_node = Object::cast_to<StaticBody3D>(mesh_instance_node->get_child(i));
if (!static_body_node) {
continue;
}
List<uint32_t> shapes;
static_body_node->get_shape_owners(&shapes);
for (uint32_t &E : shapes) {
if (static_body_node->is_shape_owner_disabled(E)) {
continue;
}
Transform3D shape_transform;
if (p_apply_xforms) {
shape_transform = mesh_instance_node->get_transform();
}
shape_transform *= static_body_node->get_transform() * static_body_node->shape_owner_get_transform(E);
for (int k = 0; k < static_body_node->shape_owner_get_shape_count(E); k++) {
Ref<Shape3D> collision_shape = static_body_node->shape_owner_get_shape(E, k);
if (!collision_shape.is_valid()) {
continue;
}
MeshLibrary::ShapeData shape_data;
shape_data.shape = collision_shape;
shape_data.local_transform = shape_transform;
collisions.push_back(shape_data);
}
}
}
p_library->set_item_shapes(item_id, collisions);

for (int i = 0; i < mesh_instance_node->get_child_count(); i++) {
NavigationRegion3D *navigation_region_node = Object::cast_to<NavigationRegion3D>(mesh_instance_node->get_child(i));
if (!navigation_region_node) {
continue;
}
Ref<NavigationMesh> navigation_mesh = navigation_region_node->get_navigation_mesh();
if (!navigation_mesh.is_null()) {
Transform3D navigation_mesh_transform = navigation_region_node->get_transform();
p_library->set_item_navigation_mesh(item_id, navigation_mesh);
p_library->set_item_navigation_mesh_transform(item_id, navigation_mesh_transform);
break;
}
}
}

Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge, bool p_apply_xforms) {
_import_scene(p_base_scene, ml, p_merge, p_apply_xforms);
return OK;
Expand Down
2 changes: 2 additions & 0 deletions editor/plugins/mesh_library_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
class EditorFileDialog;
class ConfirmationDialog;
class MenuButton;
class MeshInstance3D;

class MeshLibraryEditor : public Control {
GDCLASS(MeshLibraryEditor, Control);
Expand Down Expand Up @@ -65,6 +66,7 @@ class MeshLibraryEditor : public Control {
void _menu_update_confirm(bool p_apply_xforms);

static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms);
static void _import_scene_parse_node(Ref<MeshLibrary> p_library, HashMap<int, MeshInstance3D *> &p_mesh_instances, Node *p_node, bool p_merge, bool p_apply_xforms);

protected:
static void _bind_methods();
Expand Down
Loading