Lesson 4 of 10 · Ray marching in GLSL
Normals
Which way the surface faces. The orientation map.
To light something you first need to know which way each point of its surface faces. That is the normal: an arrow perpendicular to the shell.
We do not store it, but the SDF hands it over: measure the distance at six tiny points around the hit (a bit left, right, up, down, front, back) and the difference points outward. That is the gradient. We paint n*0.5+0.5 to see it: each axis a color.
The gradientThe normal is the direction in which the SDF grows fastest. Subtracting
map(p+e)-map(p-e) on each axis measures that slope. normalize makes it unit-length. A sphere shows the full RGB rainbow because it faces every direction.Move the
0.0 in hueShift(col, 0.0) to spin the whole normal palette. Change the radius 1.0 too.The code
precision highp float;
float map(vec3 p){
return length(p)-1.0;
}
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>12.0) break;
}
vec3 pos=ro+rd*t;
vec3 n=nrm(pos);
vec3 col=mix(vec3(0.04,0.05,0.09), n*0.5+0.5, hit);
col=hueShift(col, 0.0);
gl_FragColor=vec4(col,1.0);
}