#version 450 layout(location = 0) in vec2 uv; layout(location = 0) out vec4 out_color; layout(set = 2, binding = 0) uniform sampler2D screen; layout(set = 2, binding = 1) uniform sampler2D depth_tex; layout(std140, set = 3, binding = 0) uniform UniformBlock { mat4 model; mat4 view; mat4 projection; mat4 inv_view; mat4 inv_projection; vec4 time_padded; vec4 cam_pos; }; const int MAX_MARCH_STEPS = 64; const float EPS_DIST = 1e-6; float sdf(vec3 point){ float t = 1.0 + 5.0*abs(sin(time_padded.x)); vec3 s1_local = mod(point, vec3(t)) - vec3(t/2.0); float s1 = length(s1_local) - 0.3; return s1; } vec3 getnormal(vec3 p) { float e = EPS_DIST; return normalize(vec3( sdf(p + vec3(e, 0.0, 0.0)) - sdf(p - vec3(e, 0.0, 0.0)), sdf(p + vec3(0.0, e, 0.0)) - sdf(p - vec3(0.0, e, 0.0)), sdf(p + vec3(0.0, 0.0, e)) - sdf(p - vec3(0.0, 0.0, e)) )); } vec4 march(vec3 point, vec3 ray, float max_depth) { float totaldist = 0.0; int i; for (i = 0; i < MAX_MARCH_STEPS && totaldist < max_depth; i += 1) { float h = sdf(point); point += h * ray; if (h + totaldist > max_depth) break; if (h < EPS_DIST) { return vec4(point, totaldist + h); } totaldist += h; } return vec4(-1.0); } vec3 camray() { vec2 ndc = uv * 2.0 - 1.0; ndc.y = -ndc.y; vec4 view_pos = inv_projection * vec4(ndc, 1.0, 1.0); view_pos /= view_pos.w; return normalize((inv_view * vec4(normalize(view_pos.xyz), 0.0)).xyz); } vec4 kernel(float max_depth) { max_depth = (max_depth > 0.0)? max_depth : 1000.0; vec3 cam_ray = camray(); return march(cam_pos.xyz, cam_ray, max_depth); } float t(float x, float y) { return length(texture(screen, vec2(x, y)).xyz); } float linearize_depth(vec2 uv) { float d = texture(depth_tex, uv).r; if (d >= 1.0) return 1000.0; vec4 ndc = vec4((uv * 2.0 - 1.0), d * 2.0 - 1.0, 1.0); vec4 view_pos = inv_projection * ndc; view_pos /= view_pos.w; return -view_pos.z; // view space, positive distance } float brightness(vec3 color) { return dot(color, vec3(0.299, 0.587, 0.114)); } float dither() { if(length(texture(screen, uv).xyz) == 0.0) return 0.0; vec2 coord = uv * textureSize(screen, 0).xy; int x = int(mod(coord.x, 4.0)); int y = int(mod(coord.y, 4.0)); int index = x + y * 4; float threshold[16] = float[]( 0.0/16.0, 8.0/16.0, 2.0/16.0, 10.0/16.0, 12.0/16.0, 4.0/16.0, 14.0/16.0, 6.0/16.0, 3.0/16.0, 11.0/16.0, 1.0/16.0, 9.0/16.0, 15.0/16.0,7.0/16.0, 13.0/16.0, 5.0/16.0 ); vec3 color = texture(screen, uv).rgb; return brightness(color) < threshold[index] ? 0.0 : 1.0; } void main() { float max_depth = linearize_depth(uv); vec4 hit = kernel(max_depth); if (hit.w > 0.0) { out_color = vec4(getnormal(hit.xyz), 1.0); } else { int t = int(fract(time_padded.x/5.0) * 30.0)/10; switch(t) { case 0: out_color = texture(screen, uv); break; case 1: out_color = vec4(brightness(texture(screen, uv).xyz) < 0.5? 0.0 : 1.0); break; case 2: out_color = vec4(dither()); break; } } }