Project_2026-03-04_16-16-28
GLSL shader by scry · created 2026-03-05 · updated 2026-03-06 · 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.
#define time iTime*2.*pi/10.
#define R iResolution.xy
#define ar R.x/R.y
vec3 cs = vec3(1.,2.,3.);
mat2 r2d(float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
// Convert Cartesian to log-spherical coordinates
// Returns vec3(log(r), theta, phi)
vec3 toLogSpherical(vec3 p) {
float r = length(p);
float theta = atan(p.y, p.x);
float phi = acos(p.z / (r + 0.0001));
return vec3(log(r + 0.0001), theta, phi);
}
// Convert log-spherical back to Cartesian
vec3 fromLogSpherical(vec3 ls) {
float r = exp(ls.x);
float theta = ls.y;
float phi = ls.z;
return vec3(
r * sin(phi) * cos(theta),
r * sin(phi) * sin(theta),
r * cos(phi)
);
}
// Adjust distance field for log-spherical space
float adjustDistanceLogSpherical(float d, vec3 p) {
return d * length(p);
}
// SDF Box
float sdBox(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
Buffer A (iChannel0)
vec4 map(vec3 p) {
p.y -= .5;
p.zy *= r2d(sin(time*0.5)*0.45+deg*-20.);
p.xz *= r2d(time*0.25+deg*45.);
vec3 sp = (fract(p-0.)-0.5);
//p.zy *= r2d(time);//at this angle it disappears, at 5.7 its fine
p.y *= 2.;
//p.xz *= r2d(deg*45.);
//p.yx *= r2d(time);
// Log-space tiling density
// scaleRatio = how much bigger each shell is than the next.
// 4.0 means each smaller box fits in 1/4 the size of the previous.
float scaleRatio = 1.6;
// s is derived so that each tile boundary corresponds to exactly scaleRatio
float rs = log(scaleRatio); // tiling period in log-space
float s = 1.0 / rs; // density = tiles per unit in log-space
// xzScale: independent scaling ratio for XZ per shell.
// 1.0 = XZ shrinks at same rate as Y shells.
// >1.0 = XZ shrinks faster (boxes get proportionally narrower).
// <1.0 = XZ shrinks slower (boxes get proportionally wider).
// e.g. 0.5 means XZ only shrinks by sqrt(scaleRatio) per shell
// 2.0 means XZ shrinks by scaleRatio^2 per shell
float xzScale = 1.66;
float stime = -time*1.4962;
// Only render for p.y < 0 (bottom half); return large distance for top
//if (p.y > 0.0) return vec4(0.0, 0.0, 0.0, 10.0);
if (p.y > 1.5) {return vec4(vec3(-1.),length(sp)-0.1);}
if (p.y > 0.) {return vec4(0.,0.,0.,5.);}
float ly = log(-p.y + 0.0001)/(1.+s*0.2);
// Animate: shift in log-space = zoom in linear space
ly += stime;
// Apply ySpacing to the tiling density, not to ly itself.
// Tile index using the modified density
float si = floor(ly * s - 0.5) - stime * s;
// Local coordinate within tile
float localY = (fract(ly * s - 0.5) - 0.5) * rs;
// tileScale: the linear-space radius at the center of this tile.
// Each tile spans rs in log-space, so the scale factor per tile
// is exp(rs) = scaleRatio, and the center of tile si is at exp((si+0.5)*rs).
float yTileScale = exp((si + 0.5) * rs);
// XZ scale per shell: independent from Y tiling.
// xzTileScale shrinks XZ by scaleRatio^xzScale per shell.
float xzTileScale = exp((si + 0.5) * rs * xzScale);
// Build the local-space point:
// localY is already in log-tile space, p.xz need to be divided by tileScale
// so the box has consistent proportions across shells
// No sign flip needed — we're only in the p.y < 0 region
vec3 lp = vec3(p.x / xzTileScale, localY, p.z / xzTileScale);
for (int i=0;i<3;i++) {
lp = abs(lp)-0.056;
}
float d = sdBox(lp, vec3(0.04))-0.015;
// Correct distance back to linear space using the smaller of the two scales
// (conservative estimate so raymarcher doesn't overshoot)
d *= min(yTileScale, xzTileScale);
//d = min(d,length(sp)-0.1);
return vec4(vec3(si), d-0.01);
}
vec3 calcNormal(vec3 p) {
vec2 e = vec2(0.001, 0.0);
return normalize(vec3(
map(p + e.xyy).w - map(p - e.xyy).w,
map(p + e.yxy).w - map(p - e.yxy).w,
map(p + e.yyx).w - map(p - e.yyx).w
));
}
vec2 RM(vec3 ro, vec3 rd) {
float dO = 0.0;
float ii = 0.0;
for (int i=0; i<1600; i++) {
vec3 p = ro + rd*dO;
float dS = map(p).w/24.;
dO += dS;
ii += 1.0; // Can be used for effects based on steps
if (dO > 20.0 || dS < 0.0001) break;
}
return vec2(dO, ii);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 tv = uv;
uv -= 0.5;
uv.x *= ar;
vec3 col = vec3(0.);
vec3 ro = vec3(0.0, 0.0, 5.); // Ray Origin
vec3 rd = normalize(vec3(uv, -1.0)); // Ray Direction
// Point light at the convergence center of the cubes
// Place it at the actual scene center where cubes converge (origin, offset by the p.y -= .5)
vec3 lightPos = vec3(0.0, 0.5, 0.0);
vec3 lightColor = vec3(1.0, 0.95, 0.8) * 8.0;
// Multi-bounce reflections
vec3 accumCol = vec3(0.0);
float accumRef = 1.0;
const int MAX_BOUNCES = 4;
vec2 d = RM(ro,rd);
for (int bounce = 0; bounce < MAX_BOUNCES; bounce++) {
vec2 res = RM(ro, rd);
float hitT = res.x;
vec3 hitP = ro + rd * hitT;
if (hitT >= 20.0) {
// Sky / background
accumCol += accumRef * vec3(0.0);
break;
}
vec3 n = calcNormal(hitP);
vec3 viewDir = -rd;
// Point light shading
vec3 toLight = lightPos - hitP;
float lightDist = length(toLight);
vec3 lightDir = toLight / lightDist;
float atten = 1.0 / (0.5 + 0.3 * lightDist * lightDist);
float diff = max(dot(n, lightDir), 0.0) * atten;
float spec = pow(max(dot(reflect(-lightDir, n), viewDir), 0.0), 32.0) * atten;
vec4 mapVal = map(hitP);
float si = mapVal.x;
bool isSphere = (si < -0.5); // tagged with -1 from the y>0 branch
vec3 tint;
float reflectivity;
if (isSphere) {
// Metallic mirror spheres
tint = vec3(0.8, 0.82, 0.85); // silver/chrome base
reflectivity = 0.85;
} else {
tint = 0.5 + 0.5 * sin(cs + si * 0.7);
reflectivity = 0.45;
}
float fres = isSphere ? pow(1.0 - max(dot(n, viewDir), 0.0), 5.0) : 0.0;
reflectivity = mix(reflectivity, 1.0, fres);
vec3 localCol = tint * (vec3(0.05) + lightColor * 0.1 * diff) + lightColor * 0.05 * spec;
accumCol += accumRef * (1.0 - reflectivity) * localCol;
accumRef *= reflectivity;
// Set up next bounce
ro = hitP + n * 0.005;
rd = reflect(rd, n);
}
col = accumCol;
// Screen-space glow for the light source itself
vec3 camPos = vec3(0.0, 0.0, 5.0);
vec3 lDir = lightPos - camPos;
vec2 lightUV = lDir.xy / (-lDir.z) * 1.0;
float glowDist = length(uv - lightUV);
vec3 addlight = vec3(0.);
addlight += lightColor * 0.02 * exp(-glowDist * glowDist * 10.0);
uv.y += -0.1;
addlight += exp(1.-length(uv)*10.)*0.2;
for (int i=0;i<31;i++) {
addlight += exp(1.-length(uv)*20.)*0.01*(sin(atan(uv.x,uv.y)*(40.+float(i-20))+time*10.*sin(float(i)*pi/2.)+sin(atan(uv.x,uv.y)*8.+sin(float(i))*14.))*0.5+0.5);
}
//if (d.x > 4.) {
col += addlight*smoothstep(0.0,2.,d.x-3.6);
//}
if (d.x > 10.) {
col += sin(d.y*0.1+cs)*0.05;
}
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.