方法逐行拆解 · 2025 — 2026

Radiant Foam:把光追请回辐射场

3D Gaussian Splatting 用光栅化把椭球拍到屏幕上,又快又好,但它不是在追光线。 Radiant Foam 把场景切成一团泡沫——三维 Voronoi 细胞——然后让光线真的 一格一格地穿过去。结果是:一个可微的、实时的光线追踪辐射场,质量接近 3DGS, 速度反而比"硬件光追版高斯"(3DGRT)快 2–3 倍,而且不需要 RTX 光追核心

预设读者:会基本的 NeRF(知道体渲染那条积分)、线性代数、微积分。不会 Voronoi / Delaunay / 可微网格也没关系——我们从头讲,并且把论文里的每一步(初始化、训练、渲染、拓扑维护)都对到 官方代码 theialab/radfoam 的真实实现上。

1 篇核心论文 + 7 篇直接后续 · 4 个交互演示 · 最后更新 2026-06-01

阅读路径建议

零基础:从 §1 顺着读,§4 的泡沫演示先玩 30 秒。 已经懂 3DGS / NeRF:直接跳 §6(光线行走)和 §8(零面积翻转)——这两节是 Radiant Foam 和所有前作真正不一样的地方。只想看后续工作:跳到 §15 的 Foam 家族。

§1一句话:它到底是什么

先把背景对齐。我们要从一堆照片(带相机位姿,通常来自 COLMAP)重建一个可以自由换视角渲染的 3D 场景。 三条主流路线:

  • NeRF:场景是一个 MLP $F_\theta(\mathbf{x}, \mathbf{d}) \to (\sigma, \mathbf{c})$。 渲染时沿每条光线采样几十上百个点,每点查一次网络,再做体积积分。质量高,但每个点一次 MLP,很慢。
  • 3D Gaussian Splatting(3DGS):场景是几百万个带协方差的高斯椭球。渲染时把椭球 投影 / 光栅化到屏幕,按深度排序后 alpha 混合。极快,但它是 splatting 不是 ray tracing—— 反射、折射、鱼眼这些"二次光线 / 非针孔相机"的东西做不了。
  • Radiant Foam:场景是一团 Voronoi 泡沫——一组可学习的点(site), 每个点拥有一块"离它最近"的多面体细胞。渲染时光线真的逐个细胞穿过去,做一次精确的体积积分。
关键想法 · 一句话

把空间用一组点切成 Voronoi 细胞(泡沫),每个细胞内密度和颜色是常数;光线穿过泡沫时,靠 相邻 site 的垂直平分面就能 O(邻居数) 地算出"下一个细胞在哪"——不需要 BVH、不需要排序、 不需要光追硬件,而且整个过程对 site 的位置可导

论文作者 Govindarajan, Rebain, Yi, Tagliasacchi(SFU / UBC / Toronto / Google DeepMind), ICCV 2025 Highlight。他们自己的总结很坦诚:这是重新捡起一个被计算机视觉遗忘了几十年的 "体积网格光线追踪"老算法,把它做成可微、可训练、实时的现代辐射场。

§2核心方程:体渲染(和 NeRF 同一条)

Radiant Foam 用的是和 NeRF 完全一样的发射-吸收体渲染模型。一条光线 $\mathbf{r}(t)=\mathbf{o}+t\mathbf{d}$ 的颜色是:

$$ \mathbf{c_r} = \int_{t_{\min}}^{t_{\max}} T(t)\,\sigma(\mathbf{r}(t))\,\mathbf{c}(\mathbf{r}(t))\,dt, \qquad T(t) = \exp\!\Big(-\!\int_{t_{\min}}^{t}\sigma(\mathbf{r}(u))\,du\Big) $$

$\sigma$ 是密度(不透明度的来源),$\mathbf{c}$ 是该点朝相机方向发出的颜色, $T(t)$透射率——光走到 $t$ 还没被挡住的概率。NeRF 里 $\sigma, \mathbf{c}$ 是 MLP 给的连续函数,这条积分只能数值近似(黎曼和)。

Radiant Foam 的关键差别:密度和颜色在每个细胞内是常数。于是一条光线被它穿过的细胞序列 天然切成若干段,每段长度 $\delta_n$(光线在细胞 $n$ 里走的弦长)。这时积分有 解析闭式解,不再是近似:

$$ \mathbf{c_r} = \sum_{n=1}^{N} T_n\,\underbrace{\big(1 - e^{-\sigma_n \delta_n}\big)}_{\alpha_n}\,\mathbf{c}_n, \qquad T_n = \prod_{j=1}^{n-1} e^{-\sigma_j \delta_j} $$

