Skip to content

Instantly share code, notes, and snippets.

@blender8r
Created July 13, 2023 14:58
Show Gist options
  • Select an option

  • Save blender8r/74655fabb002c1e9fbf973174e6372c4 to your computer and use it in GitHub Desktop.

Select an option

Save blender8r/74655fabb002c1e9fbf973174e6372c4 to your computer and use it in GitHub Desktop.
Blender script to add depth of field effect to grease pencil objects
import bpy
from mathutils import Vector
def duplicate(obj, data=True, actions=True, collection=None):
obj_copy = obj.copy()
if data:
obj_copy.data = obj_copy.data.copy()
if actions and obj_copy.animation_data.action:
obj_copy.animation_data.action = obj_copy.animation_data.action.copy()
bpy.context.collection.objects.link(obj_copy)
return obj_copy
def get_distance(pos1, pos2):
vp1 = Vector(pos1)
vp2 = Vector(pos2)
return (vp2 - vp1).length
def get_stroke_position(gp, stroke):
cx, cy, cz = 0.0, 0.0, 0.0
num_pts = 0
for p in stroke.points:
p_local = p.co
p_global = gp.matrix_world @ p_local
cx += p_global[0]
cy += p_global[1]
cz += p_global[2]
num_pts += 1
return (cx/num_pts, cy/num_pts, cz/num_pts)
def distance_to_camera(cam_pos, gp, stroke):
stroke_pos = get_stroke_position(gp, stroke)
distance_to_cam = get_distance(cam_pos, stroke_pos)
return distance_to_cam
def center_origin(gp):
cx, cy, cz = 0.0, 0.0, 0.0
num_strokes = 0
for layer in gp.data.layers:
for frame in layer.frames:
for stroke in frame.strokes:
position = get_stroke_position(gp, stroke)
cx += position[0]
cy += position[1]
cz += position[2]
num_strokes += 1
new_origin = (cx/num_strokes, cy/num_strokes, cz/num_strokes)
gp_origin = gp.matrix_world.translation
offset = (gp_origin[0]-new_origin[0], gp_origin[1]-new_origin[1], gp_origin[2]-new_origin[2])
for layer in gp.data.layers:
for frame in layer.frames:
for stroke in frame.strokes:
for p in stroke.points:
p.co = (p.co[0]+offset[0], p.co[1]+offset[1], p.co[2]+offset[2])
gp.location = (gp.location[0]-offset[0], gp.location[1]-offset[1], gp.location[2]-offset[2])
min_depth = 0
max_depth = 0
step = 2
grease_pencils = []
cameras = []
error = None
sel_objs = bpy.context.selected_objects
if sel_objs:
for sel in sel_objs:
if sel.type == 'GPENCIL':
grease_pencils.append(sel)
elif sel.type == 'CAMERA':
cameras.append(sel)
if grease_pencils and cameras:
if len(cameras) > 1:
error = "More than one camera selected!"
else:
camera = cameras[0]
else:
error = "You must select at least one grease pencil and one camera!"
if error:
print(error)
else:
for gp in grease_pencils:
stroke_distances = []
for layer in gp.data.layers:
for frame in layer.frames:
cam_pos = camera.matrix_world.translation
for stroke in frame.strokes:
stroke_distances.append(distance_to_camera(cam_pos, gp, stroke))
min_depth = min(stroke_distances)
max_depth = max(stroke_distances)
i = min_depth
while i <= max_depth:
gp_dof = duplicate(gp)
for layer in gp_dof.data.layers:
for frame in layer.frames:
for stroke in frame.strokes:
cam_pos = camera.matrix_world.translation
dist = distance_to_camera(cam_pos, gp, stroke)
if dist < i or dist > i + step:
frame.strokes.remove(stroke)
num_strokes = 0
for layer in gp_dof.data.layers:
for frame in layer.frames:
num_strokes += len(frame.strokes)
if num_strokes == 0:
bpy.data.objects.remove(gp_dof)
else:
shader_fx = gp_dof.shader_effects.new('blur', 'FX_BLUR')
shader_fx.use_dof_mode = True
shader_fx.samples = 16
center_origin(gp_dof)
i += step
gp.hide_viewport = True
gp.hide_render = True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment