diff --git a/doc/classes/MeshInstance.xml b/doc/classes/MeshInstance.xml
index 2a70c35e60d..ab81a44631e 100644
--- a/doc/classes/MeshInstance.xml
+++ b/doc/classes/MeshInstance.xml
@@ -61,6 +61,28 @@
Returns the number of surface materials.
+
+
+
+
+ Returns [code]true[/code] if this [MeshInstance] can be merged with the specified [code]other_mesh_instance[/code], using the [method MeshInstance.merge_meshes] function.
+ In order to be mergeable, properties of the [MeshInstance] must match, and each surface must match, in terms of material, attributes and vertex format.
+
+
+
+
+
+
+
+
+ This function can merge together the data from several source [MeshInstance]s into a single destination [MeshInstance] (the MeshInstance the function is called from). This is primarily useful for improving performance by reducing the number of drawcalls and [Node]s.
+ Merging should only be attempted for simple meshes that do not contain animation.
+ The final vertices can either be returned in global space, or in local space relative to the destination [MeshInstance] global transform (the destination Node must be inside the [SceneTree] for local space to work).
+ The function will make a final check for compatibility between the [MeshInstance]s by default, this should always be used unless you have previously checked for compatibility using [method MeshInstance.is_mergeable_with]. If the compatibility check is omitted and the meshes are merged, you may see rendering errors.
+ [b]Note:[/b] The requirements for similarity between meshes are quite stringent. They can be checked using the [method MeshInstance.is_mergeable_with] function prior to calling [method MeshInstance.merge_meshes].
+ Also note that any initial data in the destination [MeshInstance] data will be discarded.
+
+
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 3a7f2844020..a97547ac33a 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -847,6 +847,27 @@ void MeshInstance::create_debug_tangents() {
}
}
+bool MeshInstance::merge_meshes(Vector p_list, bool p_use_global_space, bool p_check_compatibility) {
+ // bound function only support variants, so we need to convert to a list of MeshInstances
+ Vector mis;
+
+ for (int n = 0; n < p_list.size(); n++) {
+ MeshInstance *mi = Object::cast_to(p_list[n]);
+ if (mi) {
+ if (mi != this) {
+ mis.push_back(mi);
+ } else {
+ ERR_PRINT("Destination MeshInstance cannot be a source.");
+ }
+ } else {
+ ERR_PRINT("Only MeshInstances can be merged.");
+ }
+ }
+
+ ERR_FAIL_COND_V(!mis.size(), "Array contains no MeshInstances");
+ return _merge_meshes(mis, p_use_global_space, p_check_compatibility);
+}
+
bool MeshInstance::is_mergeable_with(Node *p_other) const {
const MeshInstance *mi = Object::cast_to(p_other);
@@ -1153,7 +1174,7 @@ bool MeshInstance::_triangle_is_degenerate(const Vector3 &p_a, const Vector3 &p_
// If p_check_compatibility is set to false you MUST have performed a prior check using
// is_mergeable_with, otherwise you could get mismatching surface formats leading to graphical errors etc.
-bool MeshInstance::merge_meshes(Vector p_list, bool p_use_global_space, bool p_check_compatibility) {
+bool MeshInstance::_merge_meshes(Vector p_list, bool p_use_global_space, bool p_check_compatibility) {
if (p_list.size() < 1) {
// should not happen but just in case
return false;
@@ -1302,6 +1323,10 @@ void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance::create_debug_tangents);
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+ ClassDB::bind_method(D_METHOD("is_mergeable_with", "other_mesh_instance"), &MeshInstance::is_mergeable_with);
+ ClassDB::bind_method(D_METHOD("merge_meshes", "mesh_instances", "use_global_space", "check_compatibility"), &MeshInstance::merge_meshes, DEFVAL(Vector()), DEFVAL(false), DEFVAL(true));
+ ClassDB::set_method_flags("MeshInstance", "merge_meshes", METHOD_FLAGS_DEFAULT);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 8508b67eb77..b0740d700c9 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -96,6 +96,7 @@ protected:
private:
// merging
+ bool _merge_meshes(Vector p_list, bool p_use_global_space, bool p_check_compatibility);
bool _is_mergeable_with(const MeshInstance &p_other) const;
void _merge_into_mesh_data(const MeshInstance &p_mi, const Transform &p_dest_tr_inv, int p_surface_id, PoolVector &r_verts, PoolVector &r_norms, PoolVector &r_tangents, PoolVector &r_colors, PoolVector &r_uvs, PoolVector &r_uv2s, PoolVector &r_inds);
bool _ensure_indices_valid(PoolVector &r_indices, const PoolVector &p_verts) const;
@@ -146,7 +147,7 @@ public:
// merging
bool is_mergeable_with(Node *p_other) const;
- bool merge_meshes(Vector p_list, bool p_use_global_space, bool p_check_compatibility);
+ bool merge_meshes(Vector p_list, bool p_use_global_space, bool p_check_compatibility);
virtual AABB get_aabb() const;
virtual PoolVector get_faces(uint32_t p_usage_flags) const;
diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp
index 0d54ab98554..25db2700e5a 100644
--- a/scene/3d/room_manager.cpp
+++ b/scene/3d/room_manager.cpp
@@ -2190,7 +2190,14 @@ void RoomManager::_merge_meshes_in_room(Room *p_room) {
_merge_log("\t\t" + merged->get_name());
- if (merged->merge_meshes(merge_list, true, false)) {
+ // merge function takes a vector of variants
+ Vector variant_merge_list;
+ variant_merge_list.resize(merge_list.size());
+ for (int i = 0; i < merge_list.size(); i++) {
+ variant_merge_list.set(i, merge_list[i]);
+ }
+
+ if (merged->merge_meshes(variant_merge_list, true, false)) {
// set all the source meshes to portal mode ignore so not shown
for (int i = 0; i < merge_list.size(); i++) {
merge_list[i]->set_portal_mode(CullInstance::PORTAL_MODE_IGNORE);