:mmsus:
This commit is contained in:
parent
8a55458264
commit
8380dbbf5c
213
__init__.py
213
__init__.py
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user