Mitsuba notes
dr.jit是一个differentiable rendering framework,全名是differentiable renderer Just -In-Time
和nvdiffrast平级,dr.jit更完整,复杂
尝试了直接渲染,
gradient optimization,是将固定的某个部分来作differenital的
forward rendering
# 需要为每个参数单独计算def visualize_parameter_effect(): # 计算红色参数的影响 dr.enable_grad(params['red.reflectance.value']) image = mi.render(scene, params) red_effect_map = dr.grad(image) # 红色参数对每个像素的影响
# 重置,计算绿色参数的影响 dr.enable_grad(params['green.reflectance.value']) image = mi.render(scene, params) green_effect_map = dr.grad(image) # 绿色参数对每个像素的影响
# 可视化每个参数对图像的影响 plt.subplot(1, 2, 1) plt.imshow(red_effect_map) plt.title("Red parameter effect")
plt.subplot(1, 2, 2) plt.imshow(green_effect_map) plt.title("Green parameter effect")
相当于只显示xx对图像的贡献
就像 AOV 帮助艺术家理解光照构成一样,Forward Mode 帮助研究者理解:
- “这个参数主要影响图像的哪些区域?”
- “为什么优化算法对某些参数敏感?”
- “参数变化如何在图像中传播?“
Reverse rendering
# 一次反向传播,得到所有参数的梯度for iteration in range(50): image = mi.render(scene, params) loss = mse(image, target) dr.backward(loss) # 一次计算
# 现在所有参数都有梯度了 red_gradient = dr.grad(params['red.reflectance.value']) green_gradient = dr.grad(params['green.reflectance.value']) # ... 更新所有参数
projective sampling
Projective sampling被用来处理differentiable rendering中的visibility discontinuities,核心思想是:
在采样路径的时候,同时考虑当前参数例如物体位置,对路径空间本身的影响,从而获得包含visibility项在内的正确导数
正常的渲染里我们做的是:
$$
I(\pi) = \int_P f(\mathbf{x}, \pi) , d\mathbf{x}
$$
我们希望求:
$$
\frac{\partial I(\pi)}{\partial \pi}
$$
如果 $f$ 是连续的,就可以直接把导数放进积分符号:
$$
\frac{\partial I(\pi)}{\partial \pi} = \int_P \frac{\partial f(\mathbf{x}, \pi)}{\partial \pi} , d\mathbf{x}
$$
但如果物体的移动让一些光线突然遮挡/不遮挡了物体,就有了路径空间的拓扑变化,这个时候你不能简单地对 $f$ 做微分,而是要对整个积分过程本身做微分。这个就需要用到类似 Reynolds transport theorem 的公式,把 路径空间的变形也纳入考虑。
Projective sampling 的做法是:
- 在采样的时候,不只是采样光路本身,还记录这个路径对参数 $\pi$ 的依赖;
- 然后在微分时,除了 $f(\mathbf{x}, \pi)$ 的导数,还额外考虑了路径本身变化带来的导数;
- 这样你就得到了正确的 $\partial I / \partial \pi$,即使在 visibility 有跳变的时候也是成立的。
Path Space (路径空间)
所有从光源出发,经过一系列表面反射,最终到达相机的一条完整路径的集合
每一条路径 $\mathbf{x}$ 就是一组顶点 $(\mathbf{x}_0, \mathbf{x}_1, \dots, \mathbf{x}_n)$,这些点可能是:
- 光源(起点)
- 表面交点(中间反射点)
- 相机感光面(终点)
所以渲染其实就是在 path space 上做积分:
$$
I = \int_P f(\mathbf{x}) , d\mathbf{x}
$$
其中:
- $P$:整个路径空间
- $\mathbf{x}$:一条具体的路径(路径上的若干个顶点)
- $f(\mathbf{x})$:该路径对最终图像的贡献,比如通过 BRDF、可见性、几何项等计算出来的 radiance
跟 Monte Carlo 有什么关系?
现代渲染(特别是 path tracing)就是:
- 随机采样一些路径(在路径空间中抽样);
- 对每条路径计算 $f(\mathbf{x})$;
- 求这些值的平均,估计积分。