From 9fc0df0e1774816eb89151ba593cc98ab6888700 Mon Sep 17 00:00:00 2001 From: bangbangsheshotmedown Date: Fri, 15 Aug 2025 12:21:18 +0200 Subject: [PATCH 1/2] Include root motion bone --- blender-4.1/iqm_export.py | 41 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/blender-4.1/iqm_export.py b/blender-4.1/iqm_export.py index 119ccdf..f987478 100644 --- a/blender-4.1/iqm_export.py +++ b/blender-4.1/iqm_export.py @@ -664,6 +664,14 @@ def derigifyBones(context, armature, scale): def2org = {} defparent = {} defchildren = {} + + # Find the root motion bone + root_bone = None + for bone in data.bones.values(): + if bone.name.lower() == 'root' and bone.parent is None: + root_bone = bone + break + for bone in data.bones.values(): if bone.name.startswith('ORG-'): orgbones[bone.name[4:]] = bone @@ -672,7 +680,20 @@ def derigifyBones(context, armature, scale): defnames.append(bone.name[4:]) defbones[bone.name[4:]] = bone defchildren[bone.name[4:]] = [] + + if root_bone: + root_name = root_bone.name + defnames.append(root_name) + defbones[root_name] = root_bone + defchildren[root_name] = [] + # Create a dummy org entry for the root bone + orgbones[root_name] = root_bone + org2defs[root_name] = [root_name] + def2org[root_name] = root_name + for name, bone in defbones.items(): + if root_bone and name == root_bone.name: + continue orgname = name orgbone = orgbones.get(orgname) splitname = -1 @@ -686,7 +707,11 @@ def derigifyBones(context, armature, scale): orgname = name[:splitname] + suffix orgbone = orgbones.get(orgname) org2defs[orgname].append(name) - def2org[name] = orgname + if root_bone and name == root_bone.name: + def2org[name] = root_name + else: + def2org[name] = orgname + for defs in org2defs.values(): defs.sort() for name in defnames: @@ -701,6 +726,8 @@ def derigifyBones(context, armature, scale): if orgparent and orgparent.name.startswith('ORG-'): orgpname = orgparent.name[4:] defparent[name] = org2defs[orgpname][-1] + elif orgparent and root_bone and orgparent == root_bone: + defparent[name] = root_bone.name else: defparent[name] = defs[i-1] if name in defparent: @@ -709,6 +736,12 @@ def derigifyBones(context, armature, scale): bones = {} worldmatrix = armature.matrix_world worklist = [ bone for bone in defnames if bone not in defparent ] + + # sort to ensure root is first + name = lambda b: b if isinstance(b, str) else getattr(b, "name", "") + root_name = root_bone.name if root_bone else None + worklist.sort(key=lambda b: (name(b) != "root" and name(b) != root_name, name(b))) + for index, bname in enumerate(worklist): bone = defbones[bname] bonematrix = worldmatrix @ bone.matrix_local @@ -724,7 +757,11 @@ def collectBones(context, armature, scale): data = armature.data bones = {} worldmatrix = armature.matrix_world - worklist = [ bone for bone in data.bones.values() if not bone.parent ] + # ensure root and deformed bones appear first + worklist = sorted( + (bone for bone in data.bones.values() if not bone.parent), + key=lambda b: (b.name != "root", b.use_deform == False, b.name) + ) for index, bone in enumerate(worklist): bonematrix = worldmatrix @ bone.matrix_local if scale != 1.0: From 4f66547bd8c0b203c2beae441308e9a489b0d041 Mon Sep 17 00:00:00 2001 From: bangbangsheshotmedown Date: Fri, 15 Aug 2025 12:23:50 +0200 Subject: [PATCH 2/2] Simplify sort --- blender-4.1/iqm_export.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/blender-4.1/iqm_export.py b/blender-4.1/iqm_export.py index f987478..6aba261 100644 --- a/blender-4.1/iqm_export.py +++ b/blender-4.1/iqm_export.py @@ -738,9 +738,7 @@ def derigifyBones(context, armature, scale): worklist = [ bone for bone in defnames if bone not in defparent ] # sort to ensure root is first - name = lambda b: b if isinstance(b, str) else getattr(b, "name", "") - root_name = root_bone.name if root_bone else None - worklist.sort(key=lambda b: (name(b) != "root" and name(b) != root_name, name(b))) + worklist.sort(key=lambda b: (b != "root", b)) for index, bname in enumerate(worklist): bone = defbones[bname]