全部专题

不画三维模型,怎样用法线给距离场打光?

距离场只提供一个数值,光照却需要知道表面朝向。分别采样 x、y、z 两侧的距离,估算梯度,再归一化为方向。RGB 法线图是排查过程中的中间视图;应先确认朝向连续,再调节漫反射或镜面高光。

先固定问题

距离场提供一个标量,光照却需要表面朝向。对 X、Y、Z 两侧分别求差,可以估计距离场梯度,再归一化成法线。RGB 法线图是中间诊断,只有先看到朝向连续变化,漫反射或高光才值得继续调。

关键代码

vec3 normalAt(vec3 p){
  vec2 e=vec2(0.002,0.0);
  return normalize(vec3(
    scene(p+e.xyy)-scene(p-e.xyy),
    scene(p+e.yxy)-scene(p-e.yxy),
    scene(p+e.yyx)-scene(p-e.yyx)));
}
vec3 n=normalAt(hitPoint);
float diffuse=max(dot(n,normalize(lightDirection)),0.0);

按顺序验证

对比球体的法线图和光照图,再把差分 epsilon 改为一半或两倍。布尔雕刻场必须对最终组合距离场求梯度,否则洞壁的光照会不对。

适用范围和常见错误

太小的 epsilon 容易受浮点误差影响,太大会抹平小特征。归一化的对象是梯度,不能把未命中的射线终点当成有效表面。

继续实验

参考

官方文档

运行相关示例