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 6 de 10 · Ray marching en GLSL

El piso

Un plano + min(). Dos formas viven en la misma escena.

Una escena con un solo objeto es un planeta solitario. Para meter más, unes SDFs con min(): la distancia a lo más cercano es la menor de las dos. Esfera o piso, gana el que esté más cerca del rayo.

El piso es la SDF más barata del mundo: p.y+1.0 es la distancia vertical a un plano horizontal. Lo unes con la esfera y de pronto hay un suelo donde posarse.

min(a, b) = uniónmin de dos distancias devuelve la del objeto más cercano. Es el operador de unión: junta formas en una sola escena. Más adelante verás max para recortes y smin para fusiones suaves.
PruebaCambia p.y+1.0 a p.y+0.6 y el piso sube, la esfera parece flotar. El primer slider cambia el radio (sph=length(p)-1.0).

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)));
}
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.8,0.7,0.6));
  float diff=max(dot(n,lightDir),0.0);
  vec3 lit=vec3(0.85,0.55,0.35)*(diff*0.9+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