parent
cb0ea42e19
commit
071f4fd13b
|
@ -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, 8, 1),
|
"version": (0, 8, 2),
|
||||||
"blender": (4, 0, 2),
|
"blender": (4, 0, 2),
|
||||||
"location": "Sidebar > Gpencil Tab > Interpolate",
|
"location": "Sidebar > Gpencil Tab > Interpolate",
|
||||||
"description": "Interpolate Grease pencil strokes over 3D",
|
"description": "Interpolate Grease pencil strokes over 3D",
|
||||||
|
|
|
@ -158,7 +158,6 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
||||||
if obj:
|
if obj:
|
||||||
object_hit, hit_location, tri, tri_indices = obj_ray_cast(obj, square_co, origin, dg)
|
object_hit, hit_location, tri, tri_indices = obj_ray_cast(obj, square_co, origin, dg)
|
||||||
else:
|
else:
|
||||||
# scene raycast
|
|
||||||
object_hit, hit_location, tri, tri_indices = ray_cast_point(square_co, origin, dg)
|
object_hit, hit_location, tri, tri_indices = ray_cast_point(square_co, origin, dg)
|
||||||
|
|
||||||
if object_hit:
|
if object_hit:
|
||||||
|
@ -228,7 +227,6 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
||||||
elif self.settings.method == 'GEOMETRY':
|
elif self.settings.method == 'GEOMETRY':
|
||||||
if col != context.scene.collection:
|
if col != context.scene.collection:
|
||||||
included_cols.append(col.name)
|
included_cols.append(col.name)
|
||||||
## Maybe include a plane just behind geo ? probably bad idea
|
|
||||||
|
|
||||||
elif self.settings.method == 'OBJECT':
|
elif self.settings.method == 'OBJECT':
|
||||||
if not self.settings.target_object:
|
if not self.settings.target_object:
|
||||||
|
@ -263,7 +261,7 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
||||||
vl_col = bpy.context.view_layer.layer_collection.children.get(intercol.name)
|
vl_col = bpy.context.view_layer.layer_collection.children.get(intercol.name)
|
||||||
intercol.hide_viewport = vl_col.exclude = vl_col.hide_viewport = False
|
intercol.hide_viewport = vl_col.exclude = vl_col.hide_viewport = False
|
||||||
|
|
||||||
# Override collection
|
## Override collection
|
||||||
col = intercol
|
col = intercol
|
||||||
|
|
||||||
dg = bpy.context.evaluated_depsgraph_get()
|
dg = bpy.context.evaluated_depsgraph_get()
|
||||||
|
@ -275,9 +273,10 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
||||||
point_co_world = self.gp.matrix_world @ point.co
|
point_co_world = self.gp.matrix_world @ point.co
|
||||||
|
|
||||||
if target_obj:
|
if target_obj:
|
||||||
|
## Object raycast
|
||||||
object_hit, hit_location, tri, tri_indices = obj_ray_cast(target_obj, point_co_world, origin, dg)
|
object_hit, hit_location, tri, tri_indices = obj_ray_cast(target_obj, point_co_world, origin, dg)
|
||||||
else:
|
else:
|
||||||
# scene raycast
|
## Scene raycast
|
||||||
object_hit, hit_location, tri, tri_indices = ray_cast_point(point_co_world, origin, dg)
|
object_hit, hit_location, tri, tri_indices = ray_cast_point(point_co_world, origin, dg)
|
||||||
|
|
||||||
## Iterative increasing search range when no surface hit
|
## Iterative increasing search range when no surface hit
|
||||||
|
@ -342,10 +341,13 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
||||||
mesh=True)
|
mesh=True)
|
||||||
|
|
||||||
dg = bpy.context.evaluated_depsgraph_get()
|
dg = bpy.context.evaluated_depsgraph_get()
|
||||||
# Get only just pasted strokes
|
|
||||||
|
## Get pasted stroke
|
||||||
new_strokes = [s for s in self.gp.data.layers.active.active_frame.strokes if s.select]
|
new_strokes = [s for s in self.gp.data.layers.active.active_frame.strokes if s.select]
|
||||||
# new_strokes = self.gp.data.layers.active.active_frame.strokes[-len(self.strokes_data):]
|
## Keep reference to all accessible other strokes (in all accessible layer)
|
||||||
|
other_strokes = [s for l in self.gp.data.layers if l.active_frame and not l.lock for s in l.active_frame.strokes if not s.select]
|
||||||
|
|
||||||
|
occluded_points = []
|
||||||
# For new_stroke, stroke_data in zip(new_strokes, self.strokes_data):
|
# For new_stroke, stroke_data in zip(new_strokes, self.strokes_data):
|
||||||
for new_stroke, stroke_data in zip(list(new_strokes), list(self.strokes_data)):
|
for new_stroke, stroke_data in zip(list(new_strokes), list(self.strokes_data)):
|
||||||
world_co_3d = []
|
world_co_3d = []
|
||||||
|
@ -364,39 +366,27 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
||||||
|
|
||||||
## Occlusion management
|
## Occlusion management
|
||||||
if self.settings.method == 'GEOMETRY' and self.settings.remove_occluded:
|
if self.settings.method == 'GEOMETRY' and self.settings.remove_occluded:
|
||||||
viz_list = [True]*len(world_co_3d)
|
for i, point in enumerate(new_stroke.points):
|
||||||
for i, nco in enumerate(world_co_3d):
|
point_co = world_co_3d[i]
|
||||||
vec_direction = nco - origin
|
vec_direction = point_co - origin
|
||||||
## Reduced distance slightly to avoid occlusion on same source...
|
## Raycast with slightly reduced distance (avoid occlusion on same source)
|
||||||
dist = vec_direction.length - 0.001
|
n_hit, _, _, _, _, _ = scn.ray_cast(dg, origin, vec_direction, distance=vec_direction.length - 0.001)
|
||||||
n_hit, _, _, _, _, _ = scn.ray_cast(dg, origin, vec_direction, distance=dist)
|
|
||||||
# If there is a hit, it's occluded
|
|
||||||
if n_hit:
|
if n_hit:
|
||||||
viz_list[i] = False
|
occluded_points.append(point)
|
||||||
|
|
||||||
if all(viz_list):
|
if occluded_points:
|
||||||
# All visible, do nothing (just keep previous stroke)
|
## Select only occluded point
|
||||||
continue
|
bpy.ops.gpencil.select_all(action='DESELECT')
|
||||||
|
for point in occluded_points:
|
||||||
if any(viz_list):
|
point.select = True
|
||||||
# Create sub-strokes according to indices in original stroke
|
## remove points
|
||||||
for sublist in index_list_from_bools(viz_list):
|
bpy.ops.gpencil.delete(type='POINTS')
|
||||||
## Clear if only one isolated point ?
|
|
||||||
if len(sublist) == 1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
ns = self.gp.data.layers.active.active_frame.strokes.new()
|
|
||||||
for elem in ('hardness', 'material_index', 'line_width'):
|
|
||||||
setattr(ns, elem, getattr(new_stroke, elem))
|
|
||||||
|
|
||||||
ns.points.add(len(sublist))
|
|
||||||
for i, point_index in enumerate(sublist):
|
|
||||||
for elem in ('uv_factor', 'uv_fill', 'uv_rotation', 'pressure', 'co', 'strength', 'vertex_color'):
|
|
||||||
setattr(ns.points[i], elem, getattr(new_stroke.points[point_index], elem))
|
|
||||||
|
|
||||||
## Delete original stroke
|
|
||||||
self.gp.data.layers.active.active_frame.strokes.remove(new_stroke)
|
|
||||||
|
|
||||||
|
## restore selection (keep new strokes selected)
|
||||||
|
bpy.ops.gpencil.select_all(action='SELECT')
|
||||||
|
for stroke in other_strokes:
|
||||||
|
stroke.select = False
|
||||||
|
|
||||||
self.loop_count += 1
|
self.loop_count += 1
|
||||||
if self.loop_count >= len(self.frames_to_jump):
|
if self.loop_count >= len(self.frames_to_jump):
|
||||||
self.exit_modal(context)
|
self.exit_modal(context)
|
||||||
|
|
14
ui.py
14
ui.py
|
@ -15,6 +15,7 @@ class GP_PT_interpolate(bpy.types.Panel):
|
||||||
|
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.use_property_split = True
|
layout.use_property_split = True
|
||||||
|
layout.use_property_decorate = False
|
||||||
col = layout.column(align=False)
|
col = layout.column(align=False)
|
||||||
|
|
||||||
## Interpolation buttons
|
## Interpolation buttons
|
||||||
|
@ -32,10 +33,17 @@ class GP_PT_interpolate(bpy.types.Panel):
|
||||||
next_text = f'{scn.frame_current} > {scn.frame_preview_end if scn.use_preview_range else scn.frame_end}'
|
next_text = f'{scn.frame_current} > {scn.frame_preview_end if scn.use_preview_range else scn.frame_end}'
|
||||||
|
|
||||||
row = col.row(align=True)
|
row = col.row(align=True)
|
||||||
row.scale_x = 3
|
# row.scale_y = 1.2
|
||||||
|
direction_button_row = row.row(align=True)
|
||||||
|
direction_button_row.scale_x = 3
|
||||||
ops_id = "gp.interpolate_stroke_tri" if settings.method == 'TRI' else "gp.interpolate_stroke"
|
ops_id = "gp.interpolate_stroke_tri" if settings.method == 'TRI' else "gp.interpolate_stroke"
|
||||||
row.operator(ops_id, text=prev_text, icon=prev_icon).next = False
|
direction_button_row.operator(ops_id, text=prev_text, icon=prev_icon).next = False
|
||||||
row.operator(ops_id, text=next_text, icon=next_icon).next = True
|
direction_button_row.operator(ops_id, text=next_text, icon=next_icon).next = True
|
||||||
|
|
||||||
|
## Button for interactive mode
|
||||||
|
# interactive_mode_row = row.row()
|
||||||
|
# interactive_mode_row.operator(ops_id, text='', icon='ACTION_TWEAK') # SNAP_INCREMENT, ACTION_TWEAK, CON_ACTION, CENTER_ONLY
|
||||||
|
|
||||||
|
|
||||||
col.prop(settings, 'use_animation', text='Animation')
|
col.prop(settings, 'use_animation', text='Animation')
|
||||||
col.prop(settings, 'method', text='Method')
|
col.prop(settings, 'method', text='Method')
|
||||||
|
|
Loading…
Reference in New Issue