文本生成3D一直存在单阶段扩散模型生成质量不稳定的问题,主要矛盾是几何与外观互相干扰,采样步数少则形状残缺,步数多则纹理容易过拟合到训练视角。3DTopia选择不在一张隐空间图里同时学习所有内容,而是把模型分成两个阶段串联执行:第一阶段负责从文本恢复低分辨率几何,第二阶段负责纹理精修。这种流水线设计使每个模块的监督信号更干净,也让生成过程更可控。

一、两阶段生成管线的整体架构与设计动机
单阶段文本生成3D模型通常会采用条件扩散模型直接生成体素、点云或三平面表示,再通过解码器还原网格。这种方式的问题在于,文本语义既需要约束物体的整体轮廓,又需要指导表面纹理颜色和材质,这两类信息的空间尺度差异很大。同一个文本嵌入同时参与粗粒度几何生成和细粒度外观生成时,模型容易产生注意力分散,导致生成结果出现形状塌陷、纹理贴图错位或者细节缺失。
3DTopia把这一过程拆解为几何阶段和纹理阶段后,两个网络可以独立设置分辨率、采样步数和损失权重。几何阶段不需要处理高频外观,因此可以在较低分辨率下完成大部分形状探索;纹理阶段则固定网格结构,只优化表面属性和局部几何微调。这种拆分还带来了显存上的好处,因为纹理精修时不需要重新执行完整的形状扩散采样,只需要对已有网格做多视角渲染和图像级扩散。
从数据流角度看,用户输入一句话,例如生成一把木质扶手椅,文本先被编码成连续向量,然后作为条件进入第一阶段的条件扩散网络。第一阶段输出三平面特征图,解码后得到三角网格。这个网格只包含基础几何,表面颜色可能是统一的占位色。第二阶段拿到网格后,会固定顶点拓扑,使用可微渲染器在多个角度生成低分辨率图像序列,再通过图像条件扩散模型生成细化后的纹理图。整个过程串行执行,但两个阶段共享同一套文本编码器参数和相机位姿定义。
二、第一阶段:文本条件潜空间扩散与三平面解码
第一阶段的输入是文本描述和随机噪声,输出是一个低分辨率三维形状。3DTopia并没有直接在高分辨率体素网格上做扩散,因为三维体素的内存占用随分辨率三次方增长,很难在常规显卡上完成训练。它采用三平面隐表示作为中间载体,将三维空间分解为三个互相正交的平面特征图,每个平面只保存两个空间轴和通道维度上的信息。这种表示比体素更紧凑,也比点云更容易卷积。
文本条件注入方式并不是简单地把文本特征拼接到噪声上,而是先通过一个Transformer编码器提取句子的全局语义,再经过交叉注意力模块与扩散网络中的中间特征交互。训练时,扩散模型对真实三平面表示逐步加噪,学习从噪声中恢复干净的三平面。推理时,模型从纯噪声出发,在文本条件引导下完成多步去噪采样。为了提升生成形状的多样性,3DTopia在推理阶段保持了无分类器引导机制,让生成结果在文本一致性和多样性之间取得平衡。
三平面解码为网格通常使用等值面提取算法,例如Marching Cubes。三平面特征经过一个小型卷积解码网络输出占用场或符号距离场,然后在一个固定分辨率下提取等值面。这里的网格不需要太高的顶点数量,因为第二阶段还会做细分和边缘优化。第一阶段的输出质量主要影响物体的整体轮廓,因此训练损失以几何一致性为主,文本监督只作为条件约束,不直接参与逐顶点回归。
import torch
import torch.nn as nn
class TextConditionedShapeGenerator(nn.Module):
def __init__(self, text_dim=768, latent_dim=256):
super().__init__()
self.text_proj = nn.Linear(text_dim, latent_dim)
self.triplane_conv = nn.Conv3d(latent_dim, 3 * 32, kernel_size=3, padding=1)
def forward(self, text_feats, noise_latent):
cond = self.text_proj(text_feats)
x = torch.cat([noise_latent, cond.unsqueeze(-1).unsqueeze(-1).unsqueeze(-1)], dim=1)
triplanes = self.triplane_conv(x)
return triplanes
上述代码展示了一个简化的条件注入结构,实际模型中交叉注意力模块会替换掉简单的线性投影,以便让文本特征在空间维度上与噪声特征做更充分的交互。第一阶段训练完成后,模型权重会被固定,第二阶段只读取网格结果,不会再改动三平面解码器的参数。
三、第二阶段:多视角可微渲染下的纹理细化
第二阶段要解决的核心问题是给第一阶段生成的基础网格赋予细节纹理,同时修补几何上比较生硬的区域。3DTopia并没有直接把纹理生成当作一个二维图像合成任务,而是引入多视角可微渲染,把三维表面属性和二维扩散模型连接起来。渲染器会在预设的相机角度下把网格投影成图像,如果网格存在法线突变或几何空洞,渲染结果会直接反映出这些问题。
纹理细化过程从多个视角渲染开始。每个视角下,渲染器输出颜色图、深度图和法线图,这些图像被送入一个图像条件扩散模型。模型根据文本编码和低分辨率渲染结果,逐步恢复出高分辨率细节。这里的关键在于,扩散模型不需要从零开始生成纹理,而是以粗糙渲染为条件,只预测细节增量。这样既能复用图像扩散模型在海量自然图像上学习到的真实感先验,又能把纹理约束在网格的UV空间内。
为了消除多视角渲染之间的接缝,3DTopia在纹理优化时使用了视角一致性损失。不同视角重建出的同一块纹理区域会被投影回UV空间并计算像素差异,网络会惩罚这种差异,避免出现颜色跳变。与此同时,渲染图与文本描述之间还会计算对比损失,确保生成纹理在语义上符合输入描述。几何微调部分则通过梯度反向传播到顶点坐标,但每一步只允许很小的位移,防止破坏第一阶段建立的拓扑结构。
def refine_texture_with_diffusion(mesh, text_prompt, diffusion_model, renderer):
views = sample_camera_views(num_views=12)
rendered_images = [renderer(mesh, v) for v in views]
texture_latents = diffusion_model.encode_text(text_prompt)
for step in range(diffusion_model.num_steps):
noise_pred = diffusion_model.denoise(rendered_images, texture_latents)
rendered_images = diffusion_model.scheduler.step(noise_pred, rendered_images)
texture_map = diffusion_model.decode_to_texture(rendered_images)
return texture_map
这个流程中,可微渲染器必须支持对纹理贴图的梯度回传。如果使用传统的栅格化渲染,梯度会在离散的深度测试和纹理采样处中断,因此3DTopia在训练阶段使用软化的光栅化或者基于神经辐射场的渲染近似,以保证梯度可以稳定传递到网格顶点和纹理参数。推理阶段可以直接使用标准渲染器导出最终纹理资产。
四、训练细节、损失函数与工程实践
3DTopia的两个阶段采用分离训练策略。第一阶段使用三维形状数据集训练,监督信号主要来自体素化后的占用场与生成占用场之间的二元交叉熵损失。为了提升形状质量,还可以加入倒角距离损失和边缘长度正则项,前者衡量生成网格与真实网格点云之间的表面距离,后者抑制过度细长的三角形。第一阶段训练时文本编码器与扩散网络联合优化,学习率通常分为两组,文本编码部分使用更小的学习率,避免破坏预训练语言表示的通用性。
第二阶段训练更偏视觉。采集多视角渲染图后,损失函数包括三部分:扩散模型的去噪损失、渲染图与参考图之间的感知损失,以及不同视角之间的纹理一致性损失。去噪损失保证纹理生成质量,感知损失让纹理在语义上和输入文本对齐,一致性损失用来消除UV接缝。工程实现上,第二阶段需要维护一个纹理缓存,不同视角的渲染结果会先回到一张共享的UV纹理图,再重新渲染到新视角,以降低显存占用。
两阶段设计还让故障排查变得简单。如果生成形状不符合描述,可以直接锁定第一阶段的条件注入或三平面解码;如果形状合理但纹理模糊,则只需要检查第二阶段的可微渲染配置和扩散模型权重。相比单阶段黑盒,这种可拆分的结构在业务落地时更容易调整。实际部署时,第一阶段可以使用低精度推理加速,第二阶段则按需选择不同纹理风格模型,例如写实、卡通或者手绘风格。
五、两阶段管线带来的优势与仍然存在的局限
两阶段最大的价值在于让几何和纹理各自拥有了更适合自己的表示空间。第一阶段在三平面隐空间工作,可以用较低分辨率处理大尺度形状;第二阶段在二维渲染图像空间工作,可以充分复用现有图像扩散模型的先验。两者通过可微渲染建立联系,而不是强行使用同一个三维特征表达,这降低了模型设计复杂度,也提高了生成结果的可控性。
不过这种拆分也带来一些固有问题。第一阶段生成的网格一旦固定,第二阶段就只能做有限程度的几何修改,如果第一阶段产生了严重畸形结构,第二阶段无法根本纠正。另外,多视角渲染与纹理一致性的联合优化需要较大的计算量,推理时间通常比纯粹的前馈模型更长。对于需要实时生成的场景,还需要配合模型蒸馏或者分辨率缩减策略。但总体来看,3DTopia的两阶段管线在文本生成3D任务中提供了一条更加稳定和可维护的路线,比单阶段方案更适合工程化应用。