no need for cycle and better snap curve
1.5.0 - changed: no need to have a cycle on fcurve to bake keys anymore - changed: snap curve does not create a curve copy - added: allow to directly snap selected curve (`ctrl + Click` to keep shrinkwarp modfifier, need to apply to affect object) - fixed: error when going in curve edit from object mode
This commit is contained in:
		
							parent
							
								
									578e0d7266
								
							
						
					
					
						commit
						c98bb520b8
					
				@ -1,5 +1,12 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1.5.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- changed: no need to have a cycle on fcurve to bake keys anymore
 | 
				
			||||||
 | 
					- changed: snap curve does not create a curve copy
 | 
				
			||||||
 | 
					- added: allow to directly snap selected curve (`ctrl + Click` to keep shrinkwarp modfifier, need to apply to affect object)
 | 
				
			||||||
 | 
					- fixed: error when going in curve edit from object mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1.4.4
 | 
					1.4.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- changed: default start to 100
 | 
					- changed: default start to 100
 | 
				
			||||||
 | 
				
			|||||||
@ -36,22 +36,18 @@ def bake_cycle(on_selection=True, end=None):
 | 
				
			|||||||
    last = max(all_keys) # int(max(all_keys))
 | 
					    last = max(all_keys) # int(max(all_keys))
 | 
				
			||||||
    offset = last - first
 | 
					    offset = last - first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for fcu in act.fcurves:
 | 
					    for fcu in fn.get_only_pose_keyable_fcurves(obj, action=act):
 | 
				
			||||||
 | 
					        #-# old -- filter only on fcurve that have a cycle modifier (maybe as an option)
 | 
				
			||||||
 | 
					        # if not [m for m in fcu.modifiers if m.type == 'CYCLES']:
 | 
				
			||||||
 | 
					        #     ct_no_cycle += 1
 | 
				
			||||||
 | 
					        #     continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ## if a curve is not cycled don't touch
 | 
					 | 
				
			||||||
        if not [m for m in fcu.modifiers if m.type == 'CYCLES']:
 | 
					 | 
				
			||||||
            ct_no_cycle += 1
 | 
					 | 
				
			||||||
            continue
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if debug: print(fcu.data_path, 'has cycle')
 | 
					 | 
				
			||||||
        #-# only on location :
 | 
					        #-# only on location :
 | 
				
			||||||
        # if not fcu.data_path.endswith('.location'):
 | 
					        # if not fcu.data_path.endswith('.location'):
 | 
				
			||||||
        #     continue
 | 
					        #     continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # prop = fcu.data_path.split('.')[-1]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        b_name = fcu.data_path.split('"')[1]
 | 
					        b_name = fcu.data_path.split('"')[1]
 | 
				
			||||||
        if debug: print(b_name, 'has cycle')
 | 
					
 | 
				
			||||||
        pb = obj.pose.bones.get(b_name)
 | 
					        pb = obj.pose.bones.get(b_name)
 | 
				
			||||||
        if not pb:
 | 
					        if not pb:
 | 
				
			||||||
            print(f'{b_name} is invalid')
 | 
					            print(f'{b_name} is invalid')
 | 
				
			||||||
 | 
				
			|||||||
@ -104,7 +104,7 @@ class AW_OT_remove_follow_path(bpy.types.Operator):
 | 
				
			|||||||
