redner — 让光线追踪能反向传播过几何边缘
是什么
redner 是 2018 年 MIT 的 Tzu-Mao Li 等人做的可微路径追踪器——你给它一张照片,它能反向告诉你「场景里那个椅子腿应该往左移 0.3mm,颜色再红一点」,自动算出梯度让你用 SGD 调形状、材质、光源。
日常类比:普通渲染器是「输入场景 → 输出图片」的单向相机。redner 是一台会反向推的相机:你给它一张目标图,它能算出「为了让我拍出这张图,场景里每一个三角形该怎么动」。
最关键的一行:它是第一个能正确反向传播过几何遮挡边缘的 Monte Carlo 渲染器。
为什么重要
不理解 redner 解决的问题,下面这些事会让你困惑:
- 为什么 PyTorch 直接搭一个光线追踪器、求梯度,结果梯度永远是 0——明明场景在动
- 为什么 NeRF(2020)用体积渲染而不是表面渲染——它绕开了 redner 死磕的那个问题
- 为什么「从一张照片反推 3D 场景」(inverse rendering)在 2018 之前一直做不准
- 为什么材质识别 / 光源估计 / 形状重建在 redner 之后突然能用 SGD 端到端训了
redner 之前,大家用 rasterization-based 的近似可微渲染器(OpenDR 2014、Soft Rasterizer 2019),梯度不准但能跑。redner 第一次把「物理正确的可微」做出来。
核心要点
一句话核心问题
几何遮挡(visibility)会让像素颜色对场景参数产生”阶跃式”变化——梯度处处为 0,但在边界上是 ∞。Monte Carlo 采样直接求这种积分的方差是无穷大,完全没法反向传播。
用日常场景理解
想象你拿手电筒照墙,墙上有个圆盘投出的影子。问:「如果圆盘往右移 1mm,影子里某个点 P 的亮度怎么变?」
- 如果 P 一直在影子里 → 亮度不变,梯度 = 0
- 如果 P 一直在影子外 → 亮度不变,梯度 = 0
- 如果 P 正好在影子边缘——亮度从 0 跳到 1,梯度 = ∞
整张图的总梯度,全部来自那条细如发丝的边界线。普通 Monte Carlo 在面积上随机撒点,撒到边界的概率是 0,所以永远抓不到梯度。
redner 的三个发明
-
边缘采样(edge sampling):不再随机撒面积积分点,而是显式枚举三角形的轮廓边(silhouette edges),在边上专门撒采样点。这是把 Reynolds transport theorem 用到渲染里——把面积积分的导数拆成「内部光滑部分 + 边界部分」。
-
次级边可见性测试:直接边在镜头里看到的边好枚举,但间接光照里也有遮挡——比如墙上反射出影子。redner 处理这种间接边,用一个层次结构 + 重要性采样加速。
-
embree + autodiff 集成:用 Intel embree 做光线求交,外面套上 PyTorch 的反向传播,让整个 pipeline 既快又能 grad。
实践案例
案例 1:从一张照片反推材质
输入:一张茶壶照片 + 已知茶壶 3D 网格 未知:茶壶表面是什么材质(漫反射 / 金属 / 粗糙度)
material = redner.Material(diffuse_reflectance=torch.tensor([0.5, 0.5, 0.5], requires_grad=True))for step in range(200): rendered = redner.render(scene, material) loss = ((rendered - target_photo) ** 2).mean() loss.backward() optimizer.step()200 步后,material.diffuse_reflectance 收敛到正确颜色。没有 redner,第三行 loss.backward() 在边缘像素那里梯度就废了。
案例 2:从照片反推几何形状
更难——形状变了,遮挡也变,几何边在反向传播里出现。redner 的边缘采样在这里发力:
输入:单视图照片 优化:mesh vertex 坐标 输出:拟合出 3D 网格
这是 redner 论文 Figure 14 的实验,初代用 SGD 反推几何的工作之一。
案例 3:和 NeRF 的关系
NeRF(Mildenhall 2020)是另一条路:避开表面渲染,用体积渲染(每条光线沿路积分密度)。
- redner:表面渲染 + 显式处理遮挡边
- NeRF:体积渲染(连续函数),没有遮挡边这个问题
NeRF 拿掉了 visibility discontinuity 难题,代价是每个场景都要从头训练一个网络。redner 是显式几何 + 物理材质,支持编辑。两条路并存——表面派(redner / Mitsuba 3)做 inverse rendering,体积派(NeRF / 3DGS)做 novel view synthesis。
踩过的坑
-
边缘枚举非常贵:每个三角形要测试是否是 silhouette edge(背面 / 正面交界),N 个三角形 O(N²) 边对。redner 用 BVH 加速,但百万面级场景仍然慢。后续 Mitsuba 3(2022)用更好的算法。
-
次级边采样的方差仍然大:直接边好搞,间接边(光在场景里反弹后才碰到的遮挡)需要很多采样点才能稳定,调参不当梯度噪声大、训练不收敛。
-
不能处理透明/折射的 visibility:redner 假设硬表面遮挡。玻璃、烟雾、毛发这些「软遮挡」需要后续工作(reparameterization 2020、path-space differentiable rendering 2020)。
-
必须有正确的 3D mesh 起点:redner 优化的是已知拓扑的 mesh 顶点。拓扑变化(开个洞、加个把手)超出能力,需要 differentiable mesh evolution(Mesh R-CNN / DMTet)。
适用 vs 不适用场景
适用:
- 已知 3D 几何 + 反推材质 / 光源 / 纹理
- 已知拓扑 + 反推顶点位置(小幅变形)
- 物理正确性要求高的逆问题(科研 / VFX)
- 想保留可编辑显式几何的下游应用
不适用:
- 拓扑未知 + 大变形 → 用 NeRF / 3D Gaussian Splatting
- 实时渲染 → redner 是离线的,单帧秒级
- 软遮挡(透明 / 烟雾)→ 用后续 differentiable volumetric 方法
- 端到端从图像生成场景(无几何先验)→ 用 diffusion + 3D 重建
历史定位
- 2014:OpenDR——第一个可微渲染器,但用 rasterization + 局部线性近似,梯度不准
- 2018:redner——第一个 Monte Carlo + 物理正确的可微渲染器
- 2019:Soft Rasterizer——把 rasterization 软化以避开离散性,速度快但仍是近似
- 2020:NeRF——绕开 surface visibility,用 volume rendering
- 2020:Loubet 的 reparameterization——更通用的处理 discontinuity 方法
- 2022:Mitsuba 3——把可微渲染做成工业级框架,吸收 redner / Loubet 思想
- 2023:3D Gaussian Splatting——用各向异性高斯替代体素,速度上量级提升
redner 是这条线的理论奠基:之后所有 surface-based 可微渲染都在它的边缘采样框架上扩展。
学到什么
- 不连续函数的”期望梯度”不等于”梯度的期望”——遇到 visibility / argmax / step function 时,普通 autodiff 会静默给错答案(梯度 = 0),不是报错
- 边界积分是处理这类问题的通用工具——把面积积分的微分拆成「内部光滑 + 边界跳跃」,在边界上单独采样
- 物理正确 vs 近似可微是工程上要权衡的——redner 选了前者,速度慢但梯度准;Soft Rasterizer 选了后者,反过来
- 可微渲染开辟了”用 SGD 优化 3D 场景”的新范式,是 NeRF / 3DGS / 神经辐射场整套革命的前奏
- 同一个数学陷阱在多个领域反复出现:argmax 在分类、attention 中的硬选择、采样在 RL 中——任何”离散决定”都会让梯度断流,处理思路都是「把硬变软」或「在边界单独算」
延伸阅读
- 论文 PDF:Differentiable Monte Carlo Ray Tracing through Edge Sampling(17 页,前 6 页可读,后面公式密集)
- 作者主页 + 代码:Tzu-Mao Li / redner(PyTorch / TF 都支持)
- 综述:Tzu-Mao Li 的博士论文 Differentiable Visual Computing(2019,把可微渲染整套讲一遍)
- 后续工作:Mitsuba 3 文档(工业级实现,吸收了 redner 思想)
关联
- 3d-gaussian-splatting —— 同样追求”可微 3D”,但走 volume + 高斯路线,绕开 visibility 难题
- pytorch —— redner 的 autodiff 后端
- jax —— 后来 Mitsuba 3 也支持 JAX 后端,思路一脉相承
- attention —— attention 把 argmax(硬选)软化成 softmax,让梯度能流过,是同一类”软化离散”思路的语言模型版本
关键启发
- 当一个 pipeline 看起来「明明能跑、但 SGD 不收敛」时,先检查有没有离散决策点让梯度断流——很多深度学习架构的进步本质上是「把某个硬决策软化」
- 物理正确不是奢侈品——近似可微在简单场景能用,但复杂遮挡下近似误差会让优化收敛到错答案,redner 的边缘采样是这种场景下唯一靠谱的路
反向链接
- 3d-gaussian-splatting —— 3D Gaussian Splatting — 用一堆 3D 模糊光斑重建场景
- attention —— Attention Is All You Need
- jax —— JAX — Google 函数式数值计算
- pytorch —— PyTorch — 深度学习主流框架