def test_normals(): isle = create_island(10) height, width, nchan = isle.shape occlusion = np.empty([height, width, 1]) seconds = timeit.timeit( lambda: np.copyto(occlusion, sn.compute_skylight(isle)), number=1) print(f'\ncompute_skylight took {seconds} seconds') normals = np.empty([height - 1, width - 1, 3]) seconds = timeit.timeit( lambda: np.copyto(normals, sn.compute_normals(isle)), number=1) print(f'\ncompute_normals took {seconds} seconds') normals = sn.resize(normals, 750, 512) # Flatten the normals according to landmass versus sea. normals += np.float64([0, 0, 100]) * np.where(isle < 0.0, 1.0, 0.005) normals /= sn.reshape(np.sqrt(np.sum(normals * normals, 2))) # Compute the lambertian diffuse factor lightdir = np.float64([0.2, -0.2, 1]) lightdir /= np.linalg.norm(lightdir) df = np.clip(np.sum(normals * lightdir, 2), 0, 1) df = sn.reshape(df) df *= occlusion # Apply color LUT gradient_image = sn.resize(sn.load(path('terrain.png')), width=1024)[:, :, :3] def applyColorGradient(elevation): xvals = np.arange(1024) yvals = gradient_image[0] apply_lut = interpolate.interp1d(xvals, yvals, axis=0) el = np.clip(1023 * elevation, 0, 1023) return apply_lut(sn.unshape(el)) albedo = applyColorGradient(isle * 0.5 + 0.5) albedo *= df # Visualize the lighting layers normals = 0.5 * (normals + 1.0) isle = np.dstack([isle, isle, isle]) occlusion = np.dstack([occlusion, occlusion, occlusion]) df = np.dstack([df, df, df]) island_strip = sn.resize(sn.hstack([occlusion, normals, df, albedo]), height=256) sn.save(island_strip, 'docs/island_strip.png') sn.show(island_strip)
def create_falloff(w, h, radius=0.4, cx=0.5, cy=0.5): hw, hh = 0.5 / w, 0.5 / h x = np.linspace(hw, 1 - hw, w) y = np.linspace(hh, 1 - hh, h) u, v = np.meshgrid(x, y, sparse=True) d2 = (u-cx)**2 + (v-cy)**2 return 1-snowy.unitize(snowy.reshape(d2))
def test_draw_quad(): w, h = 100, 100 def show(im): snowy.show(snowy.resize(im, height=100, filter=None)) yellow = np.full((w, h, 4), (1, 1, 0, 1)) red = np.full((w, h, 4), (1, 0, 0, 1)) trans_border = np.full((w, h, 4), (0, 0, 1, 0.2)) t = 5 trans_border[t:h - t, t:w - t] *= 0 c0 = create_circle(w, h, 0.3) * yellow * 100000 c1 = create_circle(w, h, 0.07, 0.8, 0.8) * red * 10000 circles = np.clip(c0 + c1 + trans_border, 0, 1) r, g, b, a = circles.swapaxes(0, 2) luma = snowy.reshape(r + g + b) mask = luma != 0.0 sdf = snowy.unitize(np.abs(snowy.generate_sdf(mask))) cpcf = snowy.generate_cpcf(mask) voronoi = snowy.dereference_coords(circles, cpcf) show(voronoi) target = np.full((2000, 4000, 4), (0, 0, 0, 1), dtype=np.float32) seconds = timeit.timeit(lambda: snowy.draw_polygon( target, voronoi, np.array([(-1., -1, 1., 0., 1.), (-.5, +1, 1., 0., 0.), (+.5, +1, 1., 1., 0.), (+1., -1, 1., 1., 1.)])), number=1) show(target) print(seconds)
def test_cpcf(): w, h = 500, 500 def show(im): snowy.show(snowy.resize(im, height=100, filter=None)) yellow = np.full((w, h, 3), (1, 1, 0)) red = np.full((w, h, 3), (1, 0, 0)) blue_border = np.full((w, h, 3), (0, 0, 1)) t = 5 blue_border[t:h - t, t:w - t] *= 0 c0 = create_circle(w, h, 0.3) * yellow * 100000 c1 = create_circle(w, h, 0.07, 0.8, 0.8) * red * 10000 circles = np.clip(c0 + c1 + blue_border, 0, 1) r, g, b = circles.swapaxes(0, 2) luma = snowy.reshape(r + g + b) mask = luma != 0.0 sdf = snowy.unitize(np.abs(snowy.generate_sdf(mask))) cpcf = snowy.generate_cpcf(mask) voronoi = np.empty(circles.shape) np.copyto(voronoi, snowy.dereference_coords(circles, cpcf)) luma = np.dstack([luma, luma, luma]) sdf = np.dstack([sdf, sdf, sdf]) final = np.hstack([circles, luma, sdf, voronoi]) final = snowy.resize(final, height=400) show(final)
def create_circle(w, h, radius=0.4, cx=0.5, cy=0.5): hw, hh = 0.5 / w, 0.5 / h dp = max(hw, hh) x = np.linspace(hw, 1 - hw, w) y = np.linspace(hh, 1 - hh, h) u, v = np.meshgrid(x, y, sparse=True) d2, r2 = (u-cx)**2 + (v-cy)**2, radius**2 result = 1 - smoothstep(radius-dp, radius+dp, np.sqrt(d2)) return snowy.reshape(result)
def test_coords(): h, w = 800, 800 height, width = h, w # Draw seed image cyan = np.full([h, w, 3], np.float64([(27, 56, 80)]) / 200) pink = np.full([h, w, 3], np.float64([175, 111, 127]) / 255) orange = np.full([h, w, 3], np.float64([239, 159, 95]) / 255) yellow = np.full([h, w, 3], np.float64([239, 207, 95]) / 255) colors = np.zeros([h, w, 3]) def max_color(v): return np.maximum(colors, v) def sub_color(v): return colors * (1 - v) colors = max_color(create_circle(w, h, 0.37, [0.4, 0.5]) * cyan) colors = max_color(create_circle(w, h, 0.37, [0.6, 0.4]) * cyan) colors = max_color(create_circle(w, h, 0.27, [0.7, 0.6]) * cyan) colors = sub_color(create_circle(w, h, 0.35, [0.4, 0.5])) colors = sub_color(create_circle(w, h, 0.35, [0.6, 0.4])) colors = sub_color(create_circle(w, h, 0.25, [0.7, 0.6])) colors = max_color(create_circle(w, h, 0.01, [0.4, 0.5]) * orange) colors = max_color(create_circle(w, h, 0.01, [0.6, 0.4]) * pink) colors = max_color(create_circle(w, h, 0.01, [0.7, 0.6]) * yellow) colors = sn.linearize(colors) # Create generalized voronoi luma = sn.reshape(np.sum(colors, 2)) coords = sn.generate_cpcf(luma != 0) voronoi = sn.dereference_cpcf(colors, coords) # Warp the voronoi warpx, warpy = width / 15, height / 15 noise = sn.generate_fBm(width, height, 4, 4, 3) i, j = np.arange(width, dtype='i2'), np.arange(height, dtype='i2') coords = np.dstack(np.meshgrid(i, j, sparse=False)) warpx = warpx * np.cos(noise * math.pi * 2) warpy = warpy * np.sin(noise * math.pi * 2) coords += np.int16(np.dstack([warpx, warpy])) coords[:, :, 0] = np.clip(coords[:, :, 0], 0, width - 1) coords[:, :, 1] = np.clip(coords[:, :, 1], 0, height - 1) warped = sn.dereference_cpcf(voronoi, coords) strip = [sn.resize(i, height=256) for i in (colors, voronoi, warped)] sn.show(sn.hstack(strip))
def create_circle(w, h, radius, center=[0, 5.0, 5]): cx, cy = center hw, hh = 0.5 / w, 0.5 / h dp = max(hw, hh) x = np.linspace(hw, 1 - hw, w) y = np.linspace(hh, 1 - hh, h) u, v = np.meshgrid(x, y, sparse=True) d2, r2 = (u - cx)**2 + (v - cy)**2, radius**2 result = np.where(d2 < r2, 1.0, 0.0) return sn.reshape(result)
border_width=4, border_value=[0.5,0,0]), qualify("xforms.png")) # Test noise generation n = snowy.generate_noise(100, 100, frequency=4, seed=42, wrapx=True) n = np.hstack([n, n]) n = 0.5 + 0.5 * n snowy.show(n) snowy.export(n, qualify('noise.png')) # First try minifying grayscale gibbons = snowy.load(qualify('snowy.jpg')) gibbons = np.swapaxes(gibbons, 0, 2) gibbons = np.swapaxes(gibbons[0], 0, 1) gibbons = snowy.reshape(gibbons) source = snowy.resize(gibbons, height=200) blurry = snowy.blur(source, radius=4.0) diptych_filename = qualify('diptych.png') snowy.export(snowy.hstack([source, blurry]), diptych_filename) optimize(diptych_filename) snowy.show(diptych_filename) # Next try color gibbons = snowy.load(qualify('snowy.jpg')) source = snowy.resize(gibbons, height=200) blurry = snowy.blur(source, radius=4.0) diptych_filename = qualify('diptych.png') snowy.export(snowy.hstack([source, blurry]), diptych_filename) optimize(diptych_filename)
# 1. Create falloff shape. import snowy import numpy as np from functools import reduce from scipy import interpolate width, height = 768, 256 x, y = np.linspace(-1, 1, width), np.linspace(-1, 1, height) u, v = np.meshgrid(x, y, sparse=True) falloff = np.clip(1 - (u * u + v * v), 0, 1) falloff = snowy.reshape(falloff / 2) snowy.show(falloff) # 2. Add layers of gradient noise and scale with falloff. noise = snowy.generate_noise noise = [noise(width, height, 6 * 2**f, int(f)) * 1 / 2**f for f in range(4)] noise = reduce(lambda x, y: x + y, noise) elevation = falloff * (falloff / 2 + noise) elevation = snowy.generate_udf(elevation < 0.1) elevation /= np.amax(elevation) snowy.show(elevation) # 3. Compute ambient occlusion. occlusion = snowy.compute_skylight(elevation) snowy.show(occlusion) # 4. Generate normal map.
def clumpy(cmd): print(f"clumpy {cmd}") result = system(f".release/clumpy {cmd}") if result: raise Exception("clumpy failed") friction = 0.9 spacing = 20 step_size = 2.5 kernel_size = 5 decay = 0.99 nframes = 400 res = 4000, 2000 scalex = 2 scaley = 5 dim = "x".join(map(str, res)) clumpy(f"pendulum_phase {dim} {friction} {scalex} {scaley} field.npy") clumpy(f"bridson_points {dim} {spacing} 0 pts.npy") clumpy( f"advect_points pts.npy field.npy {step_size} {kernel_size} {decay} {nframes} phase.npy" ) im = snowy.reshape(1.0 - np.load("000phase.npy") / 255.0) im = snowy.resize(im, 500, 250) snowy.export(im, "extras/example6.png") snowy.show(im) system("rm *.npy") print("Generated extras/example6.png")
friction = 0.1 clumpy(f'pendulum_phase {dim} {friction} 1 5 field.npy') clumpy(f'bridson_points {dim} {spacing} 0 pts.npy') clumpy('advect_points pts.npy field.npy ' + f'{step_size} {kernel_size} {decay} {nframes} anim1.npy') friction = 0.9 clumpy(f'pendulum_phase {dim} {friction} 1 5 field.npy') clumpy(f'bridson_points {dim} {spacing} 0 pts.npy') clumpy('advect_points pts.npy field.npy ' + f'{step_size} {kernel_size} {decay} {nframes} anim2.npy') import imageio writer = imageio.get_writer('anim.mp4', fps=60) for i in tqdm(range(0, nframes, skip)): im1 = snowy.reshape(np.load("{:03}anim1.npy".format(i))) im1 = snowy.resize(im1, 960 - 6, 1088 - 8) im2 = snowy.reshape(np.load("{:03}anim2.npy".format(i))) im2 = snowy.resize(im2, 960 - 6, 1088 - 8) im = np.uint8(255.0 - snowy.hstack([im1, im2], border_width=4)) writer.append_data(im) writer.close() print('Generated anim.mp4') system('rm *.npy')