本文参考自:normals for an SDF - 2015
在做RayMarching时,我们获得距离和位置信息后,为了进一步做光照渲染,需要得到物体表面的法线信息。
因为我们已经得到了空间中点的位置信息p,以及每个点到最近曲面的距离d,所以可以通过标量函数f§ = d构建一个[标量场( scalar field )]当距离d为一个常量C时,所有距离为C的点p会形成一个表面,这就是这个标量场的等值面,我们要求法线的面就是场景中d=0的面,所以f(p)= 0所表示的等值面就是物体的表面,根据向量场梯度的定义,假设向量G 过任意点p,p在这个向量上运动带来的f(p)的变化最大,则这个向量G称之为函数f(p)在p点的梯度,因为梯度必定垂直标量函数f(p)的等值面,所以物体表面的法线就是当f(p)= 0时所有p点位置的梯度。
根据梯度计算公式有:
当然这里我们不需要计算导数,根据极限的思想,和导数的定义,当点p的在各个轴上的位移足够小时,在x轴上的导数可以写作:
这当中h就是那个最小值,当然这种方法会更偏向正轴,我们可以使用中心差分法来校正:
因为向正负轴个移动了h个单位所以,需要除以2h个单位,加上另外两个轴:
这里直接去掉了2h因为对于法线这种不需要长度只需要方向的单位,归一化后自然抵消掉长度信息。
当然这种方式虽然精度较高但明显损耗也较大,所以我们也可以使用正向差分法代替