方法逐行拆解 · 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
同样是把场景画出来,三条路线的代价结构完全不同。把这张表刻在脑子里——后面每一节都在解释表里的某一格
为什么成立。
| NeRF | 3DGS(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 不无相似,只是少了每点的协方差矩阵。"
§5每个 cell 存什么
在代码里(radfoam_model/scene.py 的 RadFoamScene),每个 site 是几个并排的
nn.Parameter。一共三类可学习量:
| 属性 | 张量 | 含义 / 激活 | 大小(per site) |
| 位置 $\mathbf{p}_i$ | primal_points | site 坐标,唯一决定几何 | 3 |
| 密度 $\sigma_i$ | density | 标量;scale · softplus(·, β=10) | 1 |
| 颜色 DC | att_dc | SH 0 阶(与视角无关的基色) | 3 |
| 颜色高阶 SH | att_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、不做求交测试树,
而是像在迷宫里贴着墙走:
- 入口:找光线起点 $\mathbf{o}$ 所在的细胞,即最近的 site
$i \leftarrow \mathrm{nn}(\mathbf{o})$。这是唯一一次空间查询(用一棵 AABB 树),整条光线只做这一次。
- 找出口:在当前细胞 $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}} $$
- 取所有邻居里最近的、朝前的那个交点(要求 $\mathbf{d}\cdot\mathbf{n}_{ij}>0$,即朝 $j$ 那侧穿出)。
对应的邻居就是下一个细胞。
- 终止:透射率 $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 # 颜色 + 不透明度
§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.Function(radfoam_model/render.py
的 TraceRays):forward 调 trace_forward,backward 调 trace_backward,
只对 points 和 attributes 回传梯度(邻接表、光线本身不可导)。非有限的梯度会在 Python 侧清零。
§10初始化:从 COLMAP 点云出发
和 3DGS 一样,泡沫从 SfM 稀疏点云长出来(data_loader/colmap.py 用 pycolmap 读
sparse/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 lr | final lr | 备注 |
位置 primal_points | 2e-4 | 5e-6 | 到 freeze_points=18000 步后冻结 |
密度 density | 1e-1 | 1e-2 | warmup 到 densify_from |
颜色 DC att_dc | 5e-3 | 5e-4 | — |
高阶 SH att_sh | 5e-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=2000 到
densify_until=11000 步,把 $2^{17}$ 一路抬到 final_points。
剪枝 Prune(删点)
删掉那些贡献极低、细胞又小、且邻居也都没贡献的点——既不在表面上、也不靠近表面。
另外贡献 < 1e-3 的点直接把密度设成 -1 压制掉。消融显示剪枝对 PSNR 几乎中性,主要是让模型更干净。
Demo 4 · 误差驱动的致密化
虚线圆是场景里一个"表面"(颜色突变处)。一开始点是均匀撒的,泡沫只能用粗块逼近,圆边误差很大。
每点一次"致密化",新点就按误差大小被采到——于是点不断往表面(圆边)聚集,
误差读数随之下降。这正是 Radiant Foam 用"梯度 × 细胞半径"加点的效果:算力花在该花的地方。
重建 Delaunay(连接关系的维护)
site 一动一增删,Delaunay 就可能失效,得重建。两个关键工程技巧:
- 把优化步和重建步解耦,重建周期从小到大。
train.py 里
triangulation_update_period 从致密化后的"几乎每步重建"开始,每次 +2,最多到 100——
早期连接变化快就勤建,后期泡沫稳定了就让它漂 ~100 步再建一次。这之所以安全,正是因为 §8:小位移很少触发翻转,
而翻转又是梯度安全的。
- 自研 GPU Delaunay(
src/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.69 | 0.87 | 0.22 | 293 |
| Mip-Splatting | 否 | 29.39 | 0.88 | 0.20 | 241 |
| Mip-NeRF360 | 是(MLP) | 29.23 | 0.84 | 0.21 | <1 |
| 3DGRT(硬件光追高斯) | 是(需 RT 核) | 28.71 | 0.85 | 0.25 | 78 |
| Radiant Foam | 是(无需 RT 核) | 28.47 | 0.83 | 0.21 | 200 |
(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
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
开放词表 / 物体级的场景语义分解,点式(3DGS)方法缺乏空间正则,监督不一致时易出伪影。
关键想法:在泡沫上挂一个逐 Voronoi-cell 的语义特征场,把 Radiant Foam 的
空间体积划分当成天然正则——细胞的空间一致性帮语义跨视角对齐,在分割上超过 Gaussian Grouping / SAGA。
论文明确"将 Radiant Foam 表示扩展到语义分解"。
Radiant Foam 只重建辐射;Semantic Foam 给每个细胞再加一层语义特征,把泡沫变成可分割的语义体。
SDFoam
— Signed-Distance Foam for explicit surface reconstruction
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
关键想法:把训练好的泡沫部署到 Graphcore IPU(1472 个 tile)上做全 SRAM 分布式渲染——
把细胞分片到各 tile,光线在分片间转发。它正好吃到了 Radiant Foam"局部邻接、逐格行走"的特性。系统/部署工作,不是新表示。
Scalable GPU Voronoi
— Scalable GPU Construction of 3D Voronoi and Power Diagrams
关键想法:一个高度并行的 GPU 算法,快速构建大规模 3D Voronoi / power diagram,面向"mesh-based 神经渲染"
这类应用。它正好能替换 Radiant Foam 的 Voronoi 构建步、解掉建图瓶颈,把规模推到 >20M 点。
注:其摘要里并未点名 Radiant Foam,"赋能泡沫"是按用途的合理推断,不是论文自述的对标。
Tier 3 · 近邻(同思路、引用它做对比,但没采用泡沫)
Radiance Meshes
— Radiance Meshes for Volumetric Reconstruction
Voronoi 细胞面多(约 15 面),不友好于现成图形硬件。
关键想法:用 Delaunay 四面体(泡沫的对偶结构,每个只有 4 面)做常密度体元,
栅格化和光追都能跑,并支持鱼眼、网格抽取。把 Radiant Foam 当主要对比基线(报告室内光追快 17%)。
Radiant Foam 渲染 Voronoi 多面体(避翻转跳变);Radiance Meshes 故意改回渲染四面体,换取硬件友好——是刻意的"非泡沫"替代方案。
Spherical Voronoi
— Directional Appearance as a Differentiable Partition of the Sphere
关键想法:同实验室、同"可微 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推荐阅读顺序
不是按时间,是按"理解的台阶"排的:
- NeRF 的体渲染那一节(你已经会)——确认 §2 那条积分在脑子里。
- Radiant Foam 正文 §3–§4(表示 + 渲染)——配着本页 §4、§6 的两个 demo 读。
- Radiant Foam §3 的可微性论证——本页 §8 的翻转 demo 是它的可视化,先玩再读。
- 官方代码
radfoam_model/scene.py——把 §5/§11/§12 的参数对到真实 nn.Parameter 和优化器组。
src/tracing/tracing_utils.cuh——把 §6 的教学 Python 对到真正的 CUDA 行走核。
- Power Foam——理解"为什么无界细胞是个问题",顺势看懂栅格化车道。
- Radiance Meshes——作为"故意不用泡沫"的对照,反过来体会泡沫的取舍。