def simbone_bake(ob, pose_bone, edit_bone, scene):
    frames, frame_step = get_scene_frames(scene)

    matrices = get_matrices(ob, pose_bone, edit_bone, frames)
    end_mats = get_matrices_single_bone(ob, pose_bone, edit_bone, frames)

    # Main lists.
    positions = [
        mat.decompose()[0] * scene.simboneworld.spaceScale for mat in matrices
    ]
    orientations = [(matrices[i] @ end_mats[i].inverted()).decompose()[1]
                    for i in range(len(end_mats))]

    velocities = [(positions[i] - positions[max(0, i - 1)]) / frame_step
                  for i in range(len(positions))]
    accelerations = [(velocities[i] - velocities[max(0, i - 1)]) / frame_step
                     for i in range(len(velocities))]

    gravity = get_gravity(scene)
    custom_force = pose_bone.simbone.custom_force.copy()
    up_quat = Euler((pose_bone.simbone.up_offset - 90, 0, 0)).to_quaternion()
    start_dir = bone_quat_to_dir(matrices[0].decompose()[1])

    # Setup pendulum values.
    pen = Pendulum()
    pen.l = edit_bone.length * scene.simboneworld.spaceScale
    pen.m = pose_bone.simbone.m
    pen.set_coords(start_dir)
    pen.c_a = pose_bone.simbone.c_a
    pen.c_d = pose_bone.simbone.c_d

    datapath = 'pose.bones["' + pose_bone.name + '"].rotation_quaternion'
    pose_bone.rotation_mode = 'QUATERNION'
    pose_bone.rotation_quaternion = end_mats[0].decompose()[1]
    pose_bone.keyframe_insert(data_path='rotation_quaternion', frame=frames[0])
    fcurves = [
        ob.animation_data.action.fcurves.find(datapath, index=i)
        for i in range(4)
    ]

    for i in range(1, len(matrices)):
        matrix = matrices[i]
        frame = frames[i]
        g = gravity.copy()
        f = custom_force.copy()
        f.rotate(orientations[i])

        pen.w = scene.simboneworld.wind - velocities[i]
        pen.f = g + f - accelerations[i]

        pen.do_steps(frame_step * scene.simboneworld.timeScale, 1)
        direction = Vector(pen.get_coords())

        direction.rotate(orientations[i].inverted())
        direction.rotate(up_quat.inverted())
        orient = direction.to_track_quat('Y', 'Z')
        orient.rotate(up_quat)

        for i in range(4):
            fcurves[i].keyframe_points.insert(frame, orient[i])
Example #2
0
    def execute(self, context):
        # Cursor matrix
        cmat = self.cmat.copy()

        # Local rotation matrix
        mat = Euler((radians(angle) for angle in self.xyz)).to_matrix()

        # Multiply with inverse local rotation matrix
        new_mat = cmat @ mat.inverted()

        context.scene.cursor.rotation_quaternion = new_mat.to_quaternion()
        return {'FINISHED'}
