Header
Your content here
Snippets
Shadertoy
// Shadertoy: 3D Raymarched Cloud Example
// iResolution, iTime, iMouse available
#define MAX_STEPS 96
#define LIGHT_STEPS 8
#define FAR 40.0
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 noise(vec3 x)
{
vec3 i = floor(x);
vec3 f = fract(x);
f = f * f * (3.0 - 2.0 * f);
float n000 = hash(i + vec3(0,0,0));
float n100 = hash(i + vec3(1,0,0));
float n010 = hash(i + vec3(0,1,0));
float n110 = hash(i + vec3(1,1,0));
float n001 = hash(i + vec3(0,0,1));
float n101 = hash(i + vec3(1,0,1));
float n011 = hash(i + vec3(0,1,1));
float n111 = hash(i + vec3(1,1,1));
return mix(
mix(mix(n000, n100, f.x), mix(n010, n110, f.x), f.y),
mix(mix(n001, n101, f.x), mix(n011, n111, f.x), f.y),
f.z
);
}
float fbm(vec3 p)
{
float v = 0.0;
float a = 0.5;
for (int i = 0; i < 5; i++)
{
v += a * noise(p);
p *= 2.02;
a *= 0.5;
}
return v;
}
float cloudDensity(vec3 p)
{
// Move clouds over time
p.xz += vec2(iTime * 0.8, iTime * 0.25);
// Vertical shaping
float h = p.y;
float base = smoothstep(-1.0, 0.2, h);
float top = 1.0 - smoothstep(1.2, 2.8, h);
float heightMask = base * top;
// Large cloud body + details
float d = fbm(p * 0.45);
d += 0.5 * fbm(p * 1.2);
d -= 0.55;
d *= heightMask;
return clamp(d, 0.0, 1.0);
}
float lightmarch(vec3 pos, vec3 lightDir)
{
float transmittance = 1.0;
float t = 0.2;
for (int i = 0; i < LIGHT_STEPS; i++)
{
vec3 p = pos + lightDir * t;
float d = cloudDensity(p);
transmittance *= exp(-d * 1.6);
t += 0.5;
}
return clamp(transmittance, 0.0, 1.0);
}
mat3 camera(vec3 ro, vec3 ta)
{
vec3 f = normalize(ta - ro);
vec3 r = normalize(cross(vec3(0,1,0), f));
vec3 u = cross(f, r);
return mat3(r, u, f);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
// Camera
vec3 ro = vec3(0.0, 1.5, -6.0);
vec3 ta = vec3(0.0, 1.2, 0.0);
// Optional mouse orbit
if (iMouse.z > 0.0)
{
float mx = (iMouse.x / iResolution.x - 0.5) * 6.2831;
float my = (iMouse.y / iResolution.y - 0.5) * 1.2;
ro = vec3(6.0 * sin(mx), 1.5 + my * 4.0, -6.0 * cos(mx));
}
mat3 cam = camera(ro, ta);
vec3 rd = normalize(cam * vec3(uv, 1.6));
// Sky
float sunAmount = max(dot(rd, normalize(vec3(0.6, 0.7, 0.5))), 0.0);
vec3 skyCol = mix(vec3(0.6, 0.75, 0.95), vec3(0.2, 0.4, 0.8), rd.y * 0.5 + 0.5);
skyCol += vec3(1.0, 0.85, 0.6) * pow(sunAmount, 64.0) * 0.8;
vec3 col = skyCol;
vec3 lightDir = normalize(vec3(0.6, 0.7, 0.5));
float t = 0.0;
float transmittance = 1.0;
vec3 accum = vec3(0.0);
for (int i = 0; i < MAX_STEPS; i++)
{
if (t > FAR || transmittance < 0.01) break;
vec3 p = ro + rd * t;
// Limit marching to cloud layer
if (p.y > -1.5 && p.y < 3.5)
{
float d = cloudDensity(p);
if (d > 0.01)
{
float light = lightmarch(p, lightDir);
vec3 cloudBase = mix(vec3(0.65, 0.68, 0.72), vec3(1.0), light);
vec3 scatter = cloudBase * (0.35 + 0.65 * light);
// Beer-Lambert
float stepSize = 0.18;
float alpha = 1.0 - exp(-d * 2.0 * stepSize);
accum += scatter * alpha * transmittance;
transmittance *= (1.0 - alpha);
}
}
// Adaptive stepping: faster in empty space
t += mix(0.08, 0.3, clamp(t * 0.03, 0.0, 1.0));
}
col = accum + skyCol * transmittance;
// Simple tonemap + gamma
col = col / (1.0 + col);
col = pow(col, vec3(0.4545));
fragColor = vec4(col, 1.0);
}