parent
cb0ea42e19
commit
071f4fd13b
|
@ -1,7 +1,7 @@
|
|||
bl_info = {
|
||||
"name": "gp interpolate",
|
||||
"name": "GP Interpolate",
|
||||
"author": "Christophe Seux, Samuel Bernou",
|
||||
"version": (0, 8, 1),
|
||||
"version": (0, 8, 2),
|
||||
"blender": (4, 0, 2),
|
||||
"location": "Sidebar > Gpencil Tab > Interpolate",
|
||||
"description": "Interpolate Grease pencil strokes over 3D",
|
||||
|
|
|
@ -158,7 +158,6 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
|||
if obj:
|
||||
object_hit, hit_location, tri, tri_indices = obj_ray_cast(obj, square_co, origin, dg)
|
||||
else:
|
||||
# scene raycast
|
||||
object_hit, hit_location, tri, tri_indices = ray_cast_point(square_co, origin, dg)
|
||||
|
||||
if object_hit:
|
||||
|
@ -228,7 +227,6 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
|||
elif self.settings.method == 'GEOMETRY':
|
||||
if col != context.scene.collection:
|
||||
included_cols.append(col.name)
|
||||
## Maybe include a plane just behind geo ? probably bad idea
|
||||
|
||||
elif self.settings.method == '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)
|
||||
intercol.hide_viewport = vl_col.exclude = vl_col.hide_viewport = False
|
||||
|
||||
# Override collection
|
||||
## Override collection
|
||||
col = intercol
|
||||
|
||||
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
|
||||
|
||||
if target_obj:
|
||||
## Object raycast
|
||||
object_hit, hit_location, tri, tri_indices = obj_ray_cast(target_obj, point_co_world, origin, dg)
|
||||
else:
|
||||
# scene raycast
|
||||
## Scene raycast
|
||||
object_hit, hit_location, tri, tri_indices = ray_cast_point(point_co_world, origin, dg)
|
||||
|
||||
## Iterative increasing search range when no surface hit
|
||||
|
@ -342,10 +341,13 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
|||
mesh=True)
|
||||
|
||||
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 = 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(list(new_strokes), list(self.strokes_data)):
|
||||
world_co_3d = []
|
||||
|
@ -364,39 +366,27 @@ class GP_OT_interpolate_stroke(GP_OT_interpolate_stroke_base):
|
|||
|
||||
## Occlusion management
|
||||
if self.settings.method == 'GEOMETRY' and self.settings.remove_occluded:
|
||||
viz_list = [True]*len(world_co_3d)
|
||||
for i, nco in enumerate(world_co_3d):
|
||||
vec_direction = nco - origin
|
||||
## Reduced distance slightly to avoid occlusion on same source...
|
||||
dist = vec_direction.length - 0.001
|
||||
n_hit, _, _, _, _, _ = scn.ray_cast(dg, origin, vec_direction, distance=dist)
|
||||
# If there is a hit, it's occluded
|
||||
for i, point in enumerate(new_stroke.points):
|
||||
point_co = world_co_3d[i]
|
||||
vec_direction = point_co - origin
|
||||
## Raycast with slightly reduced distance (avoid occlusion on same source)
|
||||
n_hit, _, _, _, _, _ = scn.ray_cast(dg, origin, vec_direction, distance=vec_direction.length - 0.001)
|
||||
if n_hit:
|
||||
viz_list[i] = False
|
||||
occluded_points.append(point)
|
||||
|
||||
if all(viz_list):
|
||||
# All visible, do nothing (just keep previous stroke)
|
||||
continue
|
||||
|
||||
if any(viz_list):
|
||||
# Create sub-strokes according to indices in original stroke
|
||||
for sublist in index_list_from_bools(viz_list):
|
||||
## 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)
|
||||
if occluded_points:
|
||||
## Select only occluded point
|
||||
bpy.ops.gpencil.select_all(action='DESELECT')
|
||||
for point in occluded_points:
|
||||
point.select = True
|
||||
## remove points
|
||||
bpy.ops.gpencil.delete(type='POINTS')
|
||||
|
||||
## 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
|
||||
if self.loop_count >= len(self.frames_to_jump):
|
||||
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.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
col = layout.column(align=False)
|
||||
|
||||
## 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}'
|
||||
|
||||
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"
|
||||
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=prev_text, icon=prev_icon).next = False
|
||||
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, 'method', text='Method')
|
||||
|
|
Loading…
Reference in New Issue