Make MeshLibrary export do recursive depth-search for MeshInstance3D nodes

Makes MeshLibrary export do recursive depth-search for MeshInstance3D nodes.
This commit is contained in:
smix8 2023-11-27 16:49:49 +01:00
parent b4e2a24c1f
commit 4d0c21c131
3 changed files with 95 additions and 104 deletions

View file

@ -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()) {
@ -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) {

View file

@ -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!
@ -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;

View file

@ -37,6 +37,7 @@
class EditorFileDialog;
class ConfirmationDialog;
class MenuButton;
class MeshInstance3D;
class MeshLibraryEditor : public Control {
GDCLASS(MeshLibraryEditor, Control);
@ -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();