本章深入探讨神经隐式曲面表示方法和3D Gaussian Splatting技术。我们将学习如何使用神经网络表示3D几何,理解NeuS、VolSDF等前沿方法的原理,掌握从隐式表示到显式网格的转换技术,并详细了解3DGS这一革命性的实时渲染方法。通过本章学习,读者将掌握现代神经几何表示的核心技术,能够实现高质量的3D重建和实时渲染。
| 神经隐式曲面使用神经网络 $f_\theta: \mathbb{R}^3 \rightarrow \mathbb{R}$ 表示有符号距离函数(SDF),其中零等值面 ${x \in \mathbb{R}^3 | f_\theta(x) = 0}$ 定义了3D物体的表面。与传统的显式网格表示相比,隐式表示具有以下优势: |
SDF的关键性质是满足Eikonal方程: \(\|\nabla f_\theta(x)\| = 1\)
这保证了函数值确实表示到最近表面的有符号距离。
NeuS的核心创新在于将体积渲染和曲面渲染统一在一个框架下。对于一条光线 $r(t) = o + td$,传统的体积渲染方程为:
\[C(r) = \int_0^{\infty} T(t) \sigma(t) c(r(t), d) dt\]其中 $T(t) = \exp(-\int_0^t \sigma(s) ds)$ 是透射率。
NeuS通过定义一个特殊的密度函数,将SDF转换为体积密度:
\[\sigma(x) = \Phi_s'(f_\theta(x))\]这里 $\Phi_s$ 是带参数 $s$ 的S型函数(如Sigmoid或Laplace CDF):
\[\Phi_s(x) = \begin{cases} \frac{1}{2}\exp(\frac{x}{s}) & x \leq 0 \\ 1 - \frac{1}{2}\exp(-\frac{x}{s}) & x > 0 \end{cases}\]NeuS的关键贡献是设计了无偏的权重函数,确保在SDF的零等值面处权重达到最大值。权重函数定义为:
\[w(t) = T(t)\sigma(t) = \exp(-\int_0^t \sigma(s)ds) \cdot \sigma(t)\]通过巧妙的数学推导,NeuS证明了当 $s \rightarrow 0$ 时,权重函数在SDF零等值面处收敛到Dirac delta函数,从而实现了准确的表面重建。
关键的数学关系: \(\lim_{s \rightarrow 0} w(t) = \delta(f_\theta(r(t)))\)
NeuS的训练使用多个损失项的组合:
颜色损失: \(\mathcal{L}_{color} = \sum_{r \in \mathcal{R}} \|C(r) - \hat{C}(r)\|^2\)
Eikonal正则化: \(\mathcal{L}_{eikonal} = \mathbb{E}_x[(\|\nabla f_\theta(x)\| - 1)^2]\)
掩码损失(如果有前景掩码): \(\mathcal{L}_{mask} = BCE(O(r), \hat{O}(r))\)
其中 $O(r) = \int_0^{\infty} T(t)\sigma(t)dt$ 是不透明度。
总损失函数: \(\mathcal{L} = \mathcal{L}_{color} + \lambda_{eik}\mathcal{L}_{eikonal} + \lambda_{mask}\mathcal{L}_{mask}\)
训练策略包括:
VolSDF提出了一种不同的密度-SDF转换方法,使用Laplace分布的累积分布函数(CDF):
\[\rho(x) = \frac{1}{\beta} \Psi_\beta(f_\theta(x))\]其中 $\Psi_\beta$ 是Laplace CDF: \(\Psi_\beta(s) = \begin{cases} \frac{1}{2}\exp(\frac{s}{\beta}) & s \leq 0 \\ 1 - \frac{1}{2}\exp(-\frac{s}{\beta}) & s > 0 \end{cases}\)
参数 $\beta$ 控制转换的锐度,类似于NeuS中的 $s$ 参数。VolSDF的一个关键优势是其理论保证:
定理:当 $\beta \rightarrow 0$ 时,体积渲染的不透明度收敛到指示函数: \(\lim_{\beta \rightarrow 0} O(r) = \mathbf{1}_{\{t^* \in [t_n, t_f]\}}\)
其中 $t^*$ 是光线与零等值面的交点。
VolSDF强调了几何正则化的重要性,使用多种先验约束:
采样策略 $\mathcal{P}$ 包括:
其中 $H(x)$ 是平均曲率,可通过SDF的二阶导数计算: \(H = \frac{1}{2}\nabla \cdot \left(\frac{\nabla f}{\|\nabla f\|}\right)\)
其中 $n(r) = \frac{\nabla f}{|\nabla f|}$ 是SDF梯度定义的法线。
VolSDF利用多视图信息增强几何重建:
光度一致性: 对于在多个视图中可见的3D点 $x$,要求其在不同视图下的颜色一致: \(\mathcal{L}_{photo} = \sum_{i,j} w_{ij} \|c_i(x) - c_j(x)\|^2\)
深度一致性(如果有深度监督): \(\mathcal{L}_{depth} = \sum_{r} \|d(r) - \hat{d}(r)\|^2\)
其中深度通过期望计算: \(d(r) = \int_0^{\infty} t \cdot w(t) dt\)
VolSDF使用层次化采样策略提高效率:
粗采样阶段: 沿光线均匀采样 $N_c$ 个点: \(t_i \sim \mathcal{U}[t_n, t_f]\)
细采样阶段: 基于粗采样的权重分布,使用逆变换采样额外 $N_f$ 个点: \(t_j \sim \frac{w(t)}{\int w(t)dt}\)
表面引导采样: 在预测的零等值面附近增加采样密度: \(t_k \sim \mathcal{N}(t^*, \sigma^2)\)
其中 $t^*$ 通过球面追踪或二分搜索获得。
神经SDF的训练效率很大程度上取决于采样策略。层次化采样通过多尺度方法逐步细化采样分布,这种策略源于计算机图形学中的重要性采样理论,能够显著减少方差并加速收敛。
两阶段采样算法:
算法:层次化光线采样
输入:光线 r(t) = o + td, 粗采样数 Nc, 细采样数 Nf
输出:采样点集合 {ti}
1. 粗采样阶段:
将 [tn, tf] 均分为 Nc 个区间
在每个区间 [ti, ti+1] 内均匀随机采样:
t = ti + (ti+1 - ti) * U(0,1)
2. 计算权重分布:
对每个采样点 ti 计算权重 wi = T(ti)σ(ti)Δti
归一化权重得到概率分布 pi = wi / Σwj
3. 细采样阶段:
构建CDF: CDFi = Σj≤i pj
生成 Nf 个均匀随机数 ui ∈ [0,1]
使用逆变换采样: ti = CDF^(-1)(ui)
4. 合并粗细采样点并排序:{t} = sort({tc} ∪ {tf})
这种采样策略的理论基础是蒙特卡洛积分的方差缩减技术。通过将更多采样点分配到对最终渲染贡献较大的区域(通常是表面附近),可以用较少的采样获得高质量的结果。
自适应采样密度控制: 根据几何特征动态调整采样密度,采样密度函数设计为: \(\rho_{sample}(x) = \alpha + \beta \cdot \|\nabla f(x)\| + \gamma \cdot |H(x)| + \delta \cdot \exp(-|f(x)|/\epsilon)\)
其中:
多分辨率采样网格: 使用空间哈希结构存储不同分辨率的采样密度:
结构:多分辨率采样网格
- Level 0: 8×8×8 粗网格,覆盖整个场景
- Level 1: 16×16×16 中等网格,覆盖物体边界框
- Level 2: 32×32×32 细网格,覆盖表面±ε范围
- Level 3+: 自适应octree,根据局部复杂度细分
重要性采样是减少蒙特卡洛估计方差的关键技术。在神经SDF中,我们需要根据多种信号自适应调整采样策略:
其中 $f_m$ 是第m个网络(或dropout采样)的预测,$\bar{f}$ 是平均预测。高不确定性区域需要更多采样以降低重建误差。
采样概率按照softmax分布: \(p(x) = \frac{\exp(\epsilon(x) / \tau)}{\int_{\Omega} \exp(\epsilon(y) / \tau) dy}\)
温度参数 $\tau$ 控制采样的集中程度。
| 其中 $H_f$ 是SDF的Hessian矩阵。主曲率的绝对值之和 $ | \kappa_1 | + | \kappa_2 | $ 作为采样密度的指导。 |
这种时序平滑避免采样分布的剧烈变化,提高训练稳定性。
神经SDF的优化面临独特挑战,需要专门的优化技巧:
其中 $\mu_g, \sigma_g$ 是梯度范数的移动平均和标准差,$k$ 通常取2-3。
权重函数: \(w_l(t) = \begin{cases} 1 & l \leq l_{base} \\ \sigma\left(\alpha \cdot (t/T - l/L)\right) & l > l_{base} \end{cases}\)
这种策略让网络先学习粗糙形状,再逐步添加细节。
球形初始化:适用于封闭物体 \(f_{\theta_0}(x) = \|x - c\| - r\)
平面初始化:适用于地面、墙面等 \(f_{\theta_0}(x) = n^T(x - p)\)
数据驱动初始化:使用粗糙点云或体素 \(f_{\theta_0}(x) = \text{SDF}_{pointcloud}(x)\)
预热阶段:线性增长 \(\eta_t = \eta_{base} \cdot \frac{t}{T_{warmup}}\)
主训练阶段:余弦退火 \(\eta_t = \eta_{min} + \frac{\eta_{max} - \eta_{min}}{2}(1 + \cos(\pi t/T))\)
精细化阶段:指数衰减 \(\eta_t = \eta_{base} \cdot \gamma^{t/T_{step}}\)
当某项损失下降较快时,自动减小其权重,让优化关注其他目标。
理解神经SDF的收敛行为对于诊断问题和改进算法至关重要:
理论收敛保证:
实现方法包括:
实际收敛诊断:
| Chamfer距离:$$CD = \frac{1}{ | S_1 | }\sum_{x \in S_1} \min_{y \in S_2} |x-y|^2 + \frac{1}{ | S_2 | }\sum_{y \in S_2} \min_{x \in S_1} |x-y|^2$$ |
| 法线一致性:$$NC = \frac{1}{ | S | }\sum_{x \in S} | n_{pred}(x) \cdot n_{gt}(x) | $$ |
典型参数:$\epsilon = 10^{-4}$,$k = 20-50$。
3D Gaussian Splatting (3DGS) 是一种革命性的3D场景表示方法,通过显式的高斯原语实现高质量的实时渲染。与神经隐式表示不同,3DGS使用数百万个各向异性3D高斯来表示场景,每个高斯具有位置、协方差、不透明度和颜色属性。
3D高斯的数学表示: 每个3D高斯由以下参数定义:
高斯的空间分布: \(G(x) = \exp\left(-\frac{1}{2}(x-\mu)^T\Sigma^{-1}(x-\mu)\right)\)
协方差矩阵的参数化: 为确保协方差矩阵的正定性和数值稳定性,3DGS使用分解形式: \(\Sigma = RSS^TR^T\)
其中:
这种参数化的优势:
球谐函数表示颜色: 为了建模视角相关的外观,3DGS使用球谐函数展开: \(c(\mathbf{d}) = \sum_{l=0}^{l_{max}} \sum_{m=-l}^{l} c_{lm} Y_l^m(\mathbf{d})\)
其中:
通常使用0-3阶球谐(16个系数),足以表示大多数视角相关效果:
3DGS的核心是高效的可微分光栅化算法,将3D高斯投影到2D图像平面:
投影过程:
其中 $\pi$ 是透视投影操作。
其中:
EWA(Elliptical Weighted Average)Splatting: 2D高斯的渲染使用EWA splatting技术: \(I(x,y) = \sum_{i \in \mathcal{N}} c_i \alpha_i G_{2D}^i(x,y) \prod_{j=1}^{i-1}(1-\alpha_j G_{2D}^j(x,y))\)
其中:
高效实现策略:
3DGS通过自适应的高斯增删策略优化场景表示:
密度自适应算法:
条件:梯度magnitude > τ_grad 或 尺度 > τ_size
操作:
- 创建两个子高斯
- 位置:μ₁ = μ + δ, μ₂ = μ - δ
- 尺度:s_new = s_old / φ (φ ≈ 1.6)
- 继承父高斯的颜色和不透明度
条件:梯度magnitude > τ_grad 且 尺度 < τ_size
操作:
- 创建副本高斯
- 位置:沿梯度方向偏移
- 保持相同尺度和属性
条件:
- 不透明度 α < τ_α (如0.005)
- 或尺度过大 max(sx, sy, sz) > τ_max
- 或尺度过小 max(sx, sy, sz) < τ_min
操作:删除高斯
自适应控制策略:
高梯度表示该区域需要更多细节。
3DGS实现实时渲染的关键优化技术:
GPU并行化策略:
__global__ void renderGaussians(
const Gaussian* gaussians,
const int* tile_lists,
float* output_image
) {
int pixel_id = blockIdx.x * blockDim.x + threadIdx.x;
int x = pixel_id % width;
int y = pixel_id / width;
float3 color = make_float3(0);
float alpha_acc = 0;
// 遍历影响该像素的高斯
for (int g : tile_lists[tile_id]) {
float2 diff = make_float2(x, y) - gaussians[g].center_2d;
float gauss_val = exp(-0.5f * dot(diff, inverse_cov * diff));
float alpha = gaussians[g].opacity * gauss_val;
// Alpha blending
color += (1 - alpha_acc) * alpha * gaussians[g].color;
alpha_acc += (1 - alpha_acc) * alpha;
if (alpha_acc > 0.99) break; // 早停
}
output_image[pixel_id] = color;
}
渲染加速技术:
结构:高斯八叉树
- 根节点:场景边界框
- 内部节点:子空间边界框 + 子节点指针
- 叶节点:高斯索引列表
剔除:递归遍历,跳过视锥外的子树
内存管理优化:
class GaussianPool {
std::vector<Gaussian> pool;
std::queue<int> free_indices;
int allocate() {
if (free_indices.empty()) {
pool.resize(pool.size() * 2);
// 添加新索引到free_indices
}
int idx = free_indices.front();
free_indices.pop();
return idx;
}
void deallocate(int idx) {
free_indices.push(idx);
}
};
将神经隐式表示(如NeuS、VolSDF)转换为显式网格是实际应用的关键步骤。这个过程涉及零等值面提取、网格质量优化和拓扑控制等技术。
Marching Cubes是从隐式函数提取等值面的经典算法,在神经SDF中需要特殊适配:
基础算法流程:
算法:神经场Marching Cubes
输入:神经网络f_θ, 边界框B, 分辨率N
输出:三角网格M = (V, F)
1. 创建规则体素网格:
将边界框B均匀划分为N³个体素
2. 评估SDF值:
对每个体素顶点v_i:
sdf_i = f_θ(v_i)
3. 处理每个体素:
根据8个顶点的符号确定配置(256种情况)
查找预计算的三角化表
4. 顶点插值:
对穿过零等值面的边:
t = sdf_1 / (sdf_1 - sdf_2)
v_interp = (1-t) * v_1 + t * v_2
5. 生成三角形:
根据查找表创建三角形
合并重复顶点
神经场特有的挑战:
其中 $f_{max}$ 是最高频率分量。过高的采样分辨率不会增加细节,反而引入噪声。
def batch_evaluate_sdf(network, points, batch_size=100000):
n_points = points.shape[0]
sdf_values = []
for i in range(0, n_points, batch_size):
batch = points[i:min(i+batch_size, n_points)]
with torch.no_grad():
sdf = network(batch)
sdf_values.append(sdf.cpu())
return torch.cat(sdf_values)
精确定位零等值面是高质量网格提取的关键:
改进的等值面定位:
def bisection_refinement(network, p1, p2, sdf1, sdf2, tol=1e-5):
# 初始线性插值
t = sdf1 / (sdf1 - sdf2)
for _ in range(10): # 最多10次迭代
p_mid = (1-t) * p1 + t * p2
sdf_mid = network(p_mid)
if abs(sdf_mid) < tol:
break
if sdf_mid * sdf1 > 0:
p1, sdf1 = p_mid, sdf_mid
else:
p2, sdf2 = p_mid, sdf_mid
t = sdf1 / (sdf1 - sdf2)
return (1-t) * p1 + t * p2
def newton_raphson_refinement(network, p_init, max_iter=5):
p = p_init
for _ in range(max_iter):
sdf, grad = network.forward_with_gradient(p)
if abs(sdf) < 1e-5:
break
# Newton步骤
step = sdf / (grad.norm() + 1e-10)
p = p - step * grad / grad.norm()
return p
法线计算: 从SDF梯度计算准确的法线: \(n(x) = \frac{\nabla f_\theta(x)}{\|\nabla f_\theta(x)\|}\)
实践中常用有限差分近似: \(\nabla f \approx \frac{1}{2h} [f(x+h) - f(x-h), f(y+h) - f(y-h), f(z+h) - f(z-h)]\)
提取的原始网格通常需要后处理以提高质量:
网格清理:
def remove_small_components(mesh, min_faces=100):
components = mesh.get_connected_components()
valid_components = []
for comp in components:
if comp.num_faces() >= min_faces:
valid_components.append(comp)
return merge_meshes(valid_components)
def fill_holes(mesh, max_hole_size=10):
boundaries = mesh.get_boundaries()
for boundary in boundaries:
if len(boundary) <= max_hole_size:
# 使用耳切法或Delaunay三角化填充
new_faces = triangulate_polygon(boundary)
mesh.add_faces(new_faces)
网格简化:
其中 $Q$ 是误差二次型矩阵,累积了顶点周围平面的约束。
网格平滑:
其中 $w_{ij}$ 是权重(如余切权重)。
其中 $w_s$ 是空间权重,$w_n$ 是法线相似性权重。
通过拉格朗日乘子或投影方法实现。
确保提取的网格满足特定的拓扑和质量要求:
拓扑约束:
def compute_genus(mesh):
V = mesh.num_vertices()
E = mesh.num_edges()
F = mesh.num_faces()
# 欧拉特征数
chi = V - E + F
# 对于封闭曲面:genus = (2 - chi) / 2
genus = (2 - chi) // 2
return genus
# 修复:分裂非流形顶点 for edge in non_manifold_edges: split_non_manifold_vertex(edge) ```
质量度量:
理想等边三角形的质量为1。
长宽比检查: \(aspect\_ratio = \frac{max\_edge\_length}{2 \cdot inradius}\)
二面角分布: 统计相邻三角形的二面角,避免过于尖锐或平坦的折叠。
自动质量改进:
def edge_flip_optimization(mesh):
improved = True
while improved:
improved = False
for edge in mesh.edges():
if should_flip(edge): # 基于质量度量
mesh.flip_edge(edge)
improved = True
顶点重定位: 优化顶点位置以改善周围三角形质量: \(v_{opt} = \arg\min_v \sum_{f \in N(v)} quality\_penalty(f, v)\)
MonoSDF结合单目深度估计和神经SDF,实现从单张图像的高质量3D重建:
深度先验集成:
其中 $d_{mono}$ 是单目深度估计(如MiDaS、DPT)的输出。
其中 $s, t$ 通过最小二乘法求解: \(\min_{s,t} \sum_r (s \cdot d_{mono}(r) + t - d_{render}(r))^2\)
几何正则化增强:
法线一致性: 利用深度图计算的法线与SDF梯度对齐: \(\mathcal{L}_{normal} = \sum_r (1 - |n_{depth}(r) \cdot n_{sdf}(r)|)\)
深度平滑性: 鼓励相邻像素的深度连续: \(\mathcal{L}_{smooth} = \sum_{r,r'} \exp(-|\nabla I|) \cdot |\nabla d|\)
边界保持: 使用图像边缘信息保护几何边界。
神经点云结合了点云的灵活性和神经网络的表达能力:
神经点云架构:
点特征学习: 每个点携带可学习的特征向量: \(p_i = (x_i, f_i)\) 其中 $x_i \in \mathbb{R}^3$ 是位置,$f_i \in \mathbb{R}^d$ 是特征。
局部聚合网络: 使用PointNet++或DGCNN聚合邻域信息: \(f_i' = \phi(f_i, \text{Aggregate}_{j \in N(i)} \psi(f_j - f_i))\)
神经纹理映射: 将点云特征映射到连续场: \(F(x) = \sum_{i} w_i(x) \cdot f_i\)
权重函数基于距离和法线相似性: \(w_i(x) = \exp(-\|x - x_i\|^2/\sigma^2) \cdot \exp(-(1 - n_i \cdot n_x)^2/\tau^2)\)
优化策略:
现代可微分渲染器的设计原则和实现:
渲染管线设计:
使用软光栅化或边界采样技术。
高级特性:
材质微分: BRDF参数的梯度计算: \(\frac{\partial L_o}{\partial \rho} = \int_{\Omega} L_i(w_i) \frac{\partial f_r}{\partial \rho} (w_i \cdot n) dw_i\)
光源优化: 同时优化光源参数和几何: \(\mathcal{L} = \mathcal{L}_{image} + \lambda_g \mathcal{L}_{geometry} + \lambda_l \mathcal{L}_{lighting}\)
纹理合成: 使用神经纹理或传统UV映射。
结合多种表示方法的优势:
NeRF + SDF混合:
密度分支:σ = MLP_density(x, viewing_direction)
SDF分支:f = MLP_sdf(x)
融合:σ_final = combine(σ, f)
显式-隐式混合:
几何 = 粗网格 + 神经位移场
外观 = 基础纹理 + 神经增强
动态选择策略: 根据视角、距离和性能要求动态选择表示:
def select_representation(camera_distance, performance_mode):
if performance_mode == "realtime":
if camera_distance > far_threshold:
return "billboard"
elif camera_distance > mid_threshold:
return "mesh_lod"
else:
return "gaussian_splatting"
else: # quality mode
return "neural_sdf"
本章深入探讨了神经隐式曲面和3D Gaussian Splatting两大前沿技术:
核心概念回顾:
关键公式汇总:
实践要点:
NeuS权重函数理解 解释为什么NeuS的权重函数在零等值面处达到最大值?这对表面重建有什么意义?
3DGS协方差参数化 为什么3D Gaussian Splatting使用旋转-缩放分解而不是直接优化协方差矩阵?
Marching Cubes分辨率选择 给定一个使用10阶位置编码的神经SDF网络,合理的Marching Cubes分辨率应该是多少?为什么?
Eikonal正则化的作用 解释Eikonal正则化 $\mathcal{L}_{eikonal} = \mathbb{E}[(|\nabla f| - 1)^2]$ 的几何意义。
多分辨率神经SDF设计 设计一个多分辨率神经SDF架构,能够同时表示大尺度结构和精细细节。描述网络结构、训练策略和内存优化方案。
3DGS实时编辑系统 设计一个支持实时编辑的3D Gaussian Splatting系统,包括选择、移动、删除和添加高斯原语。讨论交互设计和性能优化。
神经SDF到CAD模型转换 提出一个将神经SDF转换为CAD友好表示(如NURBS或CSG)的算法。考虑精度、拓扑保持和特征识别。
跨模态3D生成(开放性问题) 设计一个系统,能够从文本描述生成3D Gaussian Splatting表示,然后转换为神经SDF进行编辑,最后导出为网格。讨论各阶段的技术选择和挑战。