光线追踪
$$\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);
}