这就是熟悉的前向合成:每个细胞贡献 $\alpha_n = 1-e^{-\sigma_n \delta_n}$,乘上到此为止的透射率 $T_n$。注意两点,它们是 Radiant Foam 全部优势的根:(1) 这个和式和上面的积分 严格相等(不是近似);(2) 光线是按几何顺序穿过细胞的,天然有序,不需要像 3DGS 那样 对图元排序

直觉

$\alpha_n$ 看成"这段把光吃掉的比例"。密度越大、走得越长,吃得越多。 $T_n$ 是"前面已经被吃剩多少"。光走着走着 $T$ 掉到接近 0,后面再有东西也照不进来—— 代码里就是 if (T < 0.01) break; 提前结束。

§3为什么是 ray tracing,不是 splatting

同样是把场景画出来,三条路线的代价结构完全不同。把这张表刻在脑子里——后面每一节都在解释表里的某一格 为什么成立。

NeRF3DGS(splatting)Radiant Foam
场景表示MLP 权重~数百万带协方差高斯~2–4M Voronoi site 点
每条光线代价几十上百次 MLP 查询投影 + 排序 + 混合逐细胞行走,每步 O(邻居数)
找"下一个采样点"固定步长/重要性采样—(不是逐光线)邻居垂直平分面,无加速结构
是否需要排序(深度排序,会 popping)(几何天然有序)
体积积分近似(数值求和)近似(高斯叠加)精确(分段常数)
二次光线 / 反射折射难(光栅化做不了)天然支持
非针孔相机(鱼眼/畸变)天然支持
渲染速度(Mip-NeRF360)<1 FPS~293 FPS~200 FPS

3DGS 快,是因为它放弃了光线追踪,改成把图元拍到屏幕上。代价是排序伪影、和"只能从针孔相机 正向投影"的局限。已经有人做了"硬件光追版高斯"(3DGRT),用 RTX 的 BVH 把高斯做成可追踪——但那需要光追核心, 且只有 78 FPS。Radiant Foam 的赌注是:如果场景本身就是一张能 O(1) 找下一格的网格,光追根本不需要 BVH,也就不需要专用硬件。这正是 Voronoi 泡沫提供的东西。

§4Voronoi 泡沫与 Delaunay 对偶

给定一组 site 点 $\{\mathbf{p}_i\} \subset \mathbb{R}^3$,site $i$Voronoi 细胞是空间里"离 $\mathbf{p}_i$ 比离任何其它 site 都近"的区域:

$$ \mathbf{c}_i = \big\{\, \mathbf{x}\in\mathbb{R}^3 \;:\; \arg\min_j \lVert \mathbf{x}-\mathbf{p}_j\rVert = i \,\big\} $$

这些细胞是凸多面体,无缝铺满整个空间,像一团闭孔泡沫(论文名字的来源)。两个细胞共享一个面 ⟺ 它们的 site 在 Delaunay 三角剖分里相邻。Delaunay 是 Voronoi 的对偶图

  • Voronoi 给的是几何——光线要穿过的那些细胞墙(面)。
  • Delaunay 给的是连接关系——谁和谁相邻,也就是光线"下一步能去哪"。

Radiant Foam 同时保留这两套结构:Delaunay 邻接表用来行走,Voronoi 面用来算交点。注意这里没有协方差、 没有椭球——细胞的形状完全由邻居决定,site 只是一个点。论文自己说:"本质上是一个可学习的点云, 和 3DGS 不无相似,只是少了每点的协方差矩阵。"

Demo 1 · Voronoi 泡沫 playground
拖动任意一个橙点(site),它的细胞会跟着变形——而且邻居的细胞也会变,因为边界是两点共同决定的。 打开"Delaunay 对偶"看青色虚线:那就是邻接图,光线追踪走的就是这张图。试着把一个点拖到很远,看它的邻居关系怎么断开重连。

§5每个 cell 存什么

在代码里(radfoam_model/scene.pyRadFoamScene),每个 site 是几个并排的 nn.Parameter。一共三类可学习量:

属性张量含义 / 激活大小(per site)
位置 $\mathbf{p}_i$primal_pointssite 坐标,唯一决定几何3
密度 $\sigma_i$density标量;scale · softplus(·, β=10)1
颜色 DCatt_dcSH 0 阶(与视角无关的基色)3
颜色高阶 SHatt_sh球谐 3 阶,视角相关3·15 = 45

颜色用球谐函数(spherical harmonics, degree 3),和 3DGS 一模一样——DC 项是基色, 高阶项让颜色随视角变化(镜面高光、各向异性反射)。primal(原始顶点)这个词指的就是 Voronoi site, 因为 Voronoi 是 Delaunay 的对偶,site 是 Delaunay 的"原始"顶点。

