从一条射线到一个球:Ray Marching 的步长究竟怎么选?
固定步长可能跳过薄物体,也可能在空白区域浪费迭代。球面追踪按到表面的安全距离前进。球的 length(p)-r 是精确距离场;随意缩放或扭曲后的场则未必仍提供不会越过表面的距离下界。
先固定问题
固定步长容易跳过薄物体,也可能在空区域浪费大量迭代。Sphere tracing 的前提是距离场给出到表面的安全距离,因此可以按这个距离前进。示例球体的 length(p)-r 是精确 SDF,而被随意放大或扭曲的函数可能不再提供安全步长。
关键代码
float travel=0.0;
bool hit=false;
for(int i=0;i<80;i++){
float distance=scene(origin+direction*travel);
if(distance<0.002){hit=true;break;}
travel+=max(distance,0.001);
if(travel>12.0)break;
}
vec3 color=hit?shade(origin+direction*travel):background;
按顺序验证
先看球体,再看布尔凹槽。降低步数时检查漏掉的像素;扩大命中 epsilon 时检查轮廓膨胀。每次只改一个退出条件。
适用范围和常见错误
循环用尽不等于命中。远处没有命中也必须终止;法线与阴影只应在命中后求值。复杂分形还需要对应的距离估计推导。