From c6a75f25f843c5dab0e3c02fd6b9c58225d591e1 Mon Sep 17 00:00:00 2001 From: Pullusb Date: Mon, 11 Apr 2022 11:41:56 +0200 Subject: [PATCH] improved ui and poll handling 0.6.0 - World paste and `Jump next frame` - more compact and improved ui for world paste - fix errors in some operators --- OP_animate_path.py | 3 +-- OP_setup_curve_path.py | 5 +++-- OP_snap_contact.py | 7 +++++++ OP_world_copy_paste.py | 33 +++++++++++++++++++++++++++++++++ README.md | 7 +++++++ __init__.py | 2 +- fn.py | 1 + panels.py | 31 +++++++++++++++++++++++++------ properties.py | 2 +- 9 files changed, 79 insertions(+), 12 deletions(-) diff --git a/OP_animate_path.py b/OP_animate_path.py index 288c856..e81851f 100644 --- a/OP_animate_path.py +++ b/OP_animate_path.py @@ -32,8 +32,6 @@ def anim_path_from_translate(): print(fn.helper()) ob = bpy.context.object - if ob.type != 'ARMATURE': - return ('ERROR', 'active is not an armature type') # found curve through constraint b = bpy.context.active_pose_bone @@ -216,6 +214,7 @@ class UAC_OT_animate_path(bpy.types.Operator): def execute(self, context): # TODO clear previous animation (keys) if there is any + err = anim_path_from_translate() if err: self.report({err[0]}, err[1]) diff --git a/OP_setup_curve_path.py b/OP_setup_curve_path.py index 171962a..87ae0a1 100644 --- a/OP_setup_curve_path.py +++ b/OP_setup_curve_path.py @@ -159,12 +159,13 @@ class UAC_OT_create_curve_path(bpy.types.Operator): class UAC_OT_create_follow_path(bpy.types.Operator): bl_idname = "anim.create_follow_path" bl_label = "Create Follow Path Constraint" - bl_description = "Create follow path targeting curve in field" + bl_description = "Create follow path targeting curve chosen in dedicated field" bl_options = {"REGISTER", "UNDO"} @classmethod def poll(cls, context): - return context.object and context.object.type == 'ARMATURE' + return context.object and context.object.type == 'ARMATURE' \ + and context.scene.anim_cycle_settings.path_to_follow def execute(self, context): ob = context.object diff --git a/OP_snap_contact.py b/OP_snap_contact.py index 602af05..6f3c71d 100644 --- a/OP_snap_contact.py +++ b/OP_snap_contact.py @@ -248,6 +248,13 @@ class UAC_OT_contact_to_ground(bpy.types.Operator): return context.object and context.object.type == 'ARMATURE' def execute(self, context): + # TODO: check if possible to auto detect a ground when gnd is not specified + # (still instersteing to be able to get the ground user wants) + + if not context.scene.anim_cycle_settings.gnd: + self.report({'ERROR'}, 'need to choose a target mesh for "Ground"') + return {"CANCELLED"} + # context.scene.anim_cycle_settings.expand_on_selected_bones err = snap_feet() if err: diff --git a/OP_world_copy_paste.py b/OP_world_copy_paste.py index 993279d..bec5a25 100644 --- a/OP_world_copy_paste.py +++ b/OP_world_copy_paste.py @@ -85,11 +85,44 @@ class UAC_OT_world_space_paste_next(bpy.types.Operator): context.scene.frame_current = new_frame return {"FINISHED"} +class UAC_OT_world_space_paste_next_frame(bpy.types.Operator): + bl_idname = "anim.world_space_paste_next_frame" + bl_label = "World Paste Jump Frame" + bl_description = "Paste world space transforms and keyframe available chanels\nThen jump to prev/next frame" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return context.object and context.mode == 'POSE' and context.active_pose_bone + + prev: bpy.props.BoolProperty() + + def execute(self, context): + # apply matrix + context.active_pose_bone.matrix = context.object.matrix_world.inverted() @ bpy.context.view_layer.world_space_store + + # insert keyframe at value + # context.object.keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, group="", options={'INSERTKEY_AVAILABLE'}) + bpy.ops.anim.keyframe_insert_menu(type='Available') + + # jump to next frame + act = fn.get_obj_action(context.object) + if not act: + self.report({'ERROR'}, 'No action on armature') + return {'CANCELLED'} + + offset = -1 if self.prev else 1 + new_frame = context.scene.frame_current + offset + + context.scene.frame_current = new_frame + return {"FINISHED"} + classes=( UAC_OT_world_space_copy, UAC_OT_world_space_paste, UAC_OT_world_space_paste_next, +UAC_OT_world_space_paste_next_frame, ) def register(): diff --git a/README.md b/README.md index d4c852b..8f4b73e 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,13 @@ Bonus: ## Changelog: + +0.6.0 + +- World paste and `Jump next frame` +- more compact and improved ui for world paste +- fix errors in some operators + 0.5.0 - pin feet working diff --git a/__init__.py b/__init__.py index 9de9199..cc7831e 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ bl_info = { "name": "Unfold Anim Cycle", "description": "Anim tools to develop walk/run cycles along a curve", "author": "Samuel Bernou", - "version": (0, 5, 0), + "version": (0, 6, 0), "blender": (3, 0, 0), "location": "View3D", "warning": "WIP", diff --git a/fn.py b/fn.py index 0e6faad..65d219c 100644 --- a/fn.py +++ b/fn.py @@ -59,6 +59,7 @@ def get_follow_curve_from_armature(arm): name = get_root_name() parents = [] + const = False # root = b.id_data.pose.bones.get(name) root = arm.pose.bones.get(name) for c in root.constraints: diff --git a/panels.py b/panels.py index 180d879..4da9c01 100644 --- a/panels.py +++ b/panels.py @@ -13,8 +13,12 @@ class UAC_PT_walk_cycle_anim_panel(bpy.types.Panel): # need to know root orientation forward) ## know direction to evaluate feet moves ## Define Constraint axis (depend on root orientation) - layout.prop(settings, "forward_axis") - layout.operator("uac.autoset_axis", text='Auto-Set Axis') + + # layout.prop(settings, "forward_axis") # plain prop + row = layout.row() + row.label(text='Forward Axis') + row.prop(settings, "forward_axis", text='') + layout.operator("uac.autoset_axis", text='Auto-Set Axis') box = layout.box() if not settings.path_to_follow: @@ -81,10 +85,25 @@ class UAC_PT_anim_tools_panel(bpy.types.Panel): layout.operator('anim.contact_to_ground', text='Ground selected feet', icon='SNAP_OFF') row = layout.row() row.operator('anim.world_space_copy', text='Copy Pose', icon='COPYDOWN') - row.operator('anim.world_space_paste', text='Paste', icon='PASTEDOWN') - row = layout.row() - row.operator('anim.world_space_paste_next', text='Paste Prev', icon='PASTEDOWN').prev = True - row.operator('anim.world_space_paste_next', text='Paste Next', icon='PASTEDOWN').prev = False + # row.operator('anim.world_space_paste', text='Paste', icon='PASTEDOWN') + # row = layout.row(align=False) + + ## multi buttons + # row.label(text='Paste and jump:') + # row = layout.row(align=True) + # row.operator('anim.world_space_paste_next', text='Prev key', icon='PREV_KEYFRAME').prev = True # Paste Prev key + # row.operator('anim.world_space_paste_next', text='Next key', icon='NEXT_KEYFRAME').prev = False # Paste Next key + # row = layout.row(align=True) + # row.operator('anim.world_space_paste_next_frame', text='Prev frame', icon='FRAME_PREV').prev = True # Paste Prev frame + # row.operator('anim.world_space_paste_next_frame', text='Next frame', icon='FRAME_NEXT').prev = False # Paste Next frame + + row = layout.row(align=True) + row.operator('anim.world_space_paste_next_frame', text='', icon='FRAME_PREV').prev = True + row.operator('anim.world_space_paste_next', text='', icon='PREV_KEYFRAME').prev = True + row.operator('anim.world_space_paste', text='', icon='PASTEDOWN') + row.operator('anim.world_space_paste_next', text='', icon='NEXT_KEYFRAME').prev = False + row.operator('anim.world_space_paste_next_frame', text='', icon='FRAME_NEXT').prev = False + row.scale_x = 2 diff --git a/properties.py b/properties.py index bde76fe..b975242 100644 --- a/properties.py +++ b/properties.py @@ -31,7 +31,7 @@ class UAC_PG_settings(bpy.types.PropertyGroup) : forward_axis : bpy.props.EnumProperty( name='Forward Axis', - default='TRACK_NEGATIVE_Y', # Modifier default is FORWARD_X + default='FORWARD_Z', # Modifier default is FORWARD_X (should be TRACK_NEGATIVE_Y for a good rig) description='Local axis of the "root" bone that point forward', items=( ('FORWARD_X', 'X', ''),