From cf1b3fdd55989fe7b2d8ef665ce5fefec4db4cb7 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sat, 5 Feb 2022 13:03:02 +0000 Subject: [PATCH] Bind mesh merging functionality in MeshInstance The portal system introduced basic mesh merging functionality, this has wide ranging uses outside of the portal system. For this reason, this PR binds the mesh merging functionality. It also slightly modifies the calling from RoomManager to use a Vector of Node *, in order to allow binding of the function. --- doc/classes/MeshInstance.xml | 22 ++++++++++++++++++++++ scene/3d/mesh_instance.cpp | 27 ++++++++++++++++++++++++++- scene/3d/mesh_instance.h | 3 ++- scene/3d/room_manager.cpp | 9 ++++++++- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/doc/classes/MeshInstance.xml b/doc/classes/MeshInstance.xml index a5f48b7f204..6392222b67e 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 5bf43ca94a1..32915c5be6b 100644 --- a/scene/3d/room_manager.cpp +++ b/scene/3d/room_manager.cpp @@ -2156,7 +2156,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);