光线追踪
$$\quad\\$$
从相机向平面上某点引一条射线$\vec{v}$
定义物体的符号距离函数$f$
当$\vec{v}$行进至符号距离函数$f$为负数的点$p$时停止
通过微小变化算出此处$f$的梯度$\nabla f$
计算$\vec{pL}$与$\nabla f$的余弦,作为该点的亮度
$$\quad$$
定义最大步进次数、距离与精度,
const int steps_max = 255; const float d_min = 0.0; const float d_max = 100.0; const float precision = 0.001;
定义旋转矩阵
mat3 rotateXYZ(float ax,float ay,float az){ float cx=cos(ax); float sx=sin(ax); float cy=cos(ay); float sy=sin(ay); float cz=cos(az); float sz=sin(az); return mat3( vec3(cy*cz,-cy*sz,sy), vec3(cz*sx*sy+cx*sz,cx*cz-sx*sy*sz,-cy*sx), vec3(-cx*cz*sy+sx*sz,cz*sx+cx*sy*sz,cx*cy) ); } mat3 rotate(){ return rotateXYZ(-iTime,-iTime,-iTime);}
定义十二面体的符号距离函数
float sdf(vec3 p,mat3 transform) { vec3 offset = vec3(0.,0., 0.5); p=p*transform-offset; float d1=(length(p)-abs(length(p)*0.6*1.71353 /(p.x*0.+p.y*0.+p.z*1.53884))); float d2=(length(p)-abs(length(p)*0.6*1.71353 /(p.x*1.37638+p.y*0.+p.z*0.688191))); float d3=(length(p)-abs(length(p)*0.6*1.71353 /(p.x*0.425325+p.y*-1.30902+p.z*0.688191))); float d4=(length(p)-abs(length(p)*0.6*1.71353 /(p.x*1.11352+p.y*0.809017+p.z*-0.688191))); float d5=(length(p)-abs(length(p)*0.6*1.71353 /(p.x*-1.11352+p.y*0.809017+p.z*0.688191))); float d6=(length(p)-abs(length(p)*0.6*1.71353 /(p.x*0.425325+p.y*1.30902+p.z*0.688191))); return max(d1,max(d2,max(d3,max(d4,max(d5,d6))))); }
定义rayMarch函数获取光线碰到物体的位置
float rayMarch(vec3 camera, vec3 reverse_direction, float d_min, float d_max) { float depth = d_min; for (int i = 0; i < steps_max; i++) { vec3 p = camera + depth * reverse_direction; float d = sdf(p,rotate()); depth += d; if (d < precision || depth > d_max) break; } return depth; }
获取物体表面外法线方向
vec3 calcNormal(vec3 p) { vec2 e = vec2(1.0, -1.0) * 0.0005; return normalize( e.xyy * sdf(p + e.xyy,rotate()) + e.yyx * sdf(p + e.yyx,rotate()) + e.yxy * sdf(p + e.yxy,rotate()) + e.xxx * sdf(p + e.xxx,rotate())); }
着色
void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y; vec3 col = vec3(0); vec3 camera = vec3(0, 0, 3); vec3 reverse_direction = normalize(vec3(uv, -1)); float d = rayMarch(camera, reverse_direction, d_min, d_max); if (d > d_max) { col = vec3(0.6); } else { vec3 p = camera + reverse_direction * d; vec3 normal = calcNormal(p); vec3 lightPosition = vec3(2, 2, 4); vec3 lightDirection = normalize(lightPosition - p); float dif = clamp(dot(normal, lightDirection), 0., 1.); col = vec3(dif); } fragColor = vec4(col, 1.0); }