From b04c4008e73d1515d1f78f993ca25826847d7207 Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Thu, 1 Oct 2026 15:00:35 +0530 Subject: Add time --- src/main/resources/shaders/time.glsl | 147 +++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/main/resources/shaders/time.glsl (limited to 'src/main/resources/shaders/time.glsl') diff --git a/src/main/resources/shaders/time.glsl b/src/main/resources/shaders/time.glsl new file mode 100644 index 0000000..1c22e12 --- /dev/null +++ b/src/main/resources/shaders/time.glsl @@ -0,0 +1,147 @@ +#version 430 +layout(local_size_x = 1, local_size_y = 1) in; + +#include +#include +#include + +#define PI 3.14159265358979323 + +uniform float hours = 0; +uniform float minutes = 0; +uniform float seconds = 0; +uniform float time = 0; +layout(rgba8) uniform readonly image2D noise_texture; +layout(rgba8) uniform readonly image2D text_texture; +layout(rgba8) uniform writeonly image2D output_image; + +uniform float antialiasing = 0.28; +uniform bool enable_antialiasing = false; + +float sample_noise(in vec2 p) { + vec4 noise = imageLoad(noise_texture, ivec2((p + 0.5) * imageSize(noise_texture))); + return noise.x; +} + +float blink_easing(in float x) { + return x < 0.5 ? 8 * x * x * x * x : 1 - pow(-2 * x + 2, 4) / 2; +} + +float digit(in vec2 uv, in int digit, in float size) { + vec2 p = uv * 5000 / size; + float digitSize = imageSize(text_texture).x / 10.; + float digitOffset = digitSize * digit; + p.x = clamp(p.x + digitOffset, digitOffset, digitOffset + digitSize); + vec4 s = imageLoad(text_texture, ivec2(p)); + return s.w; +} + +vec3 image(in vec2 uv) { + const vec3 eye_color = srgb(1, 1, 1); + const vec3 iris_color = srgb(0.2, 0.1, 0.1); + const vec3 pupil_color = srgb(0, 0, 0); + const vec3 skin_color = srgb(0.14, 0.03, 0.14); + // const vec3 skin_color = mix(srgb(0.94, 0.75, 0.65), vec3(0), 0.9); + const vec3 bloodvessel_color = srgb(0.89, 0.12, 0.06); + const vec3 clockdigit_color = mix(bloodvessel_color, vec3(0), 0.1); + + vec3 color = bloodvessel_color; + + { + float eye = sdf_circle(uv, 0.41 * (1 - 0.08 * fbm(100 * uv))); + vec3 eyeball_color = eye_color; + float veins = sin((uv.y + 1) * 260 * sin((uv.x + 1) * 0.1) * fbm(uv * 20)) + 0.98; + eyeball_color = mix(eyeball_color, bloodvessel_color, mix(0, step(veins, 0), clamp(sample_noise(uv) - 0.1, 0, 1))); + eyeball_color = mix(eyeball_color, vec3(0), (0.2 - uv.x) * (1.3 - uv.y)); + color = mix(color, eyeball_color, step(eye, 0)); + } + + { + float iris = sdf_circle(uv, 0.144); + color = mix(color, iris_color, step(iris, 0)); + float angle = 50 * (atan(uv.y, uv.x)) + 10.0 * fbm(uv * 100); + float irispat = max(iris, sin(angle)); + color = mix(color, vec3(0), 0.6 * step(irispat, 0)); + } + + { + float angle = PI / 2 - hours * PI / 6 - minutes * PI / (12 * 60); + vec2 offset = 0.10 * vec2(cos(angle), sin(angle)); + float iris_spec = sdf_circle((uv - offset) * vec2(0.8, 1.0), 0.010); + color = mix(color, vec3(1), step(iris_spec, 0)); + } + { + float angle = PI / 2 - minutes * PI / 30; + vec2 offset = 0.148 * vec2(cos(angle), sin(angle)); + float iris_spec = sdf_circle(uv - offset, 0.005); + color = mix(color, iris_color, step(iris_spec, 0)); + } + + { + float pupil = sdf_circle(uv, 0.04); + color = mix(color, pupil_color, step(pupil, 0)); + } + + { + // TODO: Switch to domain repetition + for (int i = 0; i < 12; i++) { + float theta = PI / 6.; + float r = 0.17; + vec2 digitpos = uv + vec2(0.011, 0.034) - r * vec2(cos(-i * theta + PI / 3), sin(-i * theta + PI / 3)); + digitpos *= (1 + 0.8 * fbm(60 * uv)); + float digit_size = 1.6; + float s = 0; + if (i + 1 >= 10) { + s = digit(digitpos + vec2(0.01, 0), 1, digit_size); + digitpos.x -= 0.01; + } + s = max(s, digit(digitpos, (i + 1) % 10, digit_size)); + color = mix(color, clockdigit_color, s); + } + } + + float eye_open_factor = 0.092; + float eyehole_factor = 0.136; + float eyelid_size = 4; + vec2 eyep = uv; + { + float blinkduration = 0.6; + float blink_every = 8; + float blinkt = mod(time, blink_every) * 2 / blinkduration; + int should_blink = int(mod(time, blink_every) < blinkduration); + float blink = blink_easing(mod(blinkt, 1)); + blink = mix(1 - blink, blink, clamp(int(blinkt) % 2, 0., 1.)); + float a = mix(0, eye_open_factor, mix(1, blink, should_blink)); + float eyelid = a * cos(eyelid_size * eyep.x / 2 * PI) - abs(eyep.y) + a; + float eyehole = eyehole_factor * cos((eyelid_size / 1.16) * eyep.x / 2 * PI) - abs(eyep.y) + eyehole_factor; + vec3 eyelid_color = skin_color; + vec3 patterning = mix(srgb(1, 0, 0), srgb(1, 0.46, 0), pow(sin(eyep.x * 16 + 100 * fbm(vec3(uv * 10, time / 20), 3)), 2)); + float patnoise = smoothstep(-eyelid, 0, 0.028 * fbm(uv * 100)); + eyelid_color = mix(eyelid_color, patterning, 1 - clamp(patnoise, 0, 1)); + eyelid_color = mix(eyelid_color, vec3(0), 1 - step(eyelid + 0.004, 0)); + color = mix(color, eyelid_color, step(eyelid, 0)); + } + + 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); + + imageStore(output_image, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1)); +} -- cgit v1.3.1