Skip to content

Instantly share code, notes, and snippets.

@noidexe
Created September 2, 2024 13:59
Show Gist options
  • Save noidexe/7cfbdc50a9a8656795fb41bb1c8b8e1b to your computer and use it in GitHub Desktop.
Save noidexe/7cfbdc50a9a8656795fb41bb1c8b8e1b to your computer and use it in GitHub Desktop.
Post Import script with mesh deduplication
@tool
extends EditorScenePostImport
func _post_import(scene: Node) -> Object:
_deduplicate_meshes(scene, true)
return scene
# Finds duplicate meshes and deduplicates them, using a content hash for comparison
func _deduplicate_meshes(scene : Node, verbose := false) -> void:
var start_time := Time.get_ticks_msec()
var duplicate_count : int = 0
if verbose:
print("=========================================")
print("DEDUPLICATING MESHES...")
print("=========================================")
# Get a list of all meshinstances
var instances : Array[Node] = scene.find_children("*", "MeshInstance3D")
# Map< mesh content hash : reference to mesh instance >
var mesh_library : Dictionary = {}
for instance : MeshInstance3D in instances:
# Get the mesh from the MeshInstance3D node
var mesh : ArrayMesh = (instance as MeshInstance3D).mesh as ArrayMesh
# Create a hash based on content
var mesh_uid := _generate_mesh_uid(mesh)
# If we already have a mesh in mesh_library stored under that uid then we
# found a duplicate and we should replace it in the scene with the one
# from the library
var replacement_mesh : ArrayMesh = mesh_library.get(mesh_uid)
if replacement_mesh:
if verbose:
print("Found mesh %s for meshinstance %s, replacing..." % [replacement_mesh, instance.name])
duplicate_count += 1
instance.mesh = replacement_mesh
# otherwise, if it's the first time we see that mesh let's add it to the
# mesh library
else:
if verbose:
print("No meshes found for meshinstance %s, adding %s" % [instance.name, instance.mesh])
mesh_library[mesh_uid] = mesh
var total_time_sec : float = ( Time.get_ticks_msec() - start_time ) / 1000.0
print("================================================")
print("Scanned %s meshes and removed %s duplicates in %s seconds" % [ instances.size(), duplicate_count, total_time_sec ] )
# Creates a unique identifier for each mesh based on content
# Two meshes with the same vertex data and materials get the same uid
# which is then used for deduplication
func _generate_mesh_uid( mesh : ArrayMesh) -> int:
var surface_count = mesh.get_surface_count()
# The surfaces array will contain all per vertex data. Geometry, UVs, normals. etc
var surfaces : Array = []
# Even if the surface data is identical, two meshes are distinct if they have different
# materials assigned, so we get that info too
var materials : Array = []
# If you can think of any other data that's relevant you can add it here, but we shuold
# hash the minimum amount of data that accounts for all possible differences
for i in surface_count:
surfaces.append_array(mesh.surface_get_arrays(i))
materials.append(mesh.surface_get_material(i))
var data := surfaces + materials
# We return a hash of all the data
return data.hash()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment