diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-04-01 13:29:35 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-04-01 13:29:35 +0400 |
commit | a6f02e27d8047f4b1322093ce920b6e033626987 (patch) | |
tree | 955727112d8c5f2d44d6302722dd77c8e967718b /release | |
parent | 4a471a3a98dd66cf4d7aebeee9361dad83e8eff1 (diff) |
missed in merging from render branch
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/op/nla.py | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/release/scripts/op/nla.py b/release/scripts/op/nla.py new file mode 100644 index 00000000000..99f5ec5cca9 --- /dev/null +++ b/release/scripts/op/nla.py @@ -0,0 +1,204 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +import bpy + +def pose_info(): + from Mathutils import Matrix + + info = {} + + obj = bpy.context.object + pose = obj.pose + + pose_items = pose.bones.items() + + for name, pbone in pose_items: + binfo = {} + bone = pbone.bone + + binfo["parent"] = getattr(bone.parent, "name", None) + binfo["bone"] = bone + binfo["pbone"] = pbone + binfo["matrix_local"] = bone.matrix_local.copy() + try: + binfo["matrix_local_inv"] = binfo["matrix_local"].copy().invert() + except: + binfo["matrix_local_inv"] = Matrix() + + binfo["matrix"] = bone.matrix.copy() + binfo["matrix_pose"] = pbone.matrix.copy() + try: + binfo["matrix_pose_inv"] = binfo["matrix_pose"].copy().invert() + except: + binfo["matrix_pose_inv"] = Matrix() + + print(binfo["matrix_pose"]) + info[name] = binfo + + for name, pbone in pose_items: + binfo = info[name] + binfo_parent = binfo.get("parent", None) + if binfo_parent: + binfo_parent = info[binfo_parent] + + matrix = binfo["matrix_pose"] + rest_matrix = binfo["matrix_local"] + + if binfo_parent: + matrix= binfo_parent["matrix_pose_inv"] * matrix + rest_matrix= binfo_parent["matrix_local_inv"] * rest_matrix + + matrix = rest_matrix.copy().invert() * matrix + + binfo["matrix_key"] = matrix.copy() + + return info + + +def bake(start_frame, end_frame, step=1, only_selected=False): + # import nla; reload(nla); nla.bake() + + scene = bpy.context.scene + obj = bpy.context.object + pose = obj.pose + + info_ls = [] + + frame_range = range(start_frame, end_frame + 1, step) + + # could spped this up by applying steps here too... + for f in frame_range: + scene.set_frame(f) + + info = pose_info() + info_ls.append(info) + f += 1 + + action = bpy.data.actions.new("Action") + + bpy.context.object.animation_data.action = action + + pose_items = pose.bones.items() + + for name, pbone in pose_items: + if only_selected and not pbone.selected: + continue + + for f in frame_range: + matrix = info_ls[int((f-start_frame) / step)][name]["matrix_key"] + + #pbone.location = matrix.translation_part() + #pbone.rotation_quaternion = matrix.to_quat() + pbone.matrix_local = [f for v in matrix for f in v] + + pbone.keyframe_insert("location", -1, f) + + rotation_mode = pbone.rotation_mode + + if rotation_mode == 'QUATERNION': + pbone.keyframe_insert("rotation_quaternion", -1, f) + elif rotation_mode == 'AXIS_ANGLE': + pbone.keyframe_insert("rotation_axis_angle", -1, f) + else: # euler, XYZ, ZXY etc + pbone.keyframe_insert("rotation_euler", -1, f) + + pbone.keyframe_insert("scale", -1, f) + + # assign groups, could become a more generic function + agrp_loc = action.groups.add("Location") + agrp_rot = action.groups.add("Rotation") + agrp_sca = action.groups.add("Scale") + + for fcu in action.fcurves: + path = fcu.data_path.rsplit(".", 1)[-1] + + if path.startswith("loc"): + fcu.group = agrp_loc + if path.startswith("rot"): + fcu.group = agrp_rot + if path.startswith("sca"): + fcu.group = agrp_sca + + return action + + +from bpy.props import * + + +class BakeAction(bpy.types.Operator): + '''Add a torus mesh''' + bl_idname = "nla.bake" + bl_label = "Bake Action" + bl_options = {'REGISTER', 'UNDO'} + + start_frame = IntProperty(name="Start Frame", + description="Start frame for baking", + default=1, min=1, max=300000) + end_frame = IntProperty(name="End Frame", + description="End frame for baking", + default=250, min=1, max=300000) + step = IntProperty(name="Frame Step", + description="Frame Step", + default=1, min=1, max=120) + only_selected = BoolProperty(name="Only Selected", + default=True) + + def execute(self, context): + props = self.properties + + action = bake(props.start_frame, props.end_frame, props.step, props.only_selected) + + # basic cleanup, could move elsewhere + for fcu in action.fcurves: + keyframe_points = fcu.keyframe_points + i = 1 + while i < len(fcu.keyframe_points) - 1: + val_prev = keyframe_points[i - 1].co[1] + val_next = keyframe_points[i + 1].co[1] + val = keyframe_points[i].co[1] + + if abs(val - val_prev) + abs(val - val_next) < 0.0001: + keyframe_points.remove(keyframe_points[i]) + else: + i += 1 + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.manager + return wm.invoke_props_dialog(self) + + +#def menu_func(self, context): +# self.layout.operator(BakeAction.bl_idname, text="Bake Armature Action") + + +def register(): + bpy.types.register(BakeAction) + # bpy.types.INFO_MT_mesh_add.append(menu_func) + + +def unregister(): + bpy.types.unregister(BakeAction) + # bpy.types.INFO_MT_mesh_add.remove(menu_func) + +if __name__ == "__main__": + register()
\ No newline at end of file |