Merge pull request #87923 from smix8/meshlib_export_recursive
Make MeshLibrary export do recursive depth-search for MeshInstance3D nodes
This commit is contained in:
commit
eac2091345
3 changed files with 95 additions and 104 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue