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

Material

Color por posición + un brillo especular nítido.

Hasta ahora todo era de un solo color. Un material decide el color en cada punto del hit. Aquí lo sacamos de la posición con un cos, que va ciclando por colores conforme cambia la altura.

Y le ponemos el toque que vende el realismo: el especular, ese puntito brillante donde la luz rebota directo al ojo. Se calcula con la normal contra el vector medio entre luz y cámara, elevado a una potencia: pow(..., 32.0). Más potencia, brillo más chico y duro.

EspecularEl reflejo directo de la luz. Cuando normal, luz y vista casi se alinean, el punto se prende. La potencia (32.0) controla el tamaño: alto = punto de alfiler metálico, bajo = brillo amplio mate.
PruebaSube el 32.0 de pow(..., 32.0) y el brillo se concentra en un punto. El segundo slider cambia el ritmo de color (pos.y*2.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.7, 0.9, 0.5));
  float diff=max(dot(n,lightDir),0.0);
  vec3 mat=0.5+0.5*cos(pos.y*2.0+vec3(0.0,2.0,4.0));
  vec3 hv=normalize(lightDir+normalize(ro-pos));
  float spec=pow(max(dot(n,hv),0.0), 32.0);
  vec3 lit=mat*(diff*0.85+0.15)+vec3(1.0)*spec*0.7;
  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