Created
September 2, 2024 13:59
-
-
Save noidexe/7cfbdc50a9a8656795fb41bb1c8b8e1b to your computer and use it in GitHub Desktop.
Post Import script with mesh deduplication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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