文本驱动的3D局部编辑与替换要解决的问题是:给定一个已重建或已生成的3D对象,用户输入“把帽子换成红色贝雷帽”“把轮毂改成五辐式”这类自然语言,系统只修改目标部件,同时保持其余区域不变。这与从文本生成完整3D资产不同,核心难点在于局部性、多视图一致性和语义对齐。完整生成可以从零开始优化所有参数,而局部编辑必须区分哪些参数属于目标区域、哪些参数必须冻结,否则容易导致整个模型风格漂移。

从表示层面看,当前可编辑的3D场景通常使用神经辐射场NeRF或3D高斯泼溅3DGS表示。NeRF用多层感知机隐式编码密度和颜色,3DGS用一组带位置、协方差、颜色和不透明度的3D高斯球表示场景。两者都能把任意视角渲染结果与输入文本描述建立梯度连接。正是因为渲染过程可微,才有可能把2D扩散模型中的文本条件信号传回3D参数。理解了这一点,就能明白局部编辑并不是另起炉灶,而是在已有表示上做受控的参数更新。
为什么局部编辑比全局生成更难
文本生成完整3D对象时,优化器可以在每一步调整所有参数,使任意视角渲染结果逐步接近文本描述。这种做法通常使用Score Distillation Sampling损失,也叫做SDS损失。它把渲染图像加噪后送入扩散模型,用预测噪声与真实噪声之差作为梯度信号。由于没有区域限制,SDS会推动整个对象的几何和颜色同时变化。
局部编辑则不同。如果直接把SDS施加到整个3D表示上,目标部件确实会发生变化,但背景、邻近区域甚至光照也可能跟着漂移。比如要求“把玻璃换成磨砂材质”时,车窗周围的金属边框可能被误改。另一个问题是视角一致性:某个视角下替换成功了,转到背面却发现部件边界模糊、结构错乱。因此局部编辑需要额外引入掩码和参数约束,把文本梯度限制在真正需要修改的局部区域。
此外,替换式编辑比风格编辑更复杂。风格编辑只改变颜色或纹理,几何结构基本不变;替换式编辑则涉及形状、拓扑甚至部件增删。文本“换一个圆形尾灯”与“尾灯改成熏黑风格”对3D参数的要求完全不同。前一种需要调整高斯球的位置和形状,后一种更多是调整颜色和反射属性。区分这两类任务,才能选择合适的优化策略。
文本梯度如何注入3D表示
SDS损失的核心思想是:从当前3D表示渲染出一张图,将其映射到扩散模型的潜在空间,然后按照文本条件预测噪声。梯度方向定义为预测噪声减去实际噪声,再乘以一个与时间步相关的权重。这个梯度可以反向传播到渲染器中所有可训练参数。对NeRF而言,参数是多层感知机的权重;对3DGS而言,参数是每个高斯球的位置、协方差、颜色和不透明度。
下面是一段简化后的SDS损失计算代码,用于帮助理解文本梯度是如何得到的。实际实现中还需要考虑编码器、调度器以及无分类器引导等细节。
# 简化SDS损失计算
def sds_loss(renderer, text_embedding, diffusion_model, latents):
noise = torch.randn_like(latents)
timestep = torch.randint(0, scheduler.num_train_timesteps, (latents.shape[0],))
noisy_latents = scheduler.add_noise(latents, noise, timestep)
noise_pred = diffusion_model(noisy_latents, timestep, text_embedding)
weight = 1.0
grad = weight * (noise_pred - noise)
return torch.mean(grad * latents)
实际编辑时并不会对所有渲染像素均匀计算SDS。通常的做法是先获取目标区域的二维掩码,再在损失计算中把非目标像素置零。这样文本梯度只会影响目标区域对应的渲染像素,进而通过可微渲染反向传播到与该区域绑定的3D参数。对于3DGS表示,还可以进一步筛选出投影到掩码内的高斯球,只对这些高斯球更新位置和颜色。
另一种注入文本梯度的方式不直接优化3D参数,而是先修改多视角数据集,再用修改后的图像重新拟合3D表示。这类思路以Instruct-NeRF2NeRF为代表。它先对若干关键视角的图像做2D编辑,再把这些编辑后的图像作为监督信号回灌到3D重建过程。这样做的好处是2D编辑模型已经很成熟,缺点是编辑结果可能在不同视角间不一致,因此需要多次迭代。
局部掩码与替换式编辑实现
生成局部掩码是文本驱动3D编辑落地的关键一步。常用的做法是使用开放词汇分割模型或结合检测模型,根据文本提示自动定位目标区域。例如输入“把轮毂换成黑色多辐式”,先在渲染图像上检测并分割出轮毂区域,再将该二维掩码反投影到3D表示。对于3DGS,可以通过光栅化过程判断每个高斯球是否落在掩码内;对于NeRF,则可以在采样点层面做空间约束。
下面是一段伪代码,展示如何只在目标区域对应的参数上施加梯度。这里假设已经获得了二维掩码,并且渲染器的参数名包含颜色或位置标识。
def masked_update(renderer, mask, grad, optimizer):
for name, param in renderer.named_parameters():
if param.grad is not None:
if 'rgb' in name or 'position' in name:
param.grad = param.grad * mask
optimizer.step()
替换式编辑还需要处理几何变化。例如把“圆形尾灯”替换为“贯穿式尾灯”,原有的高斯球数量可能不足,需要新增或分裂高斯球以表达新的形状。这通常比颜色替换更困难。一个可行的策略是分阶段优化:先在目标区域增加高斯球或提高采样密度,再进行SDS优化;优化过程中定期删除不透明度接近零的高斯球,以保持表示紧凑。另一个策略是显式引入形状先验,例如从文本生成目标部件的粗模型作为初始化。
工程实践中的一致性与质量提升
多视角一致性是局部编辑最容易翻车的地方。纯SDS优化在单视角下效果尚可,但转到其他视角往往出现边缘撕裂或语义漂移。改进办法是每轮迭代从不同视角采样,同时计算SDS损失,并对同一批3D参数进行梯度累积。这样不同视角的文本约束会相互制约,迫使编辑结果在多个视角下保持一致。
参数冻结策略也很重要。以3DGS为例,可以把场景分为可编辑高斯基元与冻结高斯基元。只有投影到掩码内的高斯球才参与位置和颜色更新,其他高斯球保持原值。更细致一点,可以对靠近掩码边缘的高斯球施加软权重,让过渡区域更平滑。数据更新策略同样有效:每隔若干步,用当前3D表示渲染若干视角,再用2D编辑模型生成对应目标图,将这些目标图加入监督数据集重新训练。这种迭代方式能显著减少漂移。
损失权重的选择需要根据任务类型调整。风格替换可以适当降低SDS中与时间步相关的权重,避免几何被过度修改;几何替换则需要提高位置参数的学习率,同时加入正则项防止目标区域出现尖锐毛刺。实践中还可以加入渲染图像与原始图像在非目标区域的L1损失,强制背景完全不变。这些工程技巧叠加起来,才能让文本驱动的3D部分编辑从演示效果走向可用工具。