I haven't quite made this into an Blender addon yet but here is the current progress on the tool.
This is a picture of before running tool (with some keyframes selected. assumes there are some neighbor keys to selected ones):
This is a picture of after running tool:
#modify use at your own risk import bpy def naEaseMain(sliderValue = None): """make the animation curve resemble an ease in or ease out pattern. it runs on selected keyframes. should support multiple curves. currently only works if there is at least one keyframe before and after selected keyframes @param sliderValue -10 to 10 """ def naEaseGetValue( curve = None, selectedKeyIndex=None, leftIndex=None, rightIndex=None, sliderValue=None ): """ get new value for key @param curve , is the curve working on @param sliderValue -10, 10 negative means favor left index """ result = None sliderV = abs(sliderValue) + 1 frameAllDistance = curve.keyframe_points[rightIndex].co[0] - curve.keyframe_points[leftIndex].co[0] frameDistance = curve.keyframe_points[selectedKeyIndex].co[0] - curve.keyframe_points[leftIndex].co[0] propFrameDistance = frameDistance/frameAllDistance lastValueMinusFirstValue = curve.keyframe_points[rightIndex].co[1] - curve.keyframe_points[leftIndex].co[1] firstValue = curve.keyframe_points[leftIndex].co[1] valuePosSlider = lastValueMinusFirstValue*( 1-(abs(propFrameDistance-1))**(sliderV) ) + firstValue valueNegSlider = lastValueMinusFirstValue*( (propFrameDistance)**(sliderV) ) + firstValue result = valuePosSlider if sliderValue < 0: result = valueNegSlider return result def naEaseSetValue( curve = None, selectedKeyIndex = None, value = None ): """change key in graph editor """ curve.keyframe_points[selectedKeyIndex].co[1] = value #this bit changes tangent type of selected key might need work areatype = bpy.context.area.type bpy.context.area.type = 'GRAPH_EDITOR' bpy.ops.graph.handle_type(type='AUTO_CLAMPED') bpy.context.area.type = areatype # #get selected curve curves = bpy.context.selected_objects[0].animation_data.action.fcurves #need to error check curveIndexes = [] for i in range( len(curves) ): if curves[i].select: curveIndexes.append(i) for curveIndex in curveIndexes: #this loop is for all translate x,y,z etc channels that have a selected key #curveIndex = curveIndexes[0] #need to support all selected curves curve = curves[ curveIndex ] #get neighbor keys selectedKeyIndexes = [] for i in range( len(curve.keyframe_points) ): if curve.keyframe_points[i].select_control_point: selectedKeyIndexes.append(i) #print('selected key indexes', selectedKeyIndexes) leftIndex = min(selectedKeyIndexes)-1 rightIndex = max(selectedKeyIndexes)+1 #assert left and right index exist if leftIndex < 0: print('cannot find a neighbor key to left of selected. skipping curve index %s' %curveIndex) continue if rightIndex > len(curve.keyframe_points): print('cannot find a neighbor key to right of selected. skipping curve index %s' %curveIndex) continue print('left %s, right %s indexes' %(leftIndex,rightIndex) ) for selectedKeyIndex in selectedKeyIndexes: #this loop is for all selected keyframes for this curve #allow to use different sliderValues -10 to 10 value = naEaseGetValue( curve = curve, selectedKeyIndex=selectedKeyIndex, leftIndex=leftIndex, rightIndex=rightIndex, sliderValue=sliderValue ) #set value in graph editor naEaseSetValue( curve = curve, selectedKeyIndex = selectedKeyIndex, value = value ) naEaseMain(9) #Inspired by: #Alan Camilo's Atools alancamilo dot com #Joan Marc Fuentes Iglesias #https://blenderartists.org/t/change-fcurve-mode-via-python/530691
Happy Sketching!
Nate