Back to shaders
Shader test bench
20251103
runnable fragment
Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.
Code
precision mediump float;
// TouchDesigner GLSL TOP - Pixel Shader
// Ultra Beautiful 3D Raymarching Scene
// Theme: Ethereal Purple-Blue Cosmic Dreams
#define fragColor gl_FragColor
uniform float u_time;
uniform vec2 u_resolution;
// Your exquisite color palette
const vec3 col1 = vec3(0.212, 0.176, 0.471); // #362d78
const vec3 col2 = vec3(0.322, 0.247, 0.639); // #523fa3
const vec3 col3 = vec3(0.569, 0.424, 0.800); // #916ccc
const vec3 col4 = vec3(0.741, 0.631, 0.898); // #bda1e5
const vec3 col5 = vec3(0.784, 0.753, 0.914); // #c8c0e9
const vec3 col6 = vec3(0.518, 0.729, 0.906); // #84bae7
const vec3 col7 = vec3(0.318, 0.416, 0.831); // #516ad4
const vec3 col8 = vec3(0.200, 0.247, 0.529); // #333f87
const vec3 col9 = vec3(0.161, 0.188, 0.224); // #293039
const vec3 col10 = vec3(0.157, 0.212, 0.192); // #283631
#define PI 3.14159265359
// Smooth minimum for organic blending
float smin(float a, float b, float k) {
float h = max(k - abs(a - b), 0.0) / k;
return min(a, b) - h * h * h * k * (1.0 / 6.0);
}
// Rotation matrices
mat2 rot(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
mat3 rotateY(float angle) {
float c = cos(angle);
float s = sin(angle);
return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}
mat3 rotateX(float angle) {
float c = cos(angle);
float s = sin(angle);
return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}
// Enhanced 3D noise
float hash(vec3 p) {
p = fract(p * 0.3183099 + 0.1);
p *= 17.0;
return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
}
float noise3d(vec3 x) {
vec3 p = floor(x);
vec3 f = fract(x);
f = f * f * (3.0 - 2.0 * f);
return mix(
mix(mix(hash(p + vec3(0, 0, 0)), hash(p + vec3(1, 0, 0)), f.x),
mix(hash(p + vec3(0, 1, 0)), hash(p + vec3(1, 1, 0)), f.x), f.y),
mix(mix(hash(p + vec3(0, 0, 1)), hash(p + vec3(1, 0, 1)), f.x),
mix(hash(p + vec3(0, 1, 1)), hash(p + vec3(1, 1, 1)), f.x), f.y), f.z);
}
// Fractal Brownian Motion with more octaves
float fbm(vec3 p) {
float f = 0.0;
float amp = 0.5;
for(int i = 0; i < 6; i++) {
f += amp * noise3d(p);
p = p * 2.32;
amp *= 0.5;
}
return f;
}
// Domain repetition
vec3 opRep(vec3 p, vec3 c) {
return mod(p + 0.5 * c, c) - 0.5 * c;
}
// SDF primitives
float sdSphere(vec3 p, float r) {
return length(p) - r;
}
float sdTorus(vec3 p, vec2 t) {
vec2 q = vec2(length(p.xz) - t.x, p.y);
return length(q) - t.y;
}
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);
}
float sdOctahedron(vec3 p, float s) {
p = abs(p);
float m = p.x + p.y + p.z - s;
vec3 q;
if(3.0 * p.x < m) q = p.xyz;
else if(3.0 * p.y < m) q = p.yzx;
else if(3.0 * p.z < m) q = p.zxy;
else return m * 0.57735027;
float k = clamp(0.5 * (q.z - q.y + s), 0.0, s);
return length(vec3(q.x, q.y - s + k, q.z - k));
}
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
vec3 pa = p - a, ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h) - r;
}
// Complex scene with multiple elements
float map(vec3 p) {
vec3 q = p;
float time = u_time * 0.5;
// Main centerpiece - morphing torus
vec3 p1 = q;
p1 = rotateY(time * 0.3) * p1;
p1 = rotateX(sin(time * 0.4) * 0.5) * p1;
p1.y += sin(p1.x * 2.0 + time) * 0.2;
p1.x += cos(p1.z * 2.0 + time * 0.8) * 0.2;
float torusSize = 1.8 + sin(time * 0.6) * 0.2;
float d = sdTorus(p1, vec2(torusSize, 0.35));
// Inner rotating sphere with displacement
vec3 p2 = q;
p2 = rotateY(-time * 0.8) * p2;
float sphere1 = sdSphere(p2, 1.0);
sphere1 += sin(p2.x * 10.0 + time * 2.0) * sin(p2.y * 10.0 - time * 2.0) * sin(p2.z * 10.0 + time) * 0.05;
d = smin(d, sphere1, 0.8);
// Orbiting octahedrons
for(float i = 0.0; i < 4.0; i++) {
float angle = time * 0.7 + i * PI * 0.5;
vec3 p3 = q;
p3.xz *= rot(angle);
p3.x -= 2.5 + sin(time * 0.5 + i) * 0.3;
p3.yz *= rot(time * (1.0 + i * 0.3));
float octa = sdOctahedron(p3, 0.25);
d = smin(d, octa, 0.4);
}
// Flowing capsules creating ribbons
for(float i = 0.0; i < 3.0; i++) {
float t = time * 0.6 + i * 2.094;
vec3 p4 = q;
p4 = rotateY(t) * p4;
vec3 a = vec3(0.0, sin(t * 1.5) * 1.5, -2.0);
vec3 b = vec3(0.0, cos(t * 1.5) * 1.5, 2.0);
float caps = sdCapsule(p4, a, b, 0.15);
d = smin(d, caps, 0.5);
}
// Outer shell with holes
vec3 p5 = q;
p5 = rotateY(time * 0.2) * p5;
float shell = abs(sdSphere(p5, 3.2)) - 0.05;
vec3 p5Rep = opRep(p5, vec3(0.8));
float holes = sdSphere(p5Rep, 0.3);
shell = max(shell, -holes);
d = smin(d, shell, 1.2);
// Small orbiting spheres (particles)
vec3 p6 = q;
p6.xz *= rot(time * 1.2);
p6.yz *= rot(time * 0.9);
vec3 p6Rep = opRep(p6 - vec3(2.8, 0, 0), vec3(1.4));
float particles = sdSphere(p6Rep, 0.08);
d = smin(d, particles, 0.3);
// Add organic displacement
d += fbm(q * 1.5 + time * 0.3) * 0.1;
d += sin(q.x * 5.0 + time) * cos(q.y * 5.0 - time) * sin(q.z * 5.0 + time) * 0.02;
return d;
}
// Enhanced normal calculation
vec3 calcNormal(vec3 p) {
const float h = 0.0001;
const vec2 k = vec2(1, -1);
return normalize(
k.xyy * map(p + k.xyy * h) +
k.yyx * map(p + k.yyx * h) +
k.yxy * map(p + k.yxy * h) +
k.xxx * map(p + k.xxx * h)
);
}
// Ambient occlusion
float calcAO(vec3 p, vec3 n) {
float occ = 0.0;
float sca = 1.0;
for(int i = 0; i < 5; i++) {
float h = 0.01 + 0.12 * float(i) / 4.0;
float d = map(p + h * n);
occ += (h - d) * sca;
sca *= 0.95;
}
return clamp(1.0 - 1.5 * occ, 0.0, 1.0);
}
// Enhanced raymarching with glow accumulation
vec2 raymarch(vec3 ro, vec3 rd) {
float t = 0.0;
float glow = 0.0;
for(int i = 0; i < 100; i++) {
vec3 p = ro + rd * t;
float d = map(p);
// Accumulate glow
glow += 0.01 / (0.1 + abs(d));
if(d < 0.001) break;
if(t > 30.0) {
t = 30.0;
break;
}
t += d * 0.6;
}
return vec2(t, glow);
}
// Dynamic color palette cycling
vec3 getColor(float t, vec3 normal, vec3 p) {
float time = u_time * 0.5;
// Multiple color gradients based on position
float grad1 = sin(p.y * 3.0 + time * 0.7) * 0.5 + 0.5;
float grad2 = sin(length(p.xz) * 2.0 - time) * 0.5 + 0.5;
float grad3 = sin(p.x * 2.0 + p.z * 2.0 + time * 0.5) * 0.5 + 0.5;
float grad4 = (normal.y * 0.5 + 0.5);
// Base color mixing
vec3 color = mix(col1, col2, grad1);
color = mix(color, col3, grad2 * 0.7);
color = mix(color, col7, grad3 * 0.5);
// Add depth-based coloring
float depth = length(p);
color = mix(color, col8, smoothstep(2.0, 4.0, depth) * 0.3);
// Normal-based highlights
color = mix(color, col4, grad4 * 0.6);
color = mix(color, col5, pow(grad4, 3.0) * 0.4);
// Add ambient variations
float ambient = (sin(normal.x * 2.0) * 0.5 + 0.5);
color = mix(color, col6, ambient * 0.3);
// Add noise-based color variation
float noiseCol = fbm(p * 2.0 + time * 0.2);
color = mix(color, col3, noiseCol * 0.2);
return color;
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / u_resolution.y;
float time = u_time * 0.5;
// Dynamic camera movement
vec3 ro = vec3(0.0, 0.0, 6.0); // Closer camera (was 6.0)
ro.xz *= rot(time * 0.15);
ro.y += sin(time * 0.3) * 0.8;
ro.xy *= rot(sin(time * 0.2) * 0.2);
vec3 target = vec3(0.0, 0.0, 0.0);
vec3 forward = normalize(target - ro);
vec3 right = normalize(cross(vec3(0, 1, 0), forward));
vec3 up = cross(forward, right);
vec3 rd = normalize(forward + uv.x * right + uv.y * up);
// Beautiful gradient background
vec3 bgColor = mix(col9, col8, uv.y * 0.5 + 0.5);
bgColor = mix(bgColor, col10, length(uv) * 0.4);
bgColor = mix(bgColor, col1 * 0.5, smoothstep(0.5, 0.0, length(uv)));
// Add stars to background
float stars = pow(hash(vec3(uv * 50.0, 1.0)), 30.0) * 0.5;
bgColor += col5 * stars;
// Raymarch
vec2 result = raymarch(ro, rd);
float t = result.x;
float glow = result.y;
vec3 color = bgColor;
if(t < 30.0) {
vec3 p = ro + rd * t;
vec3 normal = calcNormal(p);
// Surface color
vec3 surfaceColor = getColor(t, normal, p);
// Multiple light sources
vec3 light1Pos = vec3(sin(time * 0.7) * 4.0, 3.0, cos(time * 0.7) * 4.0);
vec3 light2Pos = vec3(-sin(time * 0.5) * 3.0, -2.0, cos(time * 0.5) * 3.0);
vec3 light1Dir = normalize(light1Pos - p);
vec3 light2Dir = normalize(light2Pos - p);
// Diffuse lighting
float diff1 = max(dot(normal, light1Dir), 0.0);
float diff2 = max(dot(normal, light2Dir), 0.0) * 0.6;
// Specular highlights
vec3 viewDir = normalize(ro - p);
vec3 halfDir1 = normalize(light1Dir + viewDir);
vec3 halfDir2 = normalize(light2Dir + viewDir);
float spec1 = pow(max(dot(normal, halfDir1), 0.0), 64.0);
float spec2 = pow(max(dot(normal, halfDir2), 0.0), 32.0);
// Fresnel / rim lighting
float rim = 1.0 - max(dot(viewDir, normal), 0.0);
rim = pow(rim, 3.0);
// Ambient occlusion
float ao = calcAO(p, normal);
// Subsurface scattering approximation
float sss = pow(clamp(dot(viewDir, -light1Dir) + 1.0, 0.0, 1.0), 3.0) * 0.3;
// Combine lighting
color = surfaceColor * (0.2 + diff1 * 0.6 + diff2 * 0.3) * ao;
color += col5 * spec1 * 1.5;
color += col6 * spec2 * 0.8;
color += mix(col3, col6, 0.5) * rim * 0.8;
color += col4 * sss;
// Atmospheric fog with color
float fogAmount = 1.0 - exp(-t * 0.08);
vec3 fogColor = mix(bgColor, col2 * 0.3, 0.5);
color = mix(color, fogColor, fogAmount);
// Add internal glow
color += col3 * (1.0 - t / 30.0) * 0.15;
}
// Add glow effect from raymarch
color += col3 * glow * 0.02;
color += col6 * glow * 0.01;
// Enhanced vignette
float vignette = 1.0 - pow(length(uv) * 0.7, 2.0);
color *= vignette;
// Color grading
color = pow(color, vec3(0.85)); // Gamma
color = mix(color, col2 * 0.15, 0.08); // Color tint
// Chromatic aberration (subtle)
float aberration = length(uv) * 0.01;
// Contrast and saturation boost
color = mix(vec3(dot(color, vec3(0.299, 0.587, 0.114))), color, 1.15);
color = pow(color, vec3(1.0, 0.98, 0.96)); // Subtle color shift
// Bloom simulation
float bloom = smoothstep(0.8, 1.5, dot(color, vec3(0.333)));
color += col5 * bloom * 0.2;
fragColor = vec4(color, 1.0);
}