Skip to content

Instantly share code, notes, and snippets.

@blender8r
Created November 10, 2022 13:14
Show Gist options
  • Select an option

  • Save blender8r/92a5b9fa3d5f1b9fdfe5e0039fe4766b to your computer and use it in GitHub Desktop.

Select an option

Save blender8r/92a5b9fa3d5f1b9fdfe5e0039fe4766b to your computer and use it in GitHub Desktop.
import bpy
from math import tau, pi, sin, cos, ceil
import random
import time
t = time.perf_counter()
num_points = 48
center = (0.0, 0.0, 0.0)
num_rings = 3
num_leading = 2
num_trailing = 1
steps_per_ring = 6
num_peaks = num_rings + num_leading + num_trailing
total_num_rings = num_peaks * steps_per_ring
wave_compression = 0.3
taper_strength = 0.6
optimize_threshold = 0.025
sharpness = 4.0
strength_min = 0.0
strength_max = 0.75
angle = pi + (pi/2)
angle_step = (tau * num_peaks) / total_num_rings
peak_color = (1.0, 1.0, 1.0, 1.0) #RGBA
start_frame = 1
duration = 100
fade_duration = 100
speed = 0.14
fps = 24
rate = speed / fps
def get_frame(frames, frame_num):
'''Checks for the existence of a given frame'''
frame = None
for item in frames:
if item.frame_number == frame_num:
frame = item
break
return frame
def norm(value, min, max):
return (value - min) / (max - min)
def remap(value, min1, max1, min2, max2):
return (value-min1) / (max1-min1) * (max2-min2) + min2
def ellipse(gp_frame, center, radius_x, radius_z, num_points, line_thickness):
gp_stroke = gp_frame.strokes.new()
gp_stroke.line_width = line_thickness
gp_stroke.use_cyclic = True
gp_stroke.points.add(count=num_points)
step = tau / num_points
for i in range(num_points):
angle = i * step
x = center[0] + (radius_x * cos(angle))
y = 0
z = center[2] + (radius_z* sin(angle))
gp_stroke.points[i].co = (x, y, z)
return gp_stroke
def set_ring_color(stroke, color=(1.0, 1.0, 1.0, 1.0), strength=1.0):
for p in stroke.points:
p.strength = strength
p.vertex_color = color
def build_rings(gp_frame, center, size, num_rings, num_leading, num_trailing, ring_spacing, angle, opacity):
final_rings = 0
for r in range(1, total_num_rings + 1):
r_norm = norm(r, 0, total_num_rings)
wc = r_norm ** wave_compression
if size <= 0:
break
else:
line_thickness = ceil(((ring_spacing * wc) / steps_per_ring) * 1000)
strength = remap(sin(angle), -1.0, 1.0, strength_min, strength_max)
if strength != 0:
strength = strength ** sharpness
# fade strength for leading edge
if r < num_leading * steps_per_ring:
strength = strength * (r_norm ** taper_strength)
if r > (num_rings + num_trailing) * steps_per_ring:
strength = strength * (1 - (r_norm ** (1 / taper_strength)))
strength *= opacity
if strength > optimize_threshold:
circle = ellipse(gp_frame, center, size, size, num_points, line_thickness)
set_ring_color(circle, peak_color, strength)
final_rings += 1
size = size - ((ring_spacing * wc) / steps_per_ring)
angle = angle + angle_step
return final_rings
def make_ripple(gp_layer, center, num_rings, num_leading, num_trailing, sharpness, start_frame,
duration, fade_duration):
ring_size = 0.0
ring_spacing = 0.03
opacity = 1.0
opacity_power = 2
rings_built = total_num_rings
for frame in gp_layer.frames:
gp_layer.frames.remove(frame)
for f in range(start_frame, (start_frame + duration + fade_duration)):
if f < bpy.context.scene.frame_end:
if rings_built > 0:
gp_frame = get_frame(gp_layer.frames, f)
gp_frame = gp_layer.frames.new(f)
if f >= start_frame + duration:
f_norm = norm(f, (start_frame + duration), (start_frame + duration + fade_duration))
opacity = opacity * (1 - (f_norm ** opacity_power))
rings_built = build_rings(gp_frame, center, ring_size, num_rings, num_leading, num_trailing,
ring_spacing, angle, opacity)
if (f < start_frame + 5) and (rings_built == 0):
rings_built = 1
ring_size += rate
num_rings = 0
sel_obj = None
sel_objs = bpy.context.selected_objects
if sel_objs:
sel_obj = sel_objs[0]
if sel_obj and sel_obj.type=='GPENCIL':
sel_obj.data.materials.clear()
gpencil = sel_obj.data
gpencil.stroke_thickness_space = 'WORLDSPACE'
for layer in gpencil.layers:
gpencil.layers.remove(layer)
num_ripples = 100
random.seed(60)
for r in range(num_ripples):
x = random.uniform(-2.0, 2.0)
z = random.uniform(-2.0, 2.0)
start_frame = random.randrange(1, 500)
duration = random.randrange(5, 20)
fade_duration = random.randrange(30, 100)
layer_name = "ripple%s" % str(r)
gp_layer = gpencil.layers.new(layer_name, set_active=True)
make_ripple(gp_layer, (x, 0.0, z), num_rings, num_leading, num_trailing, sharpness, start_frame,
duration, fade_duration)
for layer in gpencil.layers:
for frame in layer.frames:
num_rings += len(frame.strokes)
print("Num rings: ", num_rings)
print("Runtime: ", time.perf_counter() - t)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment