Lesson 10 of 10 · Ray marching in GLSL
Full scene
Everything together + the light orbits with time. FINALE.
The breakdown comes together. Two spheres fused with smin over a floor, normals, diffuse light, soft shadow, material by position and specular. And now it moves: the light orbits the scene using T (time) inside a cos and a sin, and the shadow swings with it.
This is a full render engine in one function. The same recipe behind fluids, planets, creatures and fractals. You can now read the whole thing.
T = time
T is seconds ticking. Fed into cos(T*ls) and sin(T*ls) it traces a circle: the light goes around. ls is the speed. Any number in the shader can drink from T and come alive.Push
ls=0.6 to 1.5 and the light orbits faster. The second slider sharpens the specular (40.0).The code
precision highp float;
float smin(float a, float b, float k){
float h=clamp(0.5+0.5*(b-a)/k, 0.0, 1.0);
return mix(b,a,h)-k*h*(1.0-h);
}
float map(vec3 p){
float s1=length(p-vec3(-0.6,0.0,0.0))-0.8;
float s2=length(p-vec3(0.6,0.0,0.0))-0.8;
float blob=smin(s1, s2, 0.6);
float flo=p.y+1.1;
return min(blob, flo);
}
vec3 nrm(vec3 p){
vec2 e=vec2(0.001,0.0);
return normalize(vec3(
map(p+e.xyy)-map(p-e.xyy),
map(p+e.yxy)-map(p-e.yxy),
map(p+e.yyx)-map(p-e.yyx)));
}
float shad(vec3 ro, vec3 rd){
float res=1.0;
float t=0.05;
for(int i=0;i<32;i++){
float d=map(ro+rd*t);
if(d<0.001) return 0.0;
res=min(res, 10.0*d/t);
t+=d;
if(t>10.0) break;
}
return clamp(res, 0.0, 1.0);
}
void main(){
vec2 uv=(gl_FragCoord.xy*2.0-R)/R.y;
vec3 ro=vec3(0.0,0.2,3.2);
vec3 rd=normalize(vec3(uv,-1.6));
float t=0.0;
float hit=0.0;
for(int i=0;i<64;i++){
vec3 pos=ro+rd*t;
float d=map(pos);
if(d<0.001){ hit=1.0; break; }
t+=d;
if(t>20.0) break;
}
vec3 pos=ro+rd*t;
vec3 n=nrm(pos);
float ls=0.6;
vec3 lightDir=normalize(vec3(cos(T*ls)*1.4, 1.0, sin(T*ls)*1.4));
float sh=shad(pos+n*0.02, lightDir);
float diff=max(dot(n,lightDir),0.0)*sh;
vec3 mat=0.5+0.5*cos(pos.x*1.5+vec3(0.0,2.0,4.0)+T*0.2);
vec3 hv=normalize(lightDir+normalize(ro-pos));
float spec=pow(max(dot(n,hv),0.0), 40.0)*sh;
vec3 lit=mat*(diff*0.9+0.15)+vec3(1.0)*spec*0.8;
vec3 sky=mix(vec3(0.04,0.05,0.10), vec3(0.14,0.20,0.40), uv.y*0.5+0.5);
float fog=1.0-exp(-t*0.06);
vec3 col=mix(lit, sky, fog);
col=mix(sky, col, hit);
col=pow(col, vec3(0.85));
gl_FragColor=vec4(col,1.0);
}