Project_2026-01-22_22-17-47
GLSL shader by scry · created 2026-01-23 · 10s loop · 2 passes
This page opens the shader in the ShaderKit browser GLSL editor: edit it live, fork it, or render it to video, GIF or images up to 8K. Also available as a full-screen view and an embeddable player.
Shader source (GLSL)
Common
#define pi acos(-1.)
#define deg pi/180. //1 degree
#define time iTime*2.*pi/10. //sin(time) loops 10 seconds
#define R iResolution.xy //shorthand
#define ar R.x/R.y //aspect ratio
#define M iMouse //shorthand
#define xm (M.xy/R) //normalized mouse
#define nm ((xm.xy-0.5)*vec2(ar,1.)+0.5) //aspect ratio correction
vec3 cs = vec3(1.,2.,3.);
mat2 r2d(float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
Buffer A (iChannel0)
// Reality: Spheres and Light
// Spheres refract light, light shapes perception
// Clusters maintain illusions, awakening reveals truth
#define NUM_SPHERES 2
#define MAX_MARCH_STEPS 64
#define MAX_BOUNCES 4
struct Sphere {
vec3 pos;
float radius;
float ior; // index of refraction
float awakening; // 0 = deluded, 1 = awakened
};
float sphereSDF(vec3 p, Sphere s) {
return length(p - s.pos) - s.radius;
}
vec3 sphereNormal(vec3 p, Sphere s) {
return normalize(p - s.pos);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 p = (uv - 0.5) * vec2(ar, 1.0);
// Initialize spheres in a cluster formation
Sphere spheres[NUM_SPHERES];
float t = iTime * 0.3;
// Central "deluded" cluster - constantly repositioning to maintain illusion
for(int i = 0; i < NUM_SPHERES; i++) {
float fi = float(i);
float angle = fi * 2.0 * pi / float(NUM_SPHERES) + t;
float r = 0.3 + 0.1 * sin(t * 2.0 + fi);
spheres[i].pos = vec3(
cos(angle) * r,
sin(angle) * r,
0.5 + 0.2 * sin(t + fi * 0.7)
);
spheres[i].radius = 0.08 + 0.03 * sin(fi + t);
spheres[i].ior = 1.2 + 0.3 * sin(fi * 1.3);
// One sphere begins awakening
spheres[i].awakening = (i == 0) ? 0.5 + 0.5 * sin(t * 0.5) : 0.0;
}
// Ray from camera
vec3 ro = vec3(0.0, 0.0, -1.5);
vec3 rd = normalize(vec3(p, 1.0));
// Light - eternal, uncreated, passing through
vec3 lightDir = normalize(vec3(sin(t * 0.7), cos(t * 0.5), -1.0));
vec3 col = vec3(0.02, 0.01, 0.03); // void
// Simple raymarching for visualization
for(int i = 0; i < NUM_SPHERES; i++) {
vec3 oc = ro - spheres[i].pos;
float b = dot(oc, rd);
float c = dot(oc, oc) - spheres[i].radius * spheres[i].radius;
float h = b * b - c;
if(h > 0.0) {
float dist = -b - sqrt(h);
float distFar = -b + sqrt(h); // exit point for internal reflections
if(dist > 0.001 && dist < 100.0) {
vec3 hitPos = ro + rd * dist;
vec3 n = sphereNormal(hitPos, spheres[i]);
// Refraction creates the "image" - the illusion
vec3 refracted = refract(rd, n, 1.0 / spheres[i].ior);
float fresnel = pow(1.0 - abs(dot(rd, n)), 3.0);
// Light passing through - never owned, just reflected
float diff = max(dot(n, -lightDir), 0.0);
vec3 reflected = reflect(lightDir, n);
float spec = pow(max(dot(reflected, -rd), 0.0), 32.0);
// Reflection of view ray off surface
vec3 reflectedRayDir = reflect(rd, n);
// Trace reflected ray to find other spheres
vec3 reflectionCol = vec3(0.05, 0.02, 0.08); // default dark reflection
for(int j = 0; j < NUM_SPHERES; j++) {
if(j == i) continue; // skip self
vec3 oc2 = hitPos - spheres[j].pos;
float b2 = dot(oc2, reflectedRayDir);
float c2 = dot(oc2, oc2) - spheres[j].radius * spheres[j].radius;
float h2 = b2 * b2 - c2;
if(h2 > 0.0) {
float dist2 = -b2 - sqrt(h2);
if(dist2 > 0.001) {
vec3 hitPos2 = hitPos + reflectedRayDir * dist2;
vec3 n2 = sphereNormal(hitPos2, spheres[j]);
float diff2 = max(dot(n2, -lightDir), 0.0);
float spec2 = pow(max(dot(reflect(lightDir, n2), -reflectedRayDir), 0.0), 16.0);
reflectionCol = vec3(0.7, 0.5, 0.3) * diff2 + vec3(0.9) * spec2;
}
}
}
// Add environment reflection
float envReflect = 0.5 + 0.5 * dot(reflectedRayDir, vec3(0.0, 1.0, 0.0));
float envReflectX = 0.5 + 0.5 * dot(reflectedRayDir, vec3(1.0, 0.0, 0.0));
reflectionCol += mix(vec3(0.05, 0.02, 0.1), vec3(0.2, 0.3, 0.5), envReflect) * 0.3;
reflectionCol += vec3(0.15, 0.05, 0.1) * envReflectX * 0.3;
// Awakened spheres show their true nature - distinct from light
float aw = spheres[i].awakening;
vec3 illusionCol = vec3(0.8, 0.6, 0.4) * diff + vec3(1.0) * spec * 0.8;
vec3 truthCol = vec3(0.1, 0.2, 0.4) + fresnel * vec3(0.2, 0.1, 0.3);
vec3 baseCol = mix(illusionCol, truthCol, aw);
// Blend reflection more prominently using fresnel
col = mix(baseCol, reflectionCol, fresnel * 0.7) + spec * vec3(1.0, 0.95, 0.9) * 0.5;
}
}
}
// The eternal light field - always present, passing by
col += 0.03 * vec3(0.5 + 0.5 * sin(p.x * 10.0 + t), 0.5 + 0.5 * sin(p.y * 10.0 - t), 0.7);
fragColor = vec4(col, 1.0);
}
Image
Not used
More shaders by scry
- Project_2026-08-15_18-22-06
- Project_2026-08-14_16-45-00
- Project_2026-07-24_15-10-23
- Project_2026-07-15_03-18-26
- Glass of Orange Juice (raymarched)
- Project_2026-07-13_00-53-50
- Project_2026-07-10_16-39-54
- Popcorn ceiling
- Project_2026-06-20_15-32-19
- Project_2026-06-25_12-22-43
- Visual Enhancer
- Project_2026-06-24_11-11-39
Browse all public shaders · All shaders by scry · ShaderKit home
Unread comments
×Projects with new comments. Click to open and read.