本篇是随笔, 也就是随便写写一些想法, 这些想法内容不足以成文, 因此也并不考究.
我之前只接触过传统CG, 不如说传统CG都没怎么学明白. 实际上基本只学了Path Tracing, 确实是简单又出效果, 但是这导致我图形学数学基础非常烂. 最近由于要研究3DGS, 一大堆术语都是听过但是不理解. 比如球谐函数, 可微渲染种种. 我觉得不写出来就学得不踏实……
所以会更一些图形学相关的下饭小文章, 纯粹是自己的输出, 没有太在乎可读性. 不过我是比较难接受抽象想法的人, 只有把事情想得直观一些才能理解。所以应该(?)会比较简单.
试想一下我们的计算机图形学渲染过程是啥样的:
$$ 场景参数 + 算法 \rightarrow 图像 $$嗯, 算法好理解, 也就是我们整的那些渲染管线, 一般来说就是些坐标变换, 最后有个光栅化操作.
场景参数是啥? 实际上就是你对场景的控制, 一些可设定的值. 例如, 当场景中只能有一个长方体时, 你的场景参数或许就是长方体顶点坐标, 长方体旋转角度……总之, 这些参数唯一确定了场景中的一个长方体. 如果这个长方体表面还有材质, 材质也有一些参数, 例如金属度, 折射率等. 这些东西整个加在一起, 就是场景参数. 也就是在所讨论的渲染过程中, 你能够修改的场景部分.
任务: 你现在有一个场景$S$, 其参数空间为$P=\{p_i\}$. 某个参数下的场景用$S(p_i)$表示. 你经过一个渲染算法$f$, 得到了一个图像$G$. 显然, $G=f(S(p_i))$. 你现在有1张(可以多张, 但这里简化问题为1张)图片$G'$. 请你在$P$中给出参数$p$, 使得$G = f(S(p)) = G'$.
也就是说, 你现在知道渲染算法, 也知道渲染结果, 需要得到场景参数. 也就是根据图片反推场景实际是怎样的. 如果是你的话, 你会怎么办?
从机器学习视角来说, 这就是个参数搜索问题嘛! 话不多说直接上我们的梯度下降!
当前参数为$p_{cur}$, 目标参数未知. 我们先计算损失值:
$$ \begin{aligned} loss &= loss\_function(G, G') \\ &=loss\_function(G, f(S(p_{cur}))) \end{aligned} $$然后计算参数的梯度:
$$ \begin{aligned} \nabla_{p_{cur}} loss &= \nabla_{p_{cur}} loss\_function(G, f(S(p_{cur}))) \\ &= \frac{\partial loss\_function}{\partial G'} \frac{\partial f}{\partial p_{cur}} \end{aligned} $$这个算式写得非常不严谨. 为什么第二个微分式不是$\frac{\partial f}{\partial S(p_{cur})}$? 因为场景$S$不是个函数, 而$S(p)$只是我为了表述方便而写的. 实际上$S$仅仅是一种约束, 否则你不可能通过有限的参数$p$来唯一确定一个场景. 你必须提前知道场景是什么样的. 所以实际上, 更应该写成$f(p | S)$或者$f_S(p)$. 重在理解, 这里就这么写了.
一般来说, $loss\_function$是一个可微的函数, 没有问题. 而这个$f$可就有问题了: 传统CG中, 例如基于Mesh, 就算有插值, 它也是个不连续的东西. 而光栅化, 这个原本在"图像由像素组成, 不连续"的情况下非常符合直觉的做法, 在现在的场景下更是雪上加霜. 也就是说, $f$, 至少在不打补丁的情况下, 肯定是个不可微的函数. 即不可微渲染, 传统渲染(Traditional Rendering).
所以可微分渲染(Differential Rendering), 顾名思义, 就是可微的$f$. 3DGS是一种可微渲染, NeRF也是一种可微渲染. 这两个实际上我还没学明白, 以后肯定会各自单开一篇文章. 核心在于$\frac{\partial f}{\partial p}$. 即该渲染过程对其输入参数可微.


欢迎友好讨论~