规模感(来自官方配置 configs/*.yaml):初始 init_points = 131072$2^{17}$), 训练中长到 final_points——室内 $2^{21}\approx$ 210 万,室外 $2^{22}\approx$ 420 万。 所以一个训练好的模型大约是2–4 百万个细胞

§6cell-to-cell:光线怎么穿过泡沫

这是 Radiant Foam 的心脏,也是那个"被遗忘的老算法"。光线追踪在这里不查 BVH、不做求交测试树, 而是像在迷宫里贴着墙走:

  1. 入口:找光线起点 $\mathbf{o}$ 所在的细胞,即最近的 site $i \leftarrow \mathrm{nn}(\mathbf{o})$。这是唯一一次空间查询(用一棵 AABB 树),整条光线只做这一次。
  2. 找出口:在当前细胞 $i$,遍历它的 Delaunay 邻居 $j$。 细胞 $i,j$ 之间的墙,是两 site 的垂直平分面——法向 $\mathbf{n}_{ij}=\mathbf{p}_j-\mathbf{p}_i$, 过中点 $\mathbf{m}_{ij}=\tfrac12(\mathbf{p}_i+\mathbf{p}_j)$。光线和这个平面的交点参数是个除法就能算:
$$ t_{ij} = \frac{(\mathbf{m}_{ij}-\mathbf{o})\cdot\mathbf{n}_{ij}}{\mathbf{d}\cdot\mathbf{n}_{ij}} $$
  1. 取所有邻居里最近的、朝前的那个交点(要求 $\mathbf{d}\cdot\mathbf{n}_{ij}>0$,即朝 $j$ 那侧穿出)。 对应的邻居就是下一个细胞
  2. 终止:透射率 $T<\epsilon$ 就停。

为什么这是 Radiant Foam 的胜负手:找下一格只花 O(邻居数) 次平面求交,邻居数是小常数, 而且除入口外不需要任何全局加速结构。论文明说:"我们不需要层次加速结构,因此避开了相应的 $O(\log n)$ 查询。"这就是为什么它能在普通 GPU 上跑赢用 RTX BVH 的 3DGRT。

这段逻辑在代码 src/tracing/tracing_utils.cuh 里几乎可以一比一对上——下面是把 CUDA 核翻成 教学版 Python,这就是上面演示里光线真正在做的事

# 一条光线穿过 Voronoi 泡沫:cell-to-cell 行走 + 体积积分
# 对应 src/tracing/tracing_utils.cuh 的 trace() 与 pipeline.cu 的 forward 核
def trace(o, d, sites, adjacency, density, sh_color, eps=0.01):
    cur = nearest_site(o)          # 入口:整条光线唯一一次空间查询(AABB 树)
    t_enter = 0.0
    T = 1.0                        # 透射率
    C = zeros(3)                   # 累积颜色
    while T > eps:
        # 1) 在当前细胞,对每个 Delaunay 邻居测它们之间的垂直平分面
        t_exit, nxt = inf, -1
        p_i = sites[cur]
        for j in adjacency[cur]:               # O(邻居数),没有 BVH
            n = sites[j] - p_i                 # 垂直平分面法向
            m = 0.5 * (sites[j] + p_i)         # 面上一点(中点)
            dp = dot(n, d)
            if dp <= 0: continue               # 面朝后,穿不出去
            t = dot(m - o, n) / dp             # 光线 ⨉ 平面
            if 0 < t < t_exit:                 # 最近的朝前出口
                t_exit, nxt = t, j
        if nxt < 0: break

        # 2) 这一段(弦长 δ)做一次精确的体积积分
        delta = t_exit - t_enter
        sigma = density[cur]
        alpha = 1.0 - exp(-sigma * delta)      # α = 1 − exp(−σδ)
        c = eval_sh(sh_color[cur], d)          # 视角相关颜色(球谐 3 阶)
        C += T * alpha * c                     # C += T·α·c
        T *= (1.0 - alpha)                     # T ← T·(1−α)

        # 3) 跨墙,进入下一个细胞
        cur, t_enter = nxt, t_exit
    return C, 1.0 - T                           # 颜色 + 不透明度
Demo 2 · 光线行走 = 真正的渲染器
青点是相机,橙线是光线。它逐个细胞穿过泡沫(黑点是穿墙点,浅橙圈是被走过的细胞)。 颜色越深的细胞密度越高。转动角度看光线穿过的细胞序列怎么变;加大"密度强度"看透射率 T 怎么更快掉到 0 然后提前停。打开平分面测试,能看到首格在对所有邻居做"哪面先被穿出"的判断——这正是代码里的内层循环。

§7精确的体积积分(为什么"分段常数"这么关键)

回到 §2 的和式。NeRF 里 $\sigma(t)$ 是连续曲线,把它切成小段求和是近似,段越多越准、越慢。 Radiant Foam 里 $\sigma$ 在每个细胞内就是常数,所以"切成段"不是近似手段,而是密度场本身的 形状。每段贡献 $\alpha_n=1-e^{-\sigma_n\delta_n}$解析精确的,$\delta_n$ 就是上一节算出来的两个穿墙点之间的距离 $t_{\text{exit}}-t_{\text{enter}}$

代码里这段就是 pipeline.cu 的 forward 核(每段调用一个 CellFunctor):

# pipeline.cu 前向核里每段的累积(已贴近 CUDA 写法)
delta_t = max(t_1 - t_0, 0.0)               # 弦长
s = activation_scale * softplus(raw_density, beta=10)
alpha  = 1.0 - exp(-s * delta_t)            # 精确 alpha
weight = transmittance * alpha              # T·α
accumulated_rgb += weight * rgb             # 前向合成
transmittance   *= (1.0 - alpha)            # 更新 T
# 同时累积:不透明度、num_intersections、可选的逐点 contribution、
# 以及在指定 depth_quantiles 处的深度(喂给训练的 quantile 损失)

顺带记住两个副产物,后面训练要用:num_intersections(这条光线穿过几个细胞,反映哪些细胞被看到) 和 contribution(每个细胞对最终颜色贡献多少,用于剪枝)。

§8零面积翻转:可微的命门

现在到全篇最妙、也最容易被忽略的一点。要训练,就得对 site 位置 $\mathbf{p}_i$ 求导。但有个吓人的问题: 当 site 移动,Delaunay 的连接关系会突然改变(一条边/一个面 "翻转 flip")。连接关系是离散的, 离散的东西怎么求导?

论文的答案优雅到像作弊:Delaunay 翻转恰好发生在受影响的 Voronoi 面"面积为零"的那一刻。

把这句话刻进脑子

四个点共球(cocircular / cospherical)时 Delaunay 翻转——而此时即将出现/消失的那面 Voronoi 墙 面积正好是 0。由于渲染只对非零弦长积分,一面零面积的墙贡献为 0、弦长为 0。 所以连接关系是离散跳变的,但颜色作为 site 位置的函数是连续的——离散翻转被藏在了"零体积"区域里。 普通 autodiff 直接成立,不需要 straight-through、不需要 stop-gradient、不需要任何特殊重参数化。

这也解释了一个设计选择:为什么用 Voronoi 而不是直接渲染 Delaunay 网格?因为 Delaunay 网格在翻转时会真的 跳变(一个四面体突然换了形状),而它的对偶 Voronoi 不会——跳变被零面积吸收了。下面这个演示就是在 2D 里 把这件事演给你看。

Demo 3 · 拖过翻转点,看墙长归零
四个 site(L/R/B/T)。橙色粗线是 L–R 与 B 两块细胞之间共享的 Voronoi 墙,青色虚线是当前的 Delaunay 对角线。慢慢把 T 往下推:墙长会缩到 0——就在这一刻 Delaunay 对角线从 L–R 翻成 T–B, 然后墙长又长回来。读数里墙长 = 0 的瞬间就是"零面积翻转"。连接变了,但画面没有跳变。这就是 Radiant Foam 可微的全部秘密。

§9梯度从哪里来

既然翻转安全,剩下的就是普通链式法则。损失 → 光线颜色 $\mathbf{C_r}$ → 弦长 $\delta_n=t_{\text{exit}}-t_{\text{enter}}$ → 平分面交点 $t$ → 两个 site 位置。 关键的一步是 $t$ 对 site 位置的导数——因为移动一个 site 会移动它所有的平分面, 从而改变弦长、改变权重。代码 cell_intersection_grad 把它写成闭式:

$$ \frac{\partial t}{\partial \mathbf{p}_i} \;=\; \frac{1}{(\mathbf{d}\cdot\mathbf{n})^2}\Big[\,\underbrace{(\mathbf{m}-\mathbf{o})\cdot\mathbf{n}}_{\text{num}}\;\mathbf{d} \;+\; (\mathbf{d}\cdot\mathbf{n})\,(\mathbf{o}-\mathbf{p}_i)\,\Big] $$

密度 $\sigma_i$ 和颜色 SH $\mathbf{c}_i$ 拿的是普通辐射场梯度(对 $\alpha$ 和合成的导数)。在 PyTorch 侧,整个光追被包成一个 torch.autograd.Functionradfoam_model/render.pyTraceRays):forwardtrace_forwardbackwardtrace_backward, 只对 pointsattributes 回传梯度(邻接表、光线本身不可导)。非有限的梯度会在 Python 侧清零。

§10初始化:从 COLMAP 点云出发

和 3DGS 一样,泡沫从 SfM 稀疏点云长出来(data_loader/colmap.pypycolmapsparse/0/)。具体(RadFoamScene.initialize_from_pcd):

  • 取点:从 COLMAP 点里有放回地采约 90%,加一点抖动(+= randn · 1e-2)。
  • 补点:再撒一批随机点铺满场景空白处。这些背景/随机点的初始密度设成负数, 这样它们一开始不贡献,等优化决定要不要"激活"。
  • 凑数到 $2^{17}$:总数对齐到 init_points = 131072。 消融里"不用 SfM"就是改成从正态分布(std≈10)采 $2^{17}$ 点——会掉约 2 dB。
  • 颜色:DC 从点云 RGB 初始化,高阶 SH 置 0。
  • 建初始三角剖分:在这些点上用自研 CUDA Delaunay 建剖分(见 §12)。

§11训练循环与损失

训练是按光线批次(不是整图)跑 iterations = 20000 步。单个 Adam(eps=1e-15), 分四个参数组,每组独立的余弦学习率(来自 configs/*.yaml + utils.py):

参数组init lrfinal lr备注
位置 primal_points2e-45e-6freeze_points=18000 步后冻结
密度 density1e-11e-2warmup 到 densify_from
颜色 DC att_dc5e-35e-4
高阶 SH att_sh5e-3·sh_factor同比warmup 到 iterations/5(SH 晚启动)

损失三项(注意:没有 SSIM 项,这点和 3DGS 不同):

# train.py 每步的损失(光线批次)
color_loss   = SmoothL1Loss(rgb_pred, rgb_gt)          # Huber 颜色损失
opacity_loss = ((alpha_pred - mask_gt) ** 2).mean()    # 监督前景/不透明度
# quantile 深度损失:惩罚两个深度分位点的间距 ≈ 让权重集中在表面(抗 floater)
quant_loss   = (abs(depth_q[..., 0] - depth_q[..., 1]) * valid).mean()
w_depth      = quantile_weight * min(2 * step / iterations, 1.0)   # 半程升满
loss = color_loss.mean() + opacity_loss + w_depth * quant_loss

$\mathcal{L}_{\text{quantile}}$ 是 Mip-NeRF360 distortion 损失精神的"瘦身项":随机取两个深度分位数, 惩罚它们的间距,逼着每条光线的权重集中到一个薄表面而不是糊成一片雾。权重 quantile_weight = 1e-4(Deep Blending 上设 0)。还有个分辨率退火:图像先降采样再变清晰 (downsample=[4,2] 室内 / [8,4] 室外,在第 5000 步切换),coarse-to-fine。

整盘训练在 RTX 4090 上、bonsai 场景 2 万步约 70 分钟。最后 2000 步(18000→20000)位置冻结, 只优化密度和颜色——几何定型后精修外观。

§12自适应密度控制 + 重建三角剖分(动态拓扑)

这是 Radiant Foam 工程上最重的部分,也是消融里最不能少的一环(去掉 densification,PSNR 从 ~29 崩到 19.4)。 两件事在同时发生:点在增删,连接在重建。

致密化 Densify(加点)

哪些细胞欠拟合?用重建损失对 site 位置的梯度大小 × 细胞半径作为"重要性"。直觉:梯度大 = 这块没拟合好, 细胞大 = 这块分辨率不够,两者都该加点。代码(prune_and_densify)按这个权重做 torch.multinomial 采样新点,新点沿"最远邻居"方向偏移放置,并继承父细胞的颜色和密度。 点数几何增长densify_factor=1.15(每轮 ×1.15),从 densify_from=2000densify_until=11000 步,把 $2^{17}$ 一路抬到 final_points

剪枝 Prune(删点)

删掉那些贡献极低、细胞又小、且邻居也都没贡献的点——既不在表面上、也不靠近表面。 另外贡献 < 1e-3 的点直接把密度设成 -1 压制掉。消融显示剪枝对 PSNR 几乎中性,主要是让模型更干净。

Demo 4 · 误差驱动的致密化
虚线圆是场景里一个"表面"(颜色突变处)。一开始点是均匀撒的,泡沫只能用粗块逼近,圆边误差很大。 每点一次"致密化",新点就按误差大小被采到——于是点不断往表面(圆边)聚集, 误差读数随之下降。这正是 Radiant Foam 用"梯度 × 细胞半径"加点的效果:算力花在该花的地方。

重建 Delaunay(连接关系的维护)

site 一动一增删,Delaunay 就可能失效,得重建。两个关键工程技巧:

  • 把优化步和重建步解耦,重建周期从小到大。train.pytriangulation_update_period 从致密化后的"几乎每步重建"开始,每次 +2,最多到 100—— 早期连接变化快就勤建,后期泡沫稳定了就让它漂 ~100 步再建一次。这之所以安全,正是因为 §8:小位移很少触发翻转, 而翻转又是梯度安全的。
  • 自研 GPU Delaunaysrc/delaunay/),不用 CGAL/qhull/scipy,构建在 NVIDIA CUB + Shewchuk 精确谓词上:排序点 → 去重 → 建 AABB 树 → 采初始四面体 → "最大空球"生长循环 → 抽邻接表(CSR)。 退化配置(共面/共球)靠随机扰动 + 重试救回来(README 明说这是个鲁棒性软肋,25 次失败才报错)。

致密化时和冻结点那一刻(第 18000 步)会做完整重建;其余时候是增量重建。邻接关系最终以 CSR 形式存(point_adjacency + point_adjacency_offsets),就是 §6 光线行走读的那张表。

§13数字与消融

数据集 Mip-NeRF360(7 个公开场景)与 Deep Blending。重点不是"刷分第一",而是在"实时光追"这个赛道里 它是唯一又快又好的

方法是否光追PSNR↑SSIM↑LPIPS↓FPS↑
3DGS否(光栅化)28.690.870.22293
Mip-Splatting29.390.880.20241
Mip-NeRF360是(MLP)29.230.840.21<1
3DGRT(硬件光追高斯)是(需 RT 核)28.710.850.2578
Radiant Foam是(无需 RT 核)28.470.830.21200

(Mip-NeRF360 上的均值。Deep Blending 上 Radiant Foam 是 28.95 / 0.89 / 0.26 @ 301 FPS,对应 3DGRT 只有 119 FPS。) 画质和 3DGS / 3DGRT 差不到 1 dB,但作为光线追踪方法,它比硬件光追的 3DGRT 快 2–3 倍,且不用 RTX 光追核心。

消融(PSNR,均值)一眼看出哪块是骨架:

去掉哪一块PSNR 均值结论
完整模型29.15基准
去掉致密化19.36灾难——单点最重要的组件
去掉 quantile 损失27.90掉 ~1.25 dB,floater 变多
去掉 SfM 初始化27.00掉 ~2 dB,但能 work
去掉剪枝29.15≈ 中性(只是更干净)

§14ray tracing 白送的能力

既然光线是真的在追,很多 splatting 做不了或要打补丁的事,Radiant Foam 几乎免费:

  • 非针孔相机:鱼眼、镜头畸变、滚动快门、运动模糊——因为你是"投射一束任意光线",不是把椭球正向投影。
  • 二次光线:反射、折射、透明——光追的看家本领,光栅化天生做不到。
  • 精确可见性,无排序:光线按真实几何顺序穿过细胞,没有 3DGS 的深度排序和 popping 伪影。
  • 不挑硬件:用 Voronoi 行走($O(\deg)$)替代 BVH($O(\log n)$),普通可编程 GPU 就够。
  • 精确积分:分段常数让体渲染和式严格等于积分,没有 NeRF 的数值近似,也没有高斯叠加近似。

§15Foam 家族:直接继承 Radiant Foam 的后续工作

Radiant Foam 很新(2025 初),但已经长出一支可辨认的"Foam 家族"。下面按继承得有多直接排序: Tier 1 是真的在用/扩展 Voronoi 泡沫表示;Tier 2 是围绕它做系统/工具;Tier 3 是同思路的近邻(引用它做对比, 但没采用泡沫)。诚实声明:这些都是 2025-12 到 2026-05 的前沿工作(mustard 标签), 下面每一篇的标题、作者、arXiv 编号都已逐一核对过 arXiv 页面确认存在;其中 Power Foam、Semantic Foam、SDFoam、Foam-on-IPU 四篇在摘要里明确点名扩展/渲染 Radiant Foam,其余几篇(Scalable GPU Voronoi、Radiance Meshes、Spherical Voronoi) 是同思路或赋能工具,与泡沫的具体关系以原文为准。

Tier 1 · 表示层的真后裔(采用/扩展 Voronoi 泡沫)

Power Foam — Unifying Real-Time Differentiable Ray Tracing and Rasterization
2026-04 Govindarajan, Rebain, Verbin, Yi, Prabhu, Tagliasacchi · theialab(原班人马) · arXiv:2604.24994

Voronoi 细胞是无界的,没法做 3DGS 那种瓦片光栅化——于是 Radiant Foam 上不了最快的栅格化车道。

关键想法:把无界 Voronoi 泡沫推广成有界的 power diagram(带权 Voronoi,可控细胞半径), 省去昂贵的 Delaunay;再加一个"有向表面"形式刻画内外界面,并用可微纹理把几何和外观解耦。结果是一个表示 同时支持实时光追(泡沫式)和栅格化(媲美 3DGS)。论文开篇直说"我们扩展 Radiant Foam,先简要回顾它"。

Radiant Foam 只能光追;Power Foam 用 power diagram 把同一表示既能光追又能栅格化,是最直接的继承者。

Semantic Foam — Unifying Spatial and Semantic Scene Decomposition
CVPR 2026 Highlight Sharafeldin, Govindarajan, Walker, Mikaeili, Rebain, Yi, Tagliasacchi · arXiv:2604.26262

开放词表 / 物体级的场景语义分解,点式(3DGS)方法缺乏空间正则,监督不一致时易出伪影。

关键想法:在泡沫上挂一个逐 Voronoi-cell 的语义特征场,把 Radiant Foam 的 空间体积划分当成天然正则——细胞的空间一致性帮语义跨视角对齐,在分割上超过 Gaussian Grouping / SAGA。 论文明确"将 Radiant Foam 表示扩展到语义分解"。

Radiant Foam 只重建辐射;Semantic Foam 给每个细胞再加一层语义特征,把泡沫变成可分割的语义体。

SDFoam — Signed-Distance Foam for explicit surface reconstruction
2025-12 Rech, Conci, Garau · University of Trento(独立团队) · arXiv:2512.16706

Radiant Foam 辐射重建好,但 Voronoi 面不贴合真实表面,留下 floater、抽不出干净网格。

关键想法:把泡沫的显式 Voronoi 图和一个隐式 SDF 联合学习,用 SDF 的零等值面把 近表面的细胞墙"吸"到真实表面上(每个细胞视作局部 SDF)。表面更清晰、跨视角更一致、floater 更少,速度质量相当。

Radiant Foam 的细胞墙是为辐射服务的;SDFoam 加 SDF 约束让墙对齐几何表面,转向表面重建。

Tier 2 · 围绕它做的系统 / 工具

Foam on IPU — Radiant Foam Rendering on a Graph Processor
2026-01 Tuya, Alzugaray, Fry, Davison · Imperial College(Dyson Robotics Lab) · arXiv:2601.04382

关键想法:把训练好的泡沫部署到 Graphcore IPU(1472 个 tile)上做全 SRAM 分布式渲染—— 把细胞分片到各 tile,光线在分片间转发。它正好吃到了 Radiant Foam"局部邻接、逐格行走"的特性。系统/部署工作,不是新表示。

Scalable GPU Voronoi — Scalable GPU Construction of 3D Voronoi and Power Diagrams
2026-05 Taveira, Lindström, Fatemi, Hammarstrand, Kahl · Chalmers · arXiv:2605.06408

关键想法:一个高度并行的 GPU 算法,快速构建大规模 3D Voronoi / power diagram,面向"mesh-based 神经渲染" 这类应用。它正好能替换 Radiant Foam 的 Voronoi 构建步、解掉建图瓶颈,把规模推到 >20M 点注:其摘要里并未点名 Radiant Foam,"赋能泡沫"是按用途的合理推断,不是论文自述的对标。

Tier 3 · 近邻(同思路、引用它做对比,但没采用泡沫)

Radiance Meshes — Radiance Meshes for Volumetric Reconstruction
2025-12 Mai, Hedstrom, Kopanas, Kontkanen, Kuester, Barron · UCSD / Google · arXiv:2512.04076

Voronoi 细胞面多(约 15 面),不友好于现成图形硬件。

关键想法:用 Delaunay 四面体(泡沫的对偶结构,每个只有 4 面)做常密度体元, 栅格化和光追都能跑,并支持鱼眼、网格抽取。把 Radiant Foam 当主要对比基线(报告室内光追快 17%)。

Radiant Foam 渲染 Voronoi 多面体(避翻转跳变);Radiance Meshes 故意改回渲染四面体,换取硬件友好——是刻意的"非泡沫"替代方案。

Spherical Voronoi — Directional Appearance as a Differentiable Partition of the Sphere
2025-12 Di Sario, Rebain, Verbin, Grangetto, Tagliasacchi · arXiv:2512.14180

关键想法:同实验室、同"可微 Voronoi 划分"哲学,但用在方向/外观域——用球面上的 Voronoi 划分替代 3DGS 的球谐来表达视角相关颜色。是兄弟而非空间泡沫的后继。

§A还没解决的问题

从研究里能看到的明确缺口:

  • Delaunay 鲁棒性。退化配置靠随机扰动 + 重试硬扛,README 自己承认这是软肋;大场景上更脆。
  • 建图开销。增量 Delaunay 仍然贵,所以才要把重建周期拉到 1:100——Scalable GPU Voronoi 就是冲这个来的。
  • 动态 / 4D 场景。截至 2026-06,没有可核实的"动态版 Radiant Foam"或 SLAM 版后续;时变拓扑是天然难点。
  • 表面质量。原版的细胞墙不贴表面、有 floater——SDFoam 在补,但还没到 3DGS-surface 系的成熟度。
  • 栅格化车道。无界细胞上不了瓦片栅格化,Power Foam 用 power diagram 在解,但代价是放弃纯 Voronoi 的简洁。
  • 显存 / 体积。论文没公布 MB 级模型体积;2–4M 细胞 ×(位置 + 密度 + 48 SH)不算小。
总结一句话

Radiant Foam 的全部聪明可以压成两句:(a) 把空间切成 Voronoi 泡沫,光线靠"邻居垂直平分面" 一格一格走,就能 O(邻居数) 地实时光追、无需 BVH 无需排序无需 RT 核;(b) Delaunay 翻转恰好发生在 Voronoi 面 零面积处,于是连接离散跳变、画面却连续可导——普通 autodiff 直接能训。 其余一切(COLMAP 初始化、致密化、quantile 损失、增量重建)都是围着这两句话拧的螺丝。

§B名词表 · Glossary

术语解释
Voronoi 细胞空间里离某个 site 最近的区域;凸多面体,铺满全空间 = "泡沫"。
site / primal point可学习的点,每个拥有一个 Voronoi 细胞。论文里也叫 primal vertex。
Delaunay 三角剖分Voronoi 的对偶图;它的边告诉你哪两个细胞相邻 = 光线能去哪。
垂直平分面 bisector两个 site 的等距面,正是它们两块细胞之间的那堵墙。
透射率 T光走到某处还没被吸收的比例;$T \leftarrow T(1-\alpha)$
alpha $\alpha$一段把光吃掉的比例,$1-e^{-\sigma\delta}$
分段常数密度/颜色在每个细胞内是常数,使体积积分变成精确的解析和式。
零面积翻转Delaunay 翻转发生时受影响的 Voronoi 面面积为 0,贡献为 0 → 表示对位置连续可导。
致密化 densify按"梯度 × 细胞半径"加点;点数 ×1.15 几何增长。
quantile 损失惩罚两个深度分位点的间距,逼权重集中到薄表面,抗 floater。
CSR 邻接point_adjacency + offsets,压缩存储每个 site 的邻居表。
3DGRT硬件光追版高斯(用 RTX BVH);Radiant Foam 不用 RT 核却比它快 2–3×。
power diagram带权 Voronoi(细胞可有界);Power Foam 用它打通栅格化。

§C推荐阅读顺序

不是按时间,是按"理解的台阶"排的:

  1. NeRF 的体渲染那一节(你已经会)——确认 §2 那条积分在脑子里。
  2. Radiant Foam 正文 §3–§4(表示 + 渲染)——配着本页 §4、§6 的两个 demo 读。
  3. Radiant Foam §3 的可微性论证——本页 §8 的翻转 demo 是它的可视化,先玩再读。
  4. 官方代码 radfoam_model/scene.py——把 §5/§11/§12 的参数对到真实 nn.Parameter 和优化器组。
  5. src/tracing/tracing_utils.cuh——把 §6 的教学 Python 对到真正的 CUDA 行走核。
  6. Power Foam——理解"为什么无界细胞是个问题",顺势看懂栅格化车道。
  7. Radiance Meshes——作为"故意不用泡沫"的对照,反过来体会泡沫的取舍。

Made for learning. 方法解读基于 Radiant Foam (arXiv:2502.01157, ICCV 2025) 论文、项目页与官方代码仓 theialab/radfoam。完整 BibTeX、勘误、补遗欢迎 issue。最后更新 2026-06-01。

交互演示是 Canvas2D 的二维教学玩具,用来传达机制直觉,数值不代表论文实际三维性能。 §15 的后续工作为 2025-12 至 2026-05 的前沿引用(mustard 标签),七篇的标题/作者/arXiv 编号均已逐一核对存在; "是否扩展 Radiant Foam"已按各自摘要据实标注,细节请以原文为准。