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