class AW_OT_snap_curve_to_ground(bpy.types.Operator):
 | 
					class AW_OT_snap_curve_to_ground(bpy.types.Operator):
 | 
				
			||||||
    bl_idname = "autowalk.snap_curve_to_ground"
 | 
					    bl_idname = "autowalk.snap_curve_to_ground"
 | 
				
			||||||
    bl_label = "Snap Curve"
 | 
					    bl_label = "Snap Curve"
 | 
				
			||||||
    bl_description = "snap curve to ground determine in field"
 | 
					    bl_description = "Snap curve to ground determine in field"
 | 
				
			||||||
    bl_options = {"REGISTER", "UNDO"}
 | 
					    bl_options = {"REGISTER", "UNDO"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
@ -119,6 +119,34 @@ class AW_OT_snap_curve_to_ground(bpy.types.Operator):
 | 
				
			|||||||
                return {"CANCELLED"}
 | 
					                return {"CANCELLED"}
 | 
				
			||||||
        return {"FINISHED"}
 | 
					        return {"FINISHED"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AW_OT_snap_selected_curve(bpy.types.Operator):
 | 
				
			||||||
 | 
					    bl_idname = "autowalk.snap_selected_curve"
 | 
				
			||||||
 | 
					    bl_label = "Snap Selected Curve"
 | 
				
			||||||
 | 
					    bl_description = "Snap selected curve to ground\
 | 
				
			||||||
 | 
					        \nCtrl + Click : Not apply Shrinkwarp modifier (Apply manually)"
 | 
				
			||||||
 | 
					    bl_options = {"REGISTER", "UNDO"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def poll(cls, context):
 | 
				
			||||||
 | 
					        return context.object and context.object.type == 'CURVE'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def invoke(self, context, event):
 | 
				
			||||||
 | 
					        self.apply = not event.ctrl # don't apply if ctrl is pressd
 | 
				
			||||||
 | 
					        return self.execute(context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self, context):
 | 
				
			||||||
 | 
					        ob = context.object
 | 
				
			||||||
 | 
					        # bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
 | 
				
			||||||
 | 
					        ground = fn.get_gnd()
 | 
				
			||||||
 | 
					        if not ground:
 | 
				
			||||||
 | 
					            self.report({'ERROR'}, 'Need to specify ground (in curve options) or name an object in scene "Ground"')
 | 
				
			||||||
 | 
					            return {"CANCELLED"}
 | 
				
			||||||
 | 
					        fn.shrinkwrap_on_object(ob, ground, apply=self.apply)
 | 
				
			||||||
 | 
					        if self.apply:
 | 
				
			||||||
 | 
					            self.report({'INFO'}, 'ShrinkWrap Modifier need to be applyed manually')
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        return {"FINISHED"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AW_OT_edit_curve(bpy.types.Operator):
 | 
					class AW_OT_edit_curve(bpy.types.Operator):
 | 
				
			||||||
    bl_idname = "autowalk.edit_curve"
 | 
					    bl_idname = "autowalk.edit_curve"
 | 
				
			||||||
    bl_label = "Edit Curve"
 | 
					    bl_label = "Edit Curve"
 | 
				
			||||||
@ -130,6 +158,7 @@ class AW_OT_edit_curve(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):
 | 
				
			||||||
 | 
					        ob = context.object
 | 
				
			||||||
        b = context.active_pose_bone
 | 
					        b = context.active_pose_bone
 | 
				
			||||||
        curve = None
 | 
					        curve = None
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -139,7 +168,7 @@ class AW_OT_edit_curve(bpy.types.Operator):
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        # get from 'root' bone
 | 
					        # get from 'root' bone
 | 
				
			||||||
        if not curve:
 | 
					        if not curve:
 | 
				
			||||||
            curve, _const = fn.get_follow_curve_from_armature(context.object)
 | 
					            curve, _const = fn.get_follow_curve_from_armature(ob)
 | 
				
			||||||
            if isinstance(curve, str):
 | 
					            if isinstance(curve, str):
 | 
				
			||||||
                self.report({curve}, _const)
 | 
					                self.report({curve}, _const)
 | 
				
			||||||
                if curve == 'ERROR':
 | 
					                if curve == 'ERROR':
 | 
				
			||||||
@ -150,7 +179,9 @@ class AW_OT_edit_curve(bpy.types.Operator):
 | 
				
			|||||||
        # curve context.mode -> EDIT_CURVE
 | 
					        # curve context.mode -> EDIT_CURVE
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # Deselect armature object
 | 
					        # Deselect armature object
 | 
				
			||||||
        b.id_data.select_set(False)
 | 
					
 | 
				
			||||||
 | 
					        # b.id_data.select_set(False)
 | 
				
			||||||
 | 
					        ob.select_set(False)
 | 
				
			||||||
        return {"FINISHED"}
 | 
					        return {"FINISHED"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AW_OT_go_to_object(bpy.types.Operator):
 | 
					class AW_OT_go_to_object(bpy.types.Operator):
 | 
				
			||||||
@ -235,6 +266,7 @@ AW_OT_create_curve_path,
 | 
				
			|||||||
AW_OT_create_follow_path,
 | 
					AW_OT_create_follow_path,
 | 
				
			||||||
AW_OT_remove_follow_path,
 | 
					AW_OT_remove_follow_path,
 | 
				
			||||||
AW_OT_snap_curve_to_ground,
 | 
					AW_OT_snap_curve_to_ground,
 | 
				
			||||||
 | 
					AW_OT_snap_selected_curve,
 | 
				
			||||||
AW_OT_edit_curve,
 | 
					AW_OT_edit_curve,
 | 
				
			||||||
AW_OT_go_to_object,
 | 
					AW_OT_go_to_object,
 | 
				
			||||||
AW_OT_object_from_curve, # use set_choice_id is used to set an index in object_from_curve pop up menu
 | 
					AW_OT_object_from_curve, # use set_choice_id is used to set an index in object_from_curve pop up menu
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ bl_info = {
 | 
				
			|||||||
    "name": "Auto Walk",
 | 
					    "name": "Auto Walk",
 | 
				
			||||||
    "description": "Develop a walk/run cycles along a curve and pin feets",
 | 
					    "description": "Develop a walk/run cycles along a curve and pin feets",
 | 
				
			||||||
    "author": "Samuel Bernou",
 | 
					    "author": "Samuel Bernou",
 | 
				
			||||||
    "version": (1, 4, 4),
 | 
					    "version": (1, 5, 0),
 | 
				
			||||||
    "blender": (3, 0, 0),
 | 
					    "blender": (3, 0, 0),
 | 
				
			||||||
    "location": "View3D",
 | 
					    "location": "View3D",
 | 
				
			||||||
    "warning": "",
 | 
					    "warning": "",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										168
									
								
								fn.py
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								fn.py
									
									
									
									
									
								
							@ -389,66 +389,98 @@ def create_follow_path_constraint(ob, curve, follow_curve=True):
 | 
				
			|||||||
    const.use_curve_follow = True
 | 
					    const.use_curve_follow = True
 | 
				
			||||||
    return curve, const
 | 
					    return curve, const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def snap_curve():
 | 
					def shrinkwrap_on_object(source, target, apply=True):
 | 
				
			||||||
 | 
					    # shrinkwrap or cast on ground
 | 
				
			||||||
 | 
					    mod = source.modifiers.new('Shrinkwrap', 'SHRINKWRAP')
 | 
				
			||||||
 | 
					    # mod.wrap_method = 'TARGET_PROJECT'
 | 
				
			||||||
 | 
					    mod.wrap_method = 'PROJECT'
 | 
				
			||||||
 | 
					    mod.wrap_mode = 'ON_SURFACE'
 | 
				
			||||||
 | 
					    mod.use_project_z = True
 | 
				
			||||||
 | 
					    mod.use_negative_direction = True
 | 
				
			||||||
 | 
					    mod.use_positive_direction = True
 | 
				
			||||||
 | 
					    mod.target = target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if apply:
 | 
				
			||||||
 | 
					        # Apply and decimate
 | 
				
			||||||
 | 
					        switch = False
 | 
				
			||||||
 | 
					        if bpy.context.mode == 'EDIT_CURVE':
 | 
				
			||||||
 | 
					            switch = True
 | 
				
			||||||
 | 
					            bpy.ops.object.mode_set(mode='OBJECT')
 | 
				
			||||||
 | 
					        bpy.ops.object.modifier_apply({'object': source}, modifier="Shrinkwrap", report=False)
 | 
				
			||||||
 | 
					        if switch:
 | 
				
			||||||
 | 
					            bpy.ops.object.mode_set(mode='EDIT')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def snap_curve(create_copy=False):
 | 
				
			||||||
    obj = bpy.context.object
 | 
					    obj = bpy.context.object
 | 
				
			||||||
 | 
					    gnd = get_gnd()
 | 
				
			||||||
 | 
					    if not gnd:
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    curve = const = None
 | 
					    curve = const = None
 | 
				
			||||||
    if obj.type == 'ARMATURE':
 | 
					    if obj.type == 'ARMATURE':
 | 
				
			||||||
        curve, const = get_follow_curve_from_armature(obj)
 | 
					        curve, const = get_follow_curve_from_armature(obj)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    to_follow = bpy.context.scene.anim_cycle_settings.path_to_follow
 | 
					    to_follow = bpy.context.scene.anim_cycle_settings.path_to_follow
 | 
				
			||||||
    if not curve and not to_follow:
 | 
					 | 
				
			||||||
        return ('ERROR', f'No curve pointed by "Path" filed')
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    # get curve from field
 | 
					 | 
				
			||||||
    if not curve:
 | 
					 | 
				
			||||||
        curve, const = create_follow_path_constraint(obj, to_follow)
 | 
					 | 
				
			||||||
        if isinstance(curve, str):
 | 
					 | 
				
			||||||
            return (curve, const) # those are error message
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # if obj.type == 'CURVE':
 | 
					 | 
				
			||||||
    #     return ('ERROR', f'Select the armature related to curve {obj.name}')
 | 
					 | 
				
			||||||
    # else:
 | 
					 | 
				
			||||||
    #     return ('ERROR', 'Not an armature object')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    gnd = get_gnd()
 | 
					 | 
				
			||||||
    if not gnd:
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    curve_act = None
 | 
					    curve_act = None
 | 
				
			||||||
    anim_frame = None
 | 
					    anim_frame = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # if it's on a snap curve, fetch original
 | 
					    if create_copy:
 | 
				
			||||||
    if '_snap' in curve.name:
 | 
					        # get curve from field
 | 
				
			||||||
        org_name = re.sub(r'_snap\.?\d{0,3}$', '', curve.name)
 | 
					        if not curve and not to_follow:
 | 
				
			||||||
        org_curve = bpy.context.scene.objects.get(org_name)
 | 
					            return ('ERROR', f'No curve pointed by "Path" filed')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if org_curve:
 | 
					        if not curve:
 | 
				
			||||||
            const.target = org_curve
 | 
					            curve, const = create_follow_path_constraint(obj, to_follow)
 | 
				
			||||||
 | 
					            if isinstance(curve, str):
 | 
				
			||||||
 | 
					                return (curve, const) # those are error message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # keep action
 | 
					        # if obj.type == 'CURVE':
 | 
				
			||||||
        if curve.data.animation_data and curve.data.animation_data.action:
 | 
					        #     return ('ERROR', f'Select the armature related to curve {obj.name}')
 | 
				
			||||||
            curve_act = curve.data.animation_data.action
 | 
					        # else:
 | 
				
			||||||
 | 
					        #     return ('ERROR', 'Not an armature object')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        anim_frame = curve.data.path_duration
 | 
					 | 
				
			||||||
        # delete old snap
 | 
					 | 
				
			||||||
        bpy.data.objects.remove(curve)
 | 
					 | 
				
			||||||
        # assign old curve as main one
 | 
					 | 
				
			||||||
        curve = org_curve
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    nc = curve.copy()
 | 
					 | 
				
			||||||
    name = re.sub(r'\.\d{3}$', '', curve.name) + '_snap'
 | 
					 | 
				
			||||||
    const.target = nc
 | 
					 | 
				
			||||||
    nc.name = name
 | 
					 | 
				
			||||||
    nc.data = curve.data.copy()
 | 
					 | 
				
			||||||
    nc.data.name = name + '_data'
 | 
					 | 
				
			||||||
    if curve_act:
 | 
					 | 
				
			||||||
        nc.data.animation_data_create()
 | 
					 | 
				
			||||||
        nc.data.animation_data.action = curve_act
 | 
					 | 
				
			||||||
    if anim_frame:
 | 
					 | 
				
			||||||
        nc.data.path_duration = anim_frame
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    curve.users_collection[0].objects.link(nc)
 | 
					        # if it's on a snap curve, fetch original
 | 
				
			||||||
 | 
					        if '_snap' in curve.name:
 | 
				
			||||||
 | 
					            org_name = re.sub(r'_snap\.?\d{0,3}$', '', curve.name)
 | 
				
			||||||
 | 
					            org_curve = bpy.context.scene.objects.get(org_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if org_curve:
 | 
				
			||||||
 | 
					                const.target = org_curve
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # keep action
 | 
				
			||||||
 | 
					            if curve.data.animation_data and curve.data.animation_data.action:
 | 
				
			||||||
 | 
					                curve_act = curve.data.animation_data.action
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            anim_frame = curve.data.path_duration
 | 
				
			||||||
 | 
					            # delete old snap
 | 
				
			||||||
 | 
					            bpy.data.objects.remove(curve)
 | 
				
			||||||
 | 
					            # assign old curve as main one
 | 
				
			||||||
 | 
					            curve = org_curve
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nc = curve.copy()
 | 
				
			||||||
 | 
					        name = re.sub(r'\.\d{3}$', '', curve.name) + '_snap'
 | 
				
			||||||
 | 
					        const.target = nc
 | 
				
			||||||
 | 
					        nc.name = name
 | 
				
			||||||
 | 
					        nc.data = curve.data.copy()
 | 
				
			||||||
 | 
					        nc.data.name = name + '_data'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if curve_act:
 | 
				
			||||||
 | 
					            nc.data.animation_data_create()
 | 
				
			||||||
 | 
					            nc.data.animation_data.action = curve_act
 | 
				
			||||||
 | 
					        if anim_frame:
 | 
				
			||||||
 | 
					            nc.data.path_duration = anim_frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        curve.users_collection[0].objects.link(nc)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        if not curve:
 | 
				
			||||||
 | 
					            return ('ERROR', 'Path not found')
 | 
				
			||||||
 | 
					        nc = curve
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ## If object mode is Curve subdivide it (TODO if nurbs needs conversion)
 | 
					    ## If object mode is Curve subdivide it (TODO if nurbs needs conversion)
 | 
				
			||||||
    #-# subdivide the curve (if curve is not nurbs)
 | 
					    #-# subdivide the curve (if curve is not nurbs)
 | 
				
			||||||
@ -458,18 +490,7 @@ def snap_curve():
 | 
				
			|||||||
    # bpy.ops.curve.subdivide(number_cuts=4)
 | 
					    # bpy.ops.curve.subdivide(number_cuts=4)
 | 
				
			||||||
    # bpy.ops.object.mode_set(mode='OBJECT')
 | 
					    # bpy.ops.object.mode_set(mode='OBJECT')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # shrinkwrap or cast on ground
 | 
					    shrinkwrap_on_object(nc, gnd)
 | 
				
			||||||
    mod = nc.modifiers.new('Shrinkwrap', 'SHRINKWRAP')
 | 
					 | 
				
			||||||
    # mod.wrap_method = 'TARGET_PROJECT'
 | 
					 | 
				
			||||||
    mod.wrap_method = 'PROJECT'
 | 
					 | 
				
			||||||
    mod.wrap_mode = 'ON_SURFACE'
 | 
					 | 
				
			||||||
    mod.use_project_z = True
 | 
					 | 
				
			||||||
    mod.use_negative_direction = True
 | 
					 | 
				
			||||||
    mod.use_positive_direction = True
 | 
					 | 
				
			||||||
    mod.target = gnd
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # Apply and decimate
 | 
					 | 
				
			||||||
    bpy.ops.object.modifier_apply({'object': nc}, modifier="Shrinkwrap", report=False)
 | 
					 | 
				
			||||||
    bpy.context.scene.anim_cycle_settings.path_to_follow = nc
 | 
					    bpy.context.scene.anim_cycle_settings.path_to_follow = nc
 | 
				
			||||||
    # return 0, nc
 | 
					    # return 0, nc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -646,10 +667,11 @@ def remove_all_cycles_modifier(ob=None):
 | 
				
			|||||||
    print(f'Remove cyclic modifiers on {ct} fcurve(s)')
 | 
					    print(f'Remove cyclic modifiers on {ct} fcurve(s)')
 | 
				
			||||||
    return ct
 | 
					    return ct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_cycle_modifiers(ob=None):
 | 
					def get_only_pose_keyable_fcurves(ob, action=None):
 | 
				
			||||||
    ob = ob or bpy.context.object
 | 
					    '''Can action providing another action (must be for the same object)'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # skip bones that are on protected layers ?
 | 
					    act = action or ob.animation_data.action
 | 
				
			||||||
 | 
					    ## skip bones that are on protected layers ?
 | 
				
			||||||
    # protected = [i for i, l in enumerate(ob.data.layers_protected) if l]
 | 
					    # protected = [i for i, l in enumerate(ob.data.layers_protected) if l]
 | 
				
			||||||
    # for b in ob.data.bones:
 | 
					    # for b in ob.data.bones:
 | 
				
			||||||
    #     if b.use_deform: # don't affect deform bones
 | 
					    #     if b.use_deform: # don't affect deform bones
 | 
				
			||||||
@ -657,25 +679,35 @@ def create_cycle_modifiers(ob=None):
 | 
				
			|||||||
        ## b_layers = [i for i, l in enumerate(b.layers) if l]
 | 
					        ## b_layers = [i for i, l in enumerate(b.layers) if l]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    name_list = [b.name for b in ob.data.bones] #  if not b.use_deform (too limiting)
 | 
					    name_list = [b.name for b in ob.data.bones] #  if not b.use_deform (too limiting)
 | 
				
			||||||
 | 
					    fcus = []
 | 
				
			||||||
    re_prefix = re.compile(r'^(mch|def|org|vis|fld|ctp)[\._-]', flags=re.I)
 | 
					    re_prefix = re.compile(r'^(mch|def|org|vis|fld|ctp)[\._-]', flags=re.I)
 | 
				
			||||||
    ct = 0
 | 
					    for fc in act.fcurves:
 | 
				
			||||||
    for fc in ob.animation_data.action.fcurves:
 | 
					 | 
				
			||||||
        if [m for m in fc.modifiers if m.type == 'CYCLES']:
 | 
					 | 
				
			||||||
            # skip already existing modifier
 | 
					 | 
				
			||||||
            continue
 | 
					 | 
				
			||||||
        if not '"' in fc.data_path:
 | 
					 | 
				
			||||||
            continue
 | 
					 | 
				
			||||||
        # skip offset
 | 
					        # skip offset
 | 
				
			||||||
        if fc.data_path.endswith('.offset') and 'constraint' in fc.data_path:
 | 
					        if fc.data_path.endswith('.offset') and 'constraint' in fc.data_path:
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        b_name = fc.data_path.split('"')[1]
 | 
					        # skip fcus that are not bones
 | 
				
			||||||
        if re_prefix.match(b_name):
 | 
					        if not '"' in fc.data_path:
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        b_name = fc.data_path.split('"')[1]
 | 
				
			||||||
        if b_name not in name_list:
 | 
					        if b_name not in name_list:
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if re_prefix.match(b_name):
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        fcus.append(fc)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return fcus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_cycle_modifiers(ob=None):
 | 
				
			||||||
 | 
					    ob = ob or bpy.context.object
 | 
				
			||||||
 | 
					    ct = 0
 | 
				
			||||||
 | 
					    keyable_fcurves = get_only_pose_keyable_fcurves(ob)
 | 
				
			||||||
 | 
					    for fc in keyable_fcurves:
 | 
				
			||||||
 | 
					        if [m for m in fc.modifiers if m.type == 'CYCLES']:
 | 
				
			||||||
 | 
					            # skip if already existing modifier
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
        # print(f'Adding cycle modifier {fc.data_path}')
 | 
					        # print(f'Adding cycle modifier {fc.data_path}')
 | 
				
			||||||
        _m = fc.modifiers.new(type='CYCLES')
 | 
					        _m = fc.modifiers.new(type='CYCLES')
 | 
				
			||||||
        ct += 1
 | 
					        ct += 1
 | 
				
			||||||
 | 
				
			|||||||
@ -66,7 +66,13 @@ class AW_PT_walk_cycle_anim_panel(bpy.types.Panel):
 | 
				
			|||||||
            box.prop_search(settings, "gnd", context.scene, "objects")
 | 
					            box.prop_search(settings, "gnd", context.scene, "objects")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            row = box.row()
 | 
					            row = box.row()
 | 
				
			||||||
            row.operator('autowalk.snap_curve_to_ground', text='Snap curve to ground', icon='SNAP_ON')
 | 
					            if ob and ob.type == 'ARMATURE':
 | 
				
			||||||
 | 
					                row.operator('autowalk.snap_curve_to_ground', text='Snap Curve To Ground', icon='SNAP_ON')
 | 
				
			||||||
 | 
					            elif ob and ob.type == 'CURVE':
 | 
				
			||||||
 | 
					                row.operator('autowalk.snap_selected_curve', text='Snap Selected Curve To Ground', icon='SNAP_ON')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                row.label(text='Select curve or armature to snap', icon='INFO')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            row.active = bool(settings.gnd)
 | 
					            row.active = bool(settings.gnd)
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user