learn GLSL from zero
ToolsCrea con shadersShader MakerCrea shaders gratis en líneaToolkitObras de shaders listas para tu webSketcher LabPinta el hero de tu landing con shaders3D StudioEl editor Three.js en tu navegador
GamesJuega con shadersOnomatoShaderEscribe una palabra y explótalaThe WatcherUn ojo que te sigueAetherVidrio líquido con un ojo adentroBloomcoreUna palabra hace crecer un jardín de luzPyrokineAvienta fuego a la paredVoltaicLa pirámide lanza rayosSurfSurfea un océano de shader

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.
PruebaBaja 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);
}
close