simplify occlusion removal code uing native operators

Better UI
master
pullusb 2024-07-24 11:59:35 +02:00
parent cb0ea42e19
commit 071f4fd13b
3 changed files with 40 additions and 42 deletions

View File

@ -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",

View File

@ -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
View File

@ -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')