Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skeleton3D find_bone() is too slow #75915

Closed
smix8 opened this issue Apr 10, 2023 · 0 comments · Fixed by #77307
Closed

Skeleton3D find_bone() is too slow #75915

smix8 opened this issue Apr 10, 2023 · 0 comments · Fixed by #77307

Comments

@smix8
Copy link
Contributor

smix8 commented Apr 10, 2023

Godot version

c3ed7af

System information

Windows 10

Issue description

The Skeleton.find_bone() function is too slow with complex skeletons that have many bones.

While this was always the issue with find_bone() even far back as in Godot 3 the issue with its slowness is now amplified due to other more recent changes to skeletons and the asset import.

E.g. in Godot 4 the asset importer adds extra bones for each bone attachment. You end up with a lot more bones than usual to search. If you have 100 meshes all parented to the same bone in e.g. Blender you end up with 100 extra bones in Godot.

Godot 3 did not add extra bones for each bone attachment but this was apparently changed to solve other bugs with index shuffling like #64512 and #61641.

The old workaround of using the bone index instead of the name to do e.g. runtime skeleton mods does not work well now that the bone index are shuffled still with every changed attachment that adds new bones. The current situation requires to use a custom cache for bone name to bone index instead of using the slow Skeleton find_bone() function.

The solution could possibly be to use an internal HashMap for bone_name_to_bone_index instead of the current find_bone() loop that goes over the entire bone array everytime.

Steps to reproduce

func _ready() -> void:
	var skeleton : Skeleton3D = Skeleton3D.new()
	var bone_names : Array = []
	for i in 500:
		var bone_name : String = "bone_%s" % str(i)
		bone_names.push_back(bone_name)
		skeleton.add_bone(bone_names[i])
	
	var bone_map : Dictionary = {}
	for bone_name in bone_names:
		var bone_index : int = skeleton.find_bone(bone_name)
		bone_map[bone_name] = bone_index
	
	var time : int = 0
	var time_total : int = 0
	
	time = Time.get_ticks_usec()
	for bone_name in bone_names:
		var bone_index : int = skeleton.find_bone(bone_name)
	time_total = Time.get_ticks_usec() - time
	print("Time find_bone(): %s" % time_total)
	
	time = Time.get_ticks_usec()
	for bone_name in bone_names:
		var bone_index : int = bone_map[bone_name]
	time_total = Time.get_ticks_usec() - time
	print("Time Dictionary: %s" % time_total)

	# E.g. result:
	# Time find_bone(): 5907
	# Time Dictionary: 201

Minimal reproduction project

see steps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants