可微渲染实验:基于SDF的结果拟合

Project: https://github.com/MercuryGH/diff-rendering-slang

在本次实验中,我们将调整一个圆(或其他图形)的半径、圆心和颜色,拟合一个给定的三角形,使得两个图形在像素覆盖性和颜色上的均方误差最小。

预期结果

预期结果如下:

result
result

可以看到圆不断靠近三角形的中心,并调整自身半径,以期自身与三角形的覆盖程度的一致性最高;圆的颜色同时也不断接近三角形的颜色。

实验平台

相关知识

可微的光栅化过程

为了让离散的光栅化过程连续化,从而方便自动微分,我们将判断一个像素是否在三角形内的逻辑修改为基于 SDF,并使用 sigmoid 函数

\[ \sigma(x) = \frac{1}{1 + \mathrm e^{-x/\sigma}} \in (0, 1) \]

平滑计算出的有向距离,其中 \(\sigma\) 是一个较固定的参数,控制 sigmoid 函数的“陡峭”程度。

具体而言,我们对每个像素计算其到当前圆的有向距离 \(x\),其中 \(x \in (-\infty, +\infty)\) ,若像素在圆内则取负值。随后,计算 \(\sigma(-x)\) ,结果越大,则说明像素越接近圆心;反之像素越远离圆。对于 \(x\)\(0\) 附近的边缘点,这一计算结果会给出接近 \(\frac{1}{2}\) 的值。最后,我们用线性插值

\[ r = \text{lerp}(c_{\text{circle}}, c_{\text{bg}}, \sigma(-x)) \]

决定该点的颜色 \(r\),其中 \(c_{\text{circle}}, c_{\text{bg}}\) 分别为圆的颜色和背景色(白色)。由于 sigmoid 函数在 \(x = 0\) 附近平滑且快速上升,因此光栅化结果会在边缘处存在明显的模糊现象。

可微光栅化的详尽实现还需要考虑多个三角形、深度剔除等,可参考SoftRas 的原始论文

学习过程

“学习”就是使用基于梯度的方法求解目标函数的局部最小值的过程。为了拟合给定的三角形,我们定义目标函数为

1
torch.mean((outputImage - targetImage) ** 2)

即圆图形与三角形图形之间的均方误差,这一误差是每像素累计计算的。

利用 slang 的自动微分,整个光栅化过程都是可微分的,因此梯度的后向传播成为可能。我们可以利用 torch 框架的 torch.autograd.Function,为学习循环(learning loop)的前向光栅化-后向梯度传播调用过程提供便利。详细可参考相关样例。