Lección 7 de 10 · Ray marching en GLSL
Sombra
Otro rayo hacia la luz. Si choca, hay sombra.
La sombra es solo otra marcha. Desde el punto iluminado, disparas un rayo hacia la luz. Si en el camino choca con algo, la luz está bloqueada: ese punto queda en sombra.
El truco bonito (soft shadow) mide el rayo más flaco que pasó cerca de un obstáculo: si casi rozó, penumbra suave; si pasó limpio, luz total. Una marcha extra y la esfera proyecta su sombra sobre el piso.
Soft shadowMientras el rayo de sombra avanza, guardamos
min(res, k*d/t): qué tan cerca pasó de un objeto, escalado por la distancia. k es la dureza: alto = bordes nítidos, bajo = penumbra difusa.Baja el
8.0 de min(res, 8.0 y la sombra se ablanda. El segundo slider sube la luz (vec3(0.7, 0.9) y acorta la sombra.El código
precision highp float;
float map(vec3 p){
float sph=length(p)-1.0;
float flo=p.y+1.0;
return min(sph, 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, 8.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.0,3.0);
vec3 rd=normalize(vec3(uv,-1.5));
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);
vec3 lightDir=normalize(vec3(0.7, 0.9, 0.5));
float sh=shad(pos+n*0.02, lightDir);
float diff=max(dot(n,lightDir),0.0)*sh;
vec3 lit=vec3(0.85,0.55,0.35)*(diff*0.95+0.12);
vec3 sky=mix(vec3(0.05,0.06,0.12), vec3(0.16,0.22,0.42), uv.y*0.5+0.5);
float fog=1.0-exp(-t*0.08);
vec3 col=mix(lit, sky, fog);
col=mix(sky, col, hit);
gl_FragColor=vec4(col,1.0);
}