// Debug view: the fish silhouette alone, on flat grey, big enough to judge the // geometry. Not part of the pages; build with // python3 build_plasma.py 6_ice_plasma.frag debug_fish.frag debug_fish.html precision highp float; uniform vec2 u_res; uniform float u_time; float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); } float smin(float a, float b, float k) { float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0); return mix(b, a, h) - k * h * (1.0 - h); } float sdCapsule(vec2 p, vec2 a, vec2 b, float r) { vec2 pa = p - a, ba = b - a; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); return length(pa - ba * h) - r; } float sdTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) { vec2 e0 = p1 - p0, e1 = p2 - p1, e2 = p0 - p2; vec2 v0 = p - p0, v1 = p - p1, v2 = p - p2; vec2 q0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 q1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 q2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); float s = sign(e0.x * e2.y - e0.y * e2.x); vec2 d = min(min(vec2(dot(q0, q0), s * (v0.x * e0.y - v0.y * e0.x)), vec2(dot(q1, q1), s * (v1.x * e1.y - v1.y * e1.x))), vec2(dot(q2, q2), s * (v2.x * e2.y - v2.y * e2.x))); return -sqrt(d.x) * sign(d.y); } // Half-height of the outline at x: pointed nose, deepest just behind the head, // a narrow peduncle, then the tail fan opening toward the rear. One function, so // the whole animal is guaranteed to be one connected shape. // Half-height of the body at x: pointed nose, deepest a quarter of the way back, // then down to a narrow peduncle. Sweeping a circle along it keeps the body one piece. float fishWidth(float x) { float t = clamp((1.15 - x) / 2.30, 0.0, 1.0); // 0 at the nose, 1 at the peduncle return 0.34 * pow(sin(3.14159 * pow(t, 0.55)), 0.8) + 0.05 * smoothstep(0.70, 1.0, t); } float sdFish(vec2 p) { float d = length(vec2(max(abs(p.x) - 1.15, 0.0), p.y)) - fishWidth(p.x); // body // tail: two lobes fanning back from the peduncle, with a notch between them d = smin(d, sdTriangle(p, vec2(-1.02, 0.03), vec2(-1.62, 0.09), vec2(-1.46, 0.52)), 0.08); d = smin(d, sdTriangle(p, vec2(-1.02, -0.03), vec2(-1.62, -0.09), vec2(-1.46, -0.52)), 0.08); // dorsal and pectoral fins d = smin(d, sdTriangle(p, vec2(0.22, 0.20), vec2(-0.06, 0.46), vec2(-0.40, 0.16)), 0.05); d = smin(d, sdTriangle(p, vec2(0.46, -0.16), vec2(0.26, -0.08), vec2(0.10, -0.28)), 0.04); return d; } void main() { vec2 p = (gl_FragCoord.xy - 0.5 * u_res) / u_res.y * 3.0; vec3 col = vec3(0.16, 0.17, 0.18); for (int i = 0; i < 3; i++) { float id = float(i); float size = mix(1.15, 0.28, id / 2.0); vec2 at = vec2(0.0, 0.75 - 0.72 * id); float d = sdFish((p - at) / size); col = mix(col, vec3(0.01), clamp(0.5 - d / (0.005 / size), 0.0, 1.0)); } gl_FragColor = vec4(col, 1.0); }