Skip to content

Instantly share code, notes, and snippets.

@QaDeS
Last active July 2, 2023 04:30
Show Gist options
  • Save QaDeS/15ffb60242c4a1654bea7e3c2c87208d to your computer and use it in GitHub Desktop.
Save QaDeS/15ffb60242c4a1654bea7e3c2c87208d to your computer and use it in GitHub Desktop.
PoC: Just set the Dir to a folder of exported Mixamo FBX and have Characters and Animations imported automatically. Feedback welcome!
@tool
extends Node3D
@export_dir var dir :
set(value):
perform_import(value)
@export var bone_map : BoneMap
@export var create_Animation_tree : bool = false
@export var hip : String = "Hips"
@export var loops = [
"idle",
"walk",
"strafe"
]
const extensions = ["fbx"]
func perform_import(path):
#clear_children()
var player = AnimationPlayer.new()
add_child(player, true)
player.set_owner(self)
var lib = AnimationLibrary.new()
var files = DirAccess.get_files_at(path)
var skin : Node3D
for file in files:
if not extensions.has(file.get_extension()): continue
var node : Node3D = ResourceLoader.load(path + "/" + file).instantiate()
var has_mesh = !node.find_children("", "MeshInstance3D").is_empty()
if has_mesh:
skin = add_skin(node, file.get_basename())
player.root_node = skin.get_path()
add_anim(node, file.get_basename(), lib)
if skin:
var skel = skin.find_children("", "Skeleton3D", true, false)[0]
remap_bones(skel, lib)
var res = ResourceSaver.save(lib, path + ".tres")
player.add_animation_library(path.get_basename().get_file(), lib)
func clear_children():
for child in get_children():
remove_child(child)
func bone_name(name : String) -> String:
return name.split("_")[-1]
func remap_bones(skel : Skeleton3D, lib : AnimationLibrary):
var mapping = {}
for i in skel.get_bone_count():
var name = skel.get_bone_name(i)
var pname = name
if bone_map:
pname = bone_map.get_skeleton_bone_name(name)
mapping[bone_name(pname)] = name
#print(mapping)
for name in lib.get_animation_list():
var anim = lib.get_animation(name)
for track in anim.get_track_count():
var track_name = bone_name(anim.track_get_path(track))
anim.track_set_path(track, skel.name + ":" + mapping.get(track_name, track_name))
func add_skin(n:Node3D, name:String):
var node = n.get_child(0).duplicate()
node.name = name
add_child(node)
node.set_owner(self)
var skel : Skeleton3D = node.find_children("", "Skeleton3D", true, false)[0]
var old_roots = skel.get_parentless_bones()
skel.add_bone("Root")
var root = skel.find_bone("Root")
for bone in old_roots:
skel.set_bone_parent(bone, root)
return node
func add_anim(node, name, lib: AnimationLibrary):
var player : AnimationPlayer = node.find_child("AnimationPlayer").duplicate()
for anim_name in player.get_animation_list():
var anim : Animation = player.get_animation(anim_name).duplicate(true)
for track in range(anim.get_track_count()):
var t = anim.track_get_path(track)
var sub = t.get_name(t.get_name_count() - 1)
var type = anim.track_get_type(track)
for loop in loops:
if name.contains(loop):
anim.loop_mode = Animation.LoopMode.LOOP_LINEAR
if sub.ends_with(hip) and type == Animation.TrackType.TYPE_POSITION_3D:
anim.track_set_path(track, NodePath("Root"))
var first = Vector3(anim.track_get_key_value(track, 0))
for key in range(anim.track_get_key_count(track)):
var value : Vector3 = anim.track_get_key_value(track, key)
value -= first
anim.track_set_key_value(track, key, value)
lib.add_animation(name, anim)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment