#version 430 layout(local_size_x = 8, local_size_y = 8) in; #include #include #include const float MAX_DISTANCE = 1000.; // 1000. const int MAX_ITERATIONS = 800; // 600+ const float MIN_GAP = 0.001; uniform float seconds = 0; layout(rgba8) uniform writeonly image2D output_image; uniform float antialiasing = 0.28; uniform bool enable_antialiasing = false; uniform vec3 camera_position = vec3(0, 0, -3); const int O_SANDWICH_FILL = 1; const int O_SANDWICH_WAFER = 2; float time = seconds * 2; int break_sym = int(int(time) % 40 == 14 || int(time) % 40 == 18 || int(time) % 40 == 36); int break_sym_2 = int(int(time) % 40 == 20 || int(time) % 40 == 3); float sdf_icecream_sandwich(in vec3 p, in bool show_bite, inout int obj_id) { float fill = sdf_box(p, vec3(0.18, 0.04, 0.1), 0.02); float wafernoise = 0.00062 * noise(p * 900); vec3 wafersize = vec3(0.20, 0.016, 0.12) + wafernoise; float wafer = sdf_box(p - vec3(0, 0.056, 0), wafersize, 0.014); wafer = min(wafer, sdf_box(p - vec3(0, -0.056, 0), wafersize, 0.014)); { vec3 dotp = p - vec3(0, -0.07, 0); float gap = 0.07; dotp.xz -= round(dotp.xz / gap) * gap; float dots = sdf_circle(dotp, 0.006); wafer = max(wafer, -dots); } { vec3 dotp = p - vec3(0, 0.07, 0); float gap = 0.07; dotp.xz -= round(dotp.xz / gap) * gap; float dots = sdf_circle(dotp, 0.006); wafer = max(wafer, -dots); } if (show_bite) { vec3 teethp = p - vec3(-0.19, -0.07, -0.11); float theta = atan(teethp.z, teethp.x); float biteradius = 0.08 + 0.003 * sin(theta * 18); fill = max(fill, -sdf_capsule(teethp, 0.12, biteradius)); wafer = max(wafer, -sdf_capsule(teethp, 0.12, biteradius + 8.0 * wafernoise)); } float dist = min(fill, wafer); if (dist == wafer) obj_id = O_SANDWICH_WAFER; else obj_id = O_SANDWICH_FILL; return dist; } void rotate_all_axes(inout vec3 p, float theta) { mat2x2 rot = mat2x2(cos(theta), -sin(theta), sin(theta), cos(theta)); p.xy *= rot; p.yz *= rot; p.xz *= rot; } float scene(in vec3 p, out int obj_id) { float sw; int sw_id; float rotation_time = seconds; { vec3 swp = p; { float theta = rotation_time / 26 + 0.3 * break_sym + 0.17 * break_sym_2; swp.xy *= mat2x2(cos(theta), -sin(theta), sin(theta), cos(theta)); } vec2 p1rot, p2rot; float id = rotational_repetition(swp.xy, 20, p1rot, p2rot); int odd = int(id) % 2; vec3 offset = vec3(3.5 - 0.06 * odd * break_sym, 0, 4.5); float theta = -rotation_time / 6 + 0.1 + 0.5 * break_sym; int sw1_id, sw2_id; vec3 p1 = vec3(p1rot, swp.z) - offset; vec3 p2 = vec3(p2rot, swp.z) - offset; rotate_all_axes(p1, theta); rotate_all_axes(p2, theta); float b1 = sdf_icecream_sandwich(p1, bool(break_sym), sw1_id); float b2 = sdf_icecream_sandwich(p2, bool(break_sym), sw2_id); sw = min(b1, b2); if (sw == b1) sw_id = sw1_id; else if (sw == b2) sw_id = sw2_id; } { vec3 swp = p; { float theta = rotation_time / 20 + 0.3 * break_sym; swp.xy *= mat2x2(cos(theta), -sin(theta), sin(theta), cos(theta)); } vec2 p1rot, p2rot; float id = rotational_repetition(swp.xy, 20, p1rot, p2rot); int odd = int(id) % 2; vec3 offset = vec3(1 - 0.06 * odd * break_sym, 0, 0); float theta = rotation_time / 4 + 0.3 * break_sym; int sw1_id, sw2_id; vec3 p1 = vec3(p1rot, swp.z) - offset; vec3 p2 = vec3(p2rot, swp.z) - offset; rotate_all_axes(p1, theta); rotate_all_axes(p2, theta); float b1 = sdf_icecream_sandwich(p1, bool(break_sym), sw1_id); float b2 = sdf_icecream_sandwich(p2, bool(break_sym), sw2_id); sw = min(sw, min(b1, b2)); if (sw == b1) sw_id = sw1_id; else if (sw == b2) sw_id = sw2_id; } { vec3 swp = p - vec3(0, 0, 0.5); { float theta = rotation_time / 12 + 0.3 * break_sym; swp.xy *= mat2x2(cos(theta), -sin(theta), sin(theta), cos(theta)); } vec2 p1rot, p2rot; float id = rotational_repetition(swp.xy, 36, p1rot, p2rot); int odd = int(id) % 2; vec3 offset = vec3(0.8 - 0.06 * odd * break_sym, 0, 0); float theta = -rotation_time / 5 + 0.3 + 0.3 * break_sym; int sw1_id, sw2_id; vec3 p1 = vec3(p1rot, swp.z) - offset; vec3 p2 = vec3(p2rot, swp.z) - offset; rotate_all_axes(p1, theta); rotate_all_axes(p2, theta); float b1 = sdf_icecream_sandwich(p1, bool(break_sym), sw1_id); float b2 = sdf_icecream_sandwich(p2, bool(break_sym), sw2_id); sw = min(sw, min(b1, b2)); if (sw == b1) sw_id = sw1_id; else if (sw == b2) sw_id = sw2_id; } { vec3 sp = p * 0.8 - vec3(0, 0, -1); sp.yz *= mat2x2(cos(0.42), -sin(0.42), sin(0.42), cos(0.42)); sp.xz *= mat2x2(cos(-0.42), -sin(-0.42), sin(-0.42), cos(-0.42)); int sw1_id; float sando = sdf_icecream_sandwich(sp, true, sw1_id); sw = min(sw, sando); if (sw == sando) sw_id = sw1_id; } float dist = sw; if (dist == sw) obj_id = sw_id; return dist; } void apply_material( in int obj_id, in float dist, inout vec3 color, inout float ambient, inout float shine ) { if (obj_id == O_SANDWICH_FILL) { color = srgb(1); shine = 2.0; } else if (obj_id == O_SANDWICH_WAFER) { color = srgb(0.44, 0.27, 0.17); shine = 0.06; } } float raymarch_scene(vec3 ray_origin, vec3 ray_direction, out int obj_id) { float dist = 0.; for (int i = 0; i < MAX_ITERATIONS && dist <= MAX_DISTANCE; i++) { vec3 p = ray_origin + ray_direction * dist; float gap = scene(p, obj_id); dist += gap; if (gap <= MIN_GAP) return dist; } obj_id = -1; return dist; } vec3 surface_normal_scene(in vec3 p) { vec2 e = vec2(MIN_GAP, 0); int obj_id; return normalize(vec3( scene(p + e.xyy, obj_id) - scene(p - e.xyy, obj_id), scene(p + e.yxy, obj_id) - scene(p - e.yxy, obj_id), scene(p + e.yyx, obj_id) - scene(p - e.yyx, obj_id))); } vec3 image(vec2 uv) { vec3 campos = camera_position; vec3 uv_direction = normalize(vec3(uv, 1)); int obj_id = 0; float dist = raymarch_scene(campos, uv_direction, obj_id); vec3 p = campos + uv_direction * dist; vec3 norm = surface_normal_scene(p); vec3 light = vec3(6, 8, -20); vec3 light_dir = normalize(light - p); vec3 c1 = srgb(0.74, 0.93, 0.80); vec3 c2 = srgb(0.98, 0.75, 0.83); vec3 c3 = srgb(0.59, 0.88, 0.94); vec3 c4 = srgb(0.98, 0.78, 0.51); vec2 patp = uv * 30; float pat = sin(patp.x) * cos(patp.y - time) - sin(3 * patp.x) - cos(3 * patp.y); vec3 bg_color = c1; bg_color = mix(bg_color, c2, step(pat, 1.0)); bg_color = mix(bg_color, c3, step(pat, 0)); bg_color = mix(bg_color, c4, step(pat, -1.0)); bg_color = mix(bg_color, srgb(0.8, 0, 0), 0.25 * break_sym); vec3 color = bg_color; float ambient = 0.05; float shine = 1.; apply_material(obj_id, dist, color, ambient, shine); if (obj_id > 0) { float contrast = clamp(dot(norm, light_dir), 0, 1); color *= clamp((1 - ambient) * contrast + ambient, 0, 1); vec3 hal = normalize(light_dir - uv_direction); float spec = pow(clamp(dot(norm, hal), 0.0, 1.0), 16.0) * contrast * (0.04 + 0.96 * pow(clamp(1.0 + dot(hal, uv_direction), 0.0, 1.0), 5.0)); color += shine * 10. * spec * vec3(1.00, 0.70, 0.5); } return color; } vec3 antialiased_image(vec2 uv) { vec2 resolution = vec2(imageSize(output_image).xy); float s = antialiasing / max(resolution.x, resolution.y); vec3 sum = vec3(0); int count = 0; for (int i = -2; i < 2; i++) for (int j = -2; j < 2; j++, count++) sum += image(uv + vec2(i, j) * s); return sum / count; } void main() { vec2 resolution = vec2(imageSize(output_image).xy); float aspect_ratio = resolution.y / resolution.x; vec2 uv = (gl_GlobalInvocationID.xy - resolution / 2) * vec2(1.0, aspect_ratio) / resolution; vec3 color = enable_antialiasing ? antialiased_image(uv) : image(uv); float t = time; vec2 offset = vec2(mod(t * sin(t * 8 + fbm(vec2(t)) * 0.5), 0.02), 0); if (break_sym == 1) { color.r = (color.r + image(uv + offset).r + image(uv - offset).r) / 3.; color.g = (color.g + image(uv + vec2(offset.y, offset.x)).g + image(uv + offset).g) / 3.; color.b = (color.b + image(uv + vec2(offset.y, offset.x)).b + image(uv - offset).b) / 3.; } color = clamp(color, 0, 1); imageStore(output_image, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1)); }