Example #3
0
def apply_animation(bones, arm_obj, jntframes, name=None):
    """apply keyframes from pseudobones to real, armature bones"""
    if name:
        arm_obj.animation_data.action = bpy.data.actions.new(name + '_action')
    else:
        arm_obj.animation_data.action = bpy.data.actions.new(arm_obj.name+'_action')
    bpy.context.scene.frame_current = 0

    # warning: here, the `name` var changes meaning

    for com in bones:
        name = com.name.fget()
        arm_obj.data.bones[name].use_inherit_scale = False  # scale can be applied
        posebone = arm_obj.pose.bones[name]
        posebone.rotation_mode = "XZY"  # remember, coords are flipped
        bpy.context.scene.frame_current = 0
        # this keyframe is needed, overwritten anyways
        # also it is always at 1 because this function is called once per action
        posebone.keyframe_insert('location')
        posebone.keyframe_insert('rotation_euler')
        posebone.keyframe_insert('scale')
    fcurves = arm_obj.animation_data.action.fcurves
    data = {}

    for curve in fcurves:
        # create data in dicts ({bonename:{datatype:[0,1,2]...}...})
        try:
            bonename, datatype = finder.match(curve.data_path).groups()
        except TypeError:  # cannit unpack None: this fsurve is not interesting
            continue
        bonedict = common.dict_get_set(data, bonename, {})
        datadict = common.dict_get_set(bonedict, datatype, [None, None, None])
        datadict[curve.array_index] = curve

    # create keyframes, with tengents
    for com in bones:
        name = com.name.fget()
        bonedict = data[name]
        posebone = arm_obj.pose.bones[name]
        bpy.context.scene.frame_current = 0
        posebone.keyframe_insert('location')
        posebone.keyframe_insert('rotation_euler')
        posebone.keyframe_insert('scale')
        every_frame = list(com.frames.times.keys())
        every_frame.sort()
        refpos = com.jnt_frame
        if type(com.parent.fget()) is not Pseudobone:
            com.rotmatrix = Matrix.Identity(4)
            com.parentrot = Matrix.Identity(4)
        else:
            com.rotmatrix = com.parent.fget().rotmatrix
            com.parentrot = com.parent.fget().rotmatrix
        tempmat = Euler((refpos.rx, refpos.ry, refpos.rz), 'XYZ').to_matrix().to_4x4()
        com.rotmatrix *= tempmat
        cancel_ref_rot = tempmat.inverted()
        for frame in every_frame:
            bpy.context.scene.frame_current = frame
            # flip y and z
            if com.frames.times[frame][0]:
                vct, tgL, tgR = get_pos_vct(com, frame)
                if not math.isnan(vct.x):
                    posebone.location[0] = vct.x
                    co = bonedict['location'][0].keyframe_points[-1].co
                    bonedict['location'][0].keyframe_points[-1].handle_left = co+Vector((-1, -tgL.x))
                    bonedict['location'][0].keyframe_points[-1].handle_right = co+Vector((1, tgR.x))
                    posebone.keyframe_insert('location', 0)
                    # fixed: add frame to keyframes AFTER setting the right value to it. so conter-intuitive.
                if not math.isnan(vct.z):
                    posebone.location[1] = -vct.z
                    co = bonedict['location'][1].keyframe_points[-1].co
                    bonedict['location'][1].keyframe_points[-1].handle_left = co + Vector((-1, tgL.z))
                    bonedict['location'][1].keyframe_points[-1].handle_right = co + Vector((1, -tgR.z))
                    posebone.keyframe_insert('location', 1)
                if not math.isnan(vct.y):
                    posebone.location[2] = vct.y
                    co = bonedict['location'][2].keyframe_points[-1].co
                    bonedict['location'][2].keyframe_points[-1].handle_left = co + Vector((-1, -tgL.y))
                    bonedict['location'][2].keyframe_points[-1].handle_right = co + Vector((1, tgR.y))
                    posebone.keyframe_insert('location', 2)

            if com.frames.times[frame][1]:
                vct, tgL, tgR = get_rot_vct(com, frame)
                if not math.isnan(vct.x):
                    posebone.rotation_euler[0] = vct.x
                    co = bonedict['rotation_euler'][0].keyframe_points[-1].co
                    bonedict['rotation_euler'][0].keyframe_points[-1].handle_left = co + Vector((-1, -tgL.x))
                    bonedict['rotation_euler'][0].keyframe_points[-1].handle_right = co + Vector((1, tgR.x))
                    posebone.keyframe_insert('rotation_euler', 0)
                if not math.isnan(vct.z):
                    posebone.rotation_euler[1] = -vct.z
                    co = bonedict['rotation_euler'][1].keyframe_points[-1].co
                    bonedict['rotation_euler'][1].keyframe_points[-1].handle_left = co + Vector((-1, tgL.z))
                    bonedict['rotation_euler'][1].keyframe_points[-1].handle_right = co + Vector((1, -tgR.z))
                    posebone.keyframe_insert('rotation_euler', 1)
                if not math.isnan(vct.y):
                    posebone.rotation_euler[2] = vct.y
                    co = bonedict['rotation_euler'][2].keyframe_points[-1].co
                    bonedict['rotation_euler'][2].keyframe_points[-1].handle_left = co + Vector((-1, -tgL.y))
                    bonedict['rotation_euler'][2].keyframe_points[-1].handle_right = co + Vector((1, tgR.y))
                    posebone.keyframe_insert('rotation_euler', 2)

            if com.frames.times[frame][2]:
                vct, tgL, tgR = get_sc_vct(com, frame)
                if not math.isnan(vct.x):
                    posebone.scale[0] = vct.x
                    co = bonedict['scale'][0].keyframe_points[-1].co
                    bonedict['scale'][0].keyframe_points[-1].handle_left = co + Vector((-1, -tgL.x))
                    bonedict['scale'][0].keyframe_points[-1].handle_right = co + Vector((1, tgR.x))
                    posebone.keyframe_insert('scale', 0)
                if not math.isnan(vct.z):
                    posebone.scale[1] = vct.z
                    co = bonedict['scale'][1].keyframe_points[-1].co
                    bonedict['scale'][1].keyframe_points[-1].handle_left = co + Vector((-1, tgL.z))
                    bonedict['scale'][1].keyframe_points[-1].handle_right = co + Vector((1, -tgR.z))
                    posebone.keyframe_insert('scale', 1)
                if not math.isnan(vct.y):
                    posebone.scale[2] = vct.y
                    co = bonedict['scale'][2].keyframe_points[-1].co
                    bonedict['scale'][2].keyframe_points[-1].handle_left = co + Vector((-1, -tgL.y))
                    bonedict['scale'][2].keyframe_points[-1].handle_right = co + Vector((1, tgR.y))
                    posebone.keyframe_insert('scale', 2)

    return arm_obj.animation_data.action