Rotate a particular bone in edit mode without offsetting animation? I have an armature of animated bones and I want to rotate the main bone by 90 degrees in edit mode so that that particular bone has the right orientation when exporting the animation for the source engine (I accidentally animated it with the wrong rotation).

My animations are already finished, so when I rotate the bone in edit mode now it messes up the animation. (The bone is moved away from its original position and moves in the wrong direction during the animation.)

How do I fix this?

This is what the problem looks like:


Here's one of the .blend files (not rotated): idle.blend
Here's a function I wrote that lets you rotate a bone in edit mode and automatically corrects all animations so they maintain the same orientation:

def reorient_bone(operator, context, fixed_items, layers=(), bone_name="Bip0", location=mathutils.Vector((0,0,1)), rotation=mathutils.Euler((0,0,1)) ):
    qrn = rotation.to_quaternion().conjugated()
    qe = rotation.to_quaternion()
    #when no object exists, or when we are in edit mode when script is run
    for ob in bpy.context.scene.objects:
        if type(ob.data) ==  bpy.types.Armature:
            bpy.context.scene.objects.active = ob
            bpy.ops.object.mode_set(mode='EDIT')
            for bone in ob.data.edit_bones:
                if bone.name == bone_name:
                    l =  mathutils.Vector(bone.head)
                    m =  rotation.to_matrix() * bone.matrix.to_3x3()
                    bone.head = mathutils.Vector((0,0,0))
                    bone.tail = mathutils.Vector((0,1,0))
                    bone.roll = 0
                    bone.transform(m)
                    bone.translate(l)
            bpy.ops.object.mode_set(mode='POSE')

    for action in bpy.data.actions:
        for group in action.groups:
            if group.name == bone_name:
                #rotate the translation so the movement of the bone remains identical
                for t in ("location", "quaternion"):
                    curves = [fcurve for fcurve in group.channels if fcurve.data_path.endswith(t)]
                    if curves:
                        num_keys = len(curves[0].keyframe_points)
                        for i in range(0, num_keys):
                            frame = curves[0].keyframe_points[i].co[0]
                            key = [fcurve.keyframe_points[i].co[1] for fcurve in curves]
                            if len(curves) == 3:
                                key =  qrn * mathutils.Vector(key)
                            else:
                                #arbitrary rotations keeping the worldspace character of the rotation
                                if fixed_items == "0":
                                    q = mathutils.Quaternion(key)
                                    v, a = q.to_axis_angle()
                                    v =  qrn * mathutils.Vector(v)
                                    key = mathutils.Quaternion(v, a)

                                #for the other case - restore rotation around rest bone change
                                if fixed_items == "1":
                                    key = mathutils.Quaternion(key) * qe
                            for a in range(0,len(curves)):
                                curves[a].keyframe_points[i].co[1] = key[a]
                        for fcurve in curves:   
                            fcurve.update()
    #call the tangent function
    loop_fcurve_tangents()
    return {'FINISHED'}