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 operatorsmaster
parent
3c5ccf422a
commit
c6a75f25f8
|
@ -32,8 +32,6 @@ def anim_path_from_translate():
|
||||||
print(fn.helper())
|
print(fn.helper())
|
||||||
|
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
if ob.type != 'ARMATURE':
|
|
||||||
return ('ERROR', 'active is not an armature type')
|
|
||||||
|
|
||||||
# found curve through constraint
|
# found curve through constraint
|
||||||
b = bpy.context.active_pose_bone
|
b = bpy.context.active_pose_bone
|
||||||
|
@ -216,6 +214,7 @@ class UAC_OT_animate_path(bpy.types.Operator):
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
# TODO clear previous animation (keys) if there is any
|
# TODO clear previous animation (keys) if there is any
|
||||||
|
|
||||||
err = anim_path_from_translate()
|
err = anim_path_from_translate()
|
||||||
if err:
|
if err:
|
||||||
self.report({err[0]}, err[1])
|
self.report({err[0]}, err[1])
|
||||||
|
|
|
@ -159,12 +159,13 @@ class UAC_OT_create_curve_path(bpy.types.Operator):
|
||||||
class UAC_OT_create_follow_path(bpy.types.Operator):
|
class UAC_OT_create_follow_path(bpy.types.Operator):
|
||||||
bl_idname = "anim.create_follow_path"
|
bl_idname = "anim.create_follow_path"
|
||||||
bl_label = "Create Follow Path Constraint"
|
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"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
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):
|
def execute(self, context):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
|
|
|
@ -248,6 +248,13 @@ class UAC_OT_contact_to_ground(bpy.types.Operator):
|
||||||
return context.object and context.object.type == 'ARMATURE'
|
return context.object and context.object.type == 'ARMATURE'
|
||||||
|
|
||||||
def execute(self, context):
|
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
|
# context.scene.anim_cycle_settings.expand_on_selected_bones
|
||||||
err = snap_feet()
|
err = snap_feet()
|
||||||
if err:
|
if err:
|
||||||
|
|
|
@ -85,11 +85,44 @@ class UAC_OT_world_space_paste_next(bpy.types.Operator):
|
||||||
context.scene.frame_current = new_frame
|
context.scene.frame_current = new_frame
|
||||||
return {"FINISHED"}
|
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=(
|
classes=(
|
||||||
UAC_OT_world_space_copy,
|
UAC_OT_world_space_copy,
|
||||||
UAC_OT_world_space_paste,
|
UAC_OT_world_space_paste,
|
||||||
UAC_OT_world_space_paste_next,
|
UAC_OT_world_space_paste_next,
|
||||||
|
UAC_OT_world_space_paste_next_frame,
|
||||||
)
|
)
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
|
|
@ -56,6 +56,13 @@ Bonus:
|
||||||
|
|
||||||
## Changelog:
|
## 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
|
0.5.0
|
||||||
|
|
||||||
- pin feet working
|
- pin feet working
|
||||||
|
|
|
@ -2,7 +2,7 @@ bl_info = {
|
||||||
"name": "Unfold Anim Cycle",
|
"name": "Unfold Anim Cycle",
|
||||||
"description": "Anim tools to develop walk/run cycles along a curve",
|
"description": "Anim tools to develop walk/run cycles along a curve",
|
||||||
"author": "Samuel Bernou",
|
"author": "Samuel Bernou",
|
||||||
"version": (0, 5, 0),
|
"version": (0, 6, 0),
|
||||||
"blender": (3, 0, 0),
|
"blender": (3, 0, 0),
|
||||||
"location": "View3D",
|
"location": "View3D",
|
||||||
"warning": "WIP",
|
"warning": "WIP",
|
||||||
|
|
1
fn.py
1
fn.py
|
@ -59,6 +59,7 @@ def get_follow_curve_from_armature(arm):
|
||||||
name = get_root_name()
|
name = get_root_name()
|
||||||
|
|
||||||
parents = []
|
parents = []
|
||||||
|
const = False
|
||||||
# root = b.id_data.pose.bones.get(name)
|
# root = b.id_data.pose.bones.get(name)
|
||||||
root = arm.pose.bones.get(name)
|
root = arm.pose.bones.get(name)
|
||||||
for c in root.constraints:
|
for c in root.constraints:
|
||||||
|
|
29
panels.py
29
panels.py
|
@ -13,7 +13,11 @@ class UAC_PT_walk_cycle_anim_panel(bpy.types.Panel):
|
||||||
# need to know root orientation forward)
|
# need to know root orientation forward)
|
||||||
## know direction to evaluate feet moves
|
## know direction to evaluate feet moves
|
||||||
## Define Constraint axis (depend on root orientation)
|
## Define Constraint axis (depend on root orientation)
|
||||||
layout.prop(settings, "forward_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')
|
layout.operator("uac.autoset_axis", text='Auto-Set Axis')
|
||||||
|
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
|
@ -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')
|
layout.operator('anim.contact_to_ground', text='Ground selected feet', icon='SNAP_OFF')
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator('anim.world_space_copy', text='Copy Pose', icon='COPYDOWN')
|
row.operator('anim.world_space_copy', text='Copy Pose', icon='COPYDOWN')
|
||||||
row.operator('anim.world_space_paste', text='Paste', icon='PASTEDOWN')
|
# row.operator('anim.world_space_paste', text='Paste', icon='PASTEDOWN')
|
||||||
row = layout.row()
|
# row = layout.row(align=False)
|
||||||
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
|
## 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class UAC_PG_settings(bpy.types.PropertyGroup) :
|
||||||
|
|
||||||
forward_axis : bpy.props.EnumProperty(
|
forward_axis : bpy.props.EnumProperty(
|
||||||
name='Forward Axis',
|
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',
|
description='Local axis of the "root" bone that point forward',
|
||||||
items=(
|
items=(
|
||||||
('FORWARD_X', 'X', ''),
|
('FORWARD_X', 'X', ''),
|
||||||
|
|
Loading…
Reference in New Issue