This commit is contained in:
lachrymaL 2021-07-09 21:57:31 -04:00 committed by GitHub
parent 8a55458264
commit 8380dbbf5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -16,148 +16,143 @@
# along with FCurveHandleCopy. If not, see <http://www.gnu.org/licenses/>. # along with FCurveHandleCopy. If not, see <http://www.gnu.org/licenses/>.
bl_info = { bl_info = {
"name" : "FCurveHandleCopy", "name" : "FCurveHandleCopy",
"author" : "MMaker", "author" : "MMaker",
"description" : ":)", "description" : ":)",
"blender" : (2, 83, 0), "blender" : (2, 83, 0),
"version" : (0, 0, 1), "version" : (0, 0, 1),
"category" : "Animation" "category" : "Animation"
} }
import bpy import bpy
import mathutils import mathutils
import bl_math
class G: class G:
selected_keys = [] selected_keys = []
bezier = [] bezier = []
def inverse_lerp(minimum, maximum, val):
return (val - minimum) / (maximum - minimum)
def convert_handles_to_bezier(keyframes): def convert_handles_to_bezier(keyframes):
bezier = [] handles = [keyframes[0].handle_right, keyframes[1].handle_left]
in_key = keyframes[0] bezier = list(map(
out_key = keyframes[1] lambda x: list(map(
lambda v, dimension: inverse_lerp(keyframes[0].co[dimension], keyframes[1].co[dimension], v),
in_handle = in_key.handle_right x,
out_handle = out_key.handle_left range(2)
)),
bezier.append(in_handle[0] / (abs(in_key.co[0] - out_key.co[0]))) # x1 handles
bezier.append(in_handle[1] / (abs(in_key.co[1] - out_key.co[1]))) # y1 ))
bezier.append(out_handle[0] / (abs(in_key.co[0] - out_key.co[0]))) # x2 return bezier
bezier.append(out_handle[1] / (abs(in_key.co[1] - out_key.co[1]))) # y2
return bezier
def generate_new_handles(in_key, out_key): def generate_new_handles(in_key, out_key):
x_diff = abs(in_key.co[0] - out_key.co[0]) handles = list(map(
y_diff = abs(in_key.co[1] - out_key.co[1]) lambda fac: list(map(
lambda dimension: bl_math.lerp(in_key.co[dimension], out_key.co[dimension], fac[dimension]),
y_direction = (1 if (in_key.co[1] - out_key.co[1]) < 0 else -1) range(2)
)),
new_in_handle = mathutils.Vector(( G.bezier
in_key.co[0] + (G.bezier[0] * x_diff), ))
in_key.co[1] + (G.bezier[1] * y_diff * y_direction)
)) return [
mathutils.Vector(
new_out_handle = mathutils.Vector(( (handles[0][0], handles[0][1])
in_key.co[0] + (G.bezier[2] * x_diff), ),
in_key.co[1] + (G.bezier[3] * y_diff * y_direction) mathutils.Vector(
)) (handles[1][0], handles[1][1])
)
return [new_in_handle, new_out_handle] ]
class FCurveHandleCopyValue(bpy.types.Operator): class FCurveHandleCopyValue(bpy.types.Operator):
"""Copy FCurve handle values""" """Copy FCurve handle values"""
bl_idname = "anim.mmaker_fcurve_handle_copy_values" bl_idname = "anim.mmaker_fcurve_handle_copy_values"
bl_label = "Copy" bl_label = "Copy"
def execute(self, context): def execute(self, context):
if (context.selected_visible_fcurves): if (context.selected_visible_fcurves):
fcurves = context.selected_visible_fcurves fcurves = context.selected_visible_fcurves
G.selected_keys = [] G.selected_keys = []
if (len(fcurves) > 1): if (len(fcurves) > 1):
self.report({"WARNING"}, "Please only select one curve when copying an ease.") self.report({"WARNING"}, "Please only select one curve when copying an ease.")
return {'CANCELLED'} return {'CANCELLED'}
for keyframe in fcurves[0].keyframe_points: G.selected_keys = list(filter(lambda x: x.select_control_point, fcurves[0].keyframe_points))
if (len(G.selected_keys) > 2):
self.report({"WARNING"}, "Please select exactly two keyframes when copying an ease.") if (len(G.selected_keys) != 2):
return {'CANCELLED'} self.report({"WARNING"}, "Please select exactly two keyframes when copying an ease.")
return {'CANCELLED'}
if (keyframe.select_control_point):
G.selected_keys.append(keyframe) G.bezier = convert_handles_to_bezier(G.selected_keys)
if (len(G.selected_keys) != 2):
self.report({"WARNING"}, "Please select exactly two keyframes when copying an ease.")
return {'CANCELLED'}
G.bezier = convert_handles_to_bezier(G.selected_keys)
return {'FINISHED'} return {'FINISHED'}
class FCurveHandlePasteValue(bpy.types.Operator): class FCurveHandlePasteValue(bpy.types.Operator):
"""Paste FCurve handle values""" """Paste FCurve handle values"""
bl_idname = "anim.mmaker_fcurve_handle_paste_values" bl_idname = "anim.mmaker_fcurve_handle_paste_values"
bl_label = "Paste" bl_label = "Paste"
def execute(self, context): def execute(self, context):
if (context.selected_visible_fcurves): if (context.selected_visible_fcurves):
fcurves = context.selected_visible_fcurves fcurves = context.selected_visible_fcurves
for fcurve in fcurves: for fcurve in fcurves:
keys = fcurve.keyframe_points keys = fcurve.keyframe_points
selected_keys = [] selected_keys = []
for i in range(0, len(keys)): for i in range(0, len(keys)):
if (keys[i].select_control_point): if (keys[i].select_control_point):
selected_keys.append(i) selected_keys.append(i)
if (len(selected_keys) == 0): if (len(selected_keys) == 0):
self.report({"WARNING"}, "Please select some keyframes to paste an ease to.") self.report({"WARNING"}, "Please select some keyframes to paste an ease to.")
return {'CANCELLED'} return {'CANCELLED'}
if (len(selected_keys) == 1): if (len(selected_keys) == 1):
# TODO: Implement logic for this soon # TODO: Implement logic for this soon
pass pass
else: else:
selected_keys.pop() # TODO: Related to above, implement soon selected_keys.pop() # TODO: Related to above, implement soon
for i in selected_keys: for i in selected_keys:
if (i < len(keys) - 1): if (i < len(keys) - 1):
new_handles = generate_new_handles(keys[i], keys[i + 1]) new_handles = generate_new_handles(keys[i], keys[i + 1])
keys[i].interpolation = 'BEZIER' keys[i].interpolation = 'BEZIER'
keys[i + 1].interpolation = 'BEZIER' keys[i + 1].interpolation = 'BEZIER'
keys[i].handle_right_type = 'FREE' keys[i].handle_right_type = 'FREE'
keys[i + 1].handle_left_type = 'FREE' keys[i + 1].handle_left_type = 'FREE'
keys[i].handle_right = new_handles[0] keys[i].handle_right = new_handles[0]
keys[i + 1].handle_left = new_handles[1] keys[i + 1].handle_left = new_handles[1]
return {'FINISHED'} return {'FINISHED'}
def menu_func(self, context): def menu_func(self, context):
self.layout.operator(FCurveHandleCopyValue.bl_idname) self.layout.operator(FCurveHandleCopyValue.bl_idname)
self.layout.operator(FCurveHandlePasteValue.bl_idname) self.layout.operator(FCurveHandlePasteValue.bl_idname)
classes = [ classes = [
FCurveHandleCopyValue, FCurveHandleCopyValue,
FCurveHandlePasteValue FCurveHandlePasteValue
] ]
def register(): def register():
for cls in classes: for cls in classes:
bpy.utils.register_class(cls) bpy.utils.register_class(cls)
bpy.types.GRAPH_HT_header.append(menu_func) bpy.types.GRAPH_HT_header.append(menu_func)
def unregister(): def unregister():
for cls in classes: for cls in classes:
bpy.utils.unregister_class(cls) bpy.utils.unregister_class(cls)
bpy.types.GRAPH_HT_header.remove(menu_func) bpy.types.GRAPH_HT_header.remove(menu_func)
if __name__ == "__main__": if __name__ == "__main__":
try: try:
unregister() unregister()
except: except:
import sys import sys
print("Error:", sys.exc_info()[0]) print("Error:", sys.exc_info()[0])
pass pass
register() register()