animation mode to create all keys at once

master
pullusb 2023-12-07 12:16:18 +01:00
parent a56a9ea537
commit 77e3049d5d
4 changed files with 77 additions and 43 deletions

View File

@ -1,7 +1,7 @@
bl_info = { bl_info = {
"name": "gp interpolate", "name": "gp interpolate",
"author": "Christophe Seux, Samuel Bernou", "author": "Christophe Seux, Samuel Bernou",
"version": (0, 1, 2), "version": (0, 2, 0),
"blender": (3, 6, 0), "blender": (3, 6, 0),
"location": "Sidebar > Gpencil Tab > Interpolate", "location": "Sidebar > Gpencil Tab > Interpolate",
"description": "Interpolate Grease pencil strokes over 3D", "description": "Interpolate Grease pencil strokes over 3D",

View File

@ -20,13 +20,26 @@ from mathutils.geometry import (barycentric_transform,
tessellate_polygon) tessellate_polygon)
def following_key(forward=True): def following_keys(forward=True, all_keys=True) -> list:# -> list[int] | list | None:
'''return a lsit of int or an empty list'''
direction = 1 if forward else -1 direction = 1 if forward else -1
cur_frame = bpy.context.scene.frame_current cur_frame = bpy.context.scene.frame_current
settings = bpy.context.scene.gp_interpo_settings settings = bpy.context.scene.gp_interpo_settings
if settings.mode == 'FRAME': if settings.mode == 'FRAME':
return cur_frame + (settings.padding * direction) if all_keys:
scn = bpy.context.scene
if forward:
limit = scn.frame_preview_end if scn.use_preview_range else scn.frame_end
else:
limit = scn.frame_preview_start if scn.use_preview_range else scn.frame_start
limit += direction # offset by one for limit to be in range
return list(range(cur_frame, limit, settings.padding * direction))
else:
return [cur_frame + (settings.padding * direction)]
elif settings.mode == 'GPKEY': elif settings.mode == 'GPKEY':
layers = bpy.context.object.data.layers layers = bpy.context.object.data.layers
@ -42,18 +55,26 @@ def following_key(forward=True):
frames = [k.co.x for fc in arm.animation_data.action.fcurves for k in fc.keyframe_points] frames = [k.co.x for fc in arm.animation_data.action.fcurves for k in fc.keyframe_points]
if not frames: if not frames:
return return []
# Sort frames (invert if looking backward)
frames.sort(reversed=not forward)
if all_keys:
frames = list(set(frames))
if forward:
frame_list = [int(f) for f in frames if f > cur_frame]
else:
frame_list = [int(f) for f in frames if f < cur_frame]
return frame_list
frames.sort()
if forward: if forward:
new = next((f for f in frames if f > cur_frame), None) new = next((f for f in frames if f > cur_frame), None)
else: else:
below = [f for f in frames if f < cur_frame] new = next((f for f in frames if f < cur_frame), None)
if not below: if new is None:
return return []
new = below[-1] return [int(new)]
return int(new)
## TODO: add bake animation to empty for later GP layer parenting ## TODO: add bake animation to empty for later GP layer parenting
@ -88,9 +109,9 @@ class GP_OT_interpolate_stroke(bpy.types.Operator):
# auto_key_status = context.tool_settings.use_keyframe_insert_auto # auto_key_status = context.tool_settings.use_keyframe_insert_auto
# context.tool_settings.use_keyframe_insert_auto = True # context.tool_settings.use_keyframe_insert_auto = True
## Determine on what key to jump ## Determine on what key/keys to jump
frame_to_jump = following_key(forward=self.next) frames_to_jump = following_keys(forward=self.next, all_keys=settings.use_animation)
if frame_to_jump is None: if not len(frames_to_jump):
self.report({'WARNING'}, 'No keyframe available in this direction') self.report({'WARNING'}, 'No keyframe available in this direction')
return {'CANCELLED'} return {'CANCELLED'}
@ -214,7 +235,13 @@ class GP_OT_interpolate_stroke(bpy.types.Operator):
# Copy stroke selection, jump frame and paste # Copy stroke selection, jump frame and paste
bpy.ops.gpencil.copy() bpy.ops.gpencil.copy()
scn.frame_set(frame_to_jump)
wm = bpy.context.window_manager # Pgs
wm.progress_begin(frames_to_jump[0], frames_to_jump[-1]) # Pgs
for f in frames_to_jump:
wm.progress_update(f) # Pgs
scn.frame_set(f)
plan_co, plane_no = get_gp_draw_plane(gp) plan_co, plane_no = get_gp_draw_plane(gp)
bpy.ops.gpencil.paste() bpy.ops.gpencil.paste()
@ -246,6 +273,7 @@ class GP_OT_interpolate_stroke(bpy.types.Operator):
new_stroke.points.foreach_set('co', new_local_co_3d.reshape(nb_points*3)) new_stroke.points.foreach_set('co', new_local_co_3d.reshape(nb_points*3))
new_stroke.points.update() new_stroke.points.update()
wm.progress_end() # Pgs
## Reset autokey status ## Reset autokey status
# context.tool_settings.use_keyframe_insert_auto = auto_key_status # (Done in context manager) # context.tool_settings.use_keyframe_insert_auto = auto_key_status # (Done in context manager)
@ -284,8 +312,8 @@ class GP_OT_interpolate_stroke(bpy.types.Operator):
context.tool_settings.use_keyframe_insert_auto = True context.tool_settings.use_keyframe_insert_auto = True
## Determine on what key to jump ## Determine on what key to jump
frame_to_jump = following_key(forward=self.next) frames_to_jump = following_keys(forward=self.next)
if frame_to_jump is None: if frames_to_jump is None:
self.report({'WARNING'}, 'No keyframe available in this direction') self.report({'WARNING'}, 'No keyframe available in this direction')
return {'CANCELLED'} return {'CANCELLED'}
@ -376,7 +404,7 @@ class GP_OT_interpolate_stroke(bpy.types.Operator):
bpy.ops.gpencil.copy() bpy.ops.gpencil.copy()
scn.frame_set(frame_to_jump) scn.frame_set(frames_to_jump)
plan_co, plane_no = get_gp_draw_plane(gp) plan_co, plane_no = get_gp_draw_plane(gp)

View File

@ -24,6 +24,11 @@ class GP_PG_interpolate_settings(PropertyGroup):
description='Select method for interpolating strokes' description='Select method for interpolating strokes'
) )
use_animation : BoolProperty(
name='Animatation',
default=True,
description='Apply the interpolation on the remaining range')
search_range : FloatProperty( search_range : FloatProperty(
name="Search Range", name="Search Range",
description="Search range size when points are out of mesh", description="Search range size when points are out of mesh",

1
ui.py
View File

@ -30,6 +30,7 @@ class GP_PT_interpolate(bpy.types.Panel):
col.prop(settings, 'method', text='Method') col.prop(settings, 'method', text='Method')
col.prop(settings, 'use_animation', text='Animation')
if settings.method == 'BONE': if settings.method == 'BONE':
col = layout.column(align=True) col = layout.column(align=True)