Shap-E 是 OpenAI 开源的文本/图像转 3D 模型生成工具,它可以直接输出隐式函数表示的三维物体,再通过采样得到点云或网格。很多人跑通模型之后发现,真正让人纠结的不是生成环节,而是导出环节:Shap-E 的输出可以被转换成 PLY、OBJ、STL、GLTF 等多种格式,每种格式看起来都能用,但真正放进工作流里又各有各的问题。选错格式的代价不小,轻则丢颜色、丢材质,重则网格破损、文件大到没法在网页上加载。这篇文章就来把四种主流格式掰开揉碎讲清楚,帮你根据后续用途做出正确选择。

四种格式的数据结构差异:从底层设计看各自定位
要理解各格式的优缺点,先得看它们底层存的是什么。STL 是最古老也是最简陋的一种,它只存储一系列三角面片,每个面片由三个顶点坐标和一个法向量组成,没有任何颜色、材质、纹理信息,甚至连顶点索引共享都没有,同一个顶点会被多个三角形重复存储,这也是 STL 文件经常比其他格式大好几倍的原因。
OBJ 是 Wavefront 公司在上世纪为动画软件设计的格式,采用纯文本结构(也有二进制变体),支持顶点、法线、纹理坐标分离存储,通过 .mtl 材质库文件间接引用材质和贴图。这意味着一个完整的 OBJ 模型实际上是两个甚至多个文件,复制或传输时漏掉 .mtl 或贴图就会变成一片惨白。
PLY 由斯坦福大学设计,最初就是为了存储三维扫描数据。它最大的特色是对点云的原生支持以及丰富的属性扩展能力——顶点不仅有坐标,还可以带法线、颜色(RGB)、置信度等自定义属性。这一点对 Shap-E 特别友好,因为 Shap-E 本身就能直接输出带颜色的点云数据。
GLTF 是 Khronos 组织制定的标准,定位是「3D 领域的 JPEG」。它基于 JSON 描述场景结构,配合二进制缓冲区存储几何数据,支持 PBR 材质、骨骼动画、蒙皮、多层级场景,并且有 GLB 这种把所有资源打包成单一文件的形式,是目前 Web 端实时渲染的事实标准。
从 Shap-E 输出特点出发的实操对比
Shap-E 官方仓库提供了从隐式场提取网格的代码,默认走的是 marching cubes(移动立方体)算法。下面这段代码演示了如何把 Shap-E 的输出同时导出为 PLY 点云和 OBJ 网格:
import torch
from shap_e.diffusion.sample import sample_latents
from shap_e.diffusion.gaussian_diffusion import diffusion_from_config
from shap_e.models.download import load_model, load_config
from shap_e.util.notebooks import create_panorama_data, decode_latent_images
from shap_e.util.io import write_ply, write_gif
# 加载文本转3D模型
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
xm = load_model('transmitter', device=device)
model = load_model('text300M', device=device)
diffusion = diffusion_from_config(load_config('diffusion'))
latents = sample_latents(
batch_size=1,
model=model,
diffusion=diffusion,
guidance_scale=15.0,
model_kwargs=dict(texts=['a chair that looks like an avocado']),
device=device,
progress=True,
)
# 提取点云并写入 PLY 文件(带 RGB 颜色)
latent = latents[0]
t = xm.renderer.query_by_latent(latent)
points = t.points.cpu().numpy()
colors = t.channel.cpu().numpy() # 颜色通道
write_ply('avocado_chair.ply', points=points, colors=colors)
从这段代码能看出一个关键点:Shap-E 的 transmitter 输出的点云天然带有 RGB 颜色,write_ply 可以直接把这些颜色写进 PLY 文件。用 MeshLab 或 CloudCompare 打开,颜色信息一目了然。反观 STL,这些颜色在导出的瞬间就全部丢失了,因为格式本身根本没有存放颜色的字段。
如果要把隐式场转成网格,通常会借助 marching cubes 提取后再转 OBJ 或 GLTF,例如用 trimesh 库做中间桥梁:
import numpy as np
from skimage import measure
import trimesh
# 假设已经得到体素化的隐式场 volume
# 用移动立方体算法提取等值面网格
verts, faces, normals, values = measure.marching_cubes(volume, level=0.0)
mesh = trimesh.Trimesh(vertices=verts, faces=faces, vertex_normals=normals)
# 导出 OBJ
mesh.export('model.obj')
# 导出 GLB(GLTF 的二进制单文件形式)
mesh.export('model.glb')
# 导出 STL
mesh.export('model.stl')
同一个网格分别导出三种格式后,文件体积差异非常直观。以一个 128 分辨率的体素网格提取出的模型为例,STL 往往是最大的,因为它不共享顶点;OBJ 次之,纯文本还会进一步膨胀体积;GLB 由于采用二进制存储加 Draco 压缩(可选),体积通常最小。在一次实测中,同一个 avocado chair 模型导出后 STL 约 18MB,OBJ 约 11MB(不含贴图),GLB 仅 3.4MB,差距接近五倍。
按使用场景做选择:不同下游工作流的最佳格式
格式没有绝对的好坏,只有合不合适。下面按几个典型场景分别分析。
场景一:3D 打印。首选 STL,这不是因为 STL 优秀,而是因为几乎所有切片软件(Cura、PrusaSlicer、CHITUBOX)都默认支持它。3D 打印只需要封闭的几何面片,不需要颜色和材质,STL 的简陋反而成了优势。需要注意的是,Shap-E 生成的网格经过 marching cubes 提取后可能存在非流形边或者未闭合的孔洞,建议在 Blender 里用 3D 打印工具插件检查一遍,修复后再导出 STL。如果打印软件支持,也可以直接用 3MF,它是 STL 的现代升级版,还带压缩。
场景二:导入 Blender、Maya 等软件做二次编辑。推荐 OBJ 或 GLTF。OBJ 的好处是几乎所有 DCC 软件都认,导入导出零障碍,但材质走 .mtl 的老机制,PBR 效果基本还原不了。GLTF 的 PBR 材质基于 Metallic-Roughness 工作流,和 Blender 的 Principled BSDF 几乎一一对应,导进去的材质还原度明显更好。如果你在意 UV 和材质的完整性,GLTF 是更好的选择。
场景三:Web 展示(Three.js、Babylon.js)。毫无悬念选 GLTF/GLB。Three.js 官方文档明确表示 GLTF 是推荐格式,加载器经过高度优化,支持 Draco 压缩、KTX2 纹理压缩、网格量化等扩展,加载速度和内存占用都远优于 OBJ。把 Shap-E 生成的模型放进网页 demo,GLB 单文件的特性也省去了跨域加载多个资源的麻烦:
<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('model.glb', function (gltf) {
scene.add(gltf.scene);
renderer.render(scene, camera);
});
</script>
场景四:点云处理、算法研究或机器学习数据集构建。PLY 是首选。它的二进制版本读写速度快,顶点属性可自由扩展,学术界做点云配准、三维重建的论文代码几乎清一色用 PLY。Shap-E 输出的带色点云直接存成 PLY,后续接 Open3D、PCL 都很顺畅。
一张表格总结四者取舍
| 格式 | 颜色/材质 | 文件体积 | 典型用途 | 主要短板 |
|---|---|---|---|---|
| STL | 不支持 | 偏大 | 3D 打印 | 无颜色,顶点重复存储 |
| OBJ | 材质需 .mtl 配合 | 中等偏大 | DCC 软件互导 | 多文件依赖,PBR 支持弱 |
| PLY | 支持顶点颜色 | 小(二进制) | 点云、科研 | 网格场景普及度不如 OBJ |
| GLTF/GLB | 完整 PBR、纹理、动画 | 最小(可压缩) | Web 实时渲染、AR/VR | 老旧软件支持不全 |
总结一条实用原则:要打印就转 STL,要放网页就转 GLB,要做点云研究就用 PLY,要在各大建模软件之间搬运就用 OBJ。Shap-E 的输出链路足够灵活,完全可以一次性导出多种格式按需分发。另外提醒一点,格式转换本身是有损操作,比如从网格降采样回点云会丢面片信息,尽量从 Shap-E 的原始 latent 或 transmitter 输出分别生成,而不是在不同格式之间来回倒腾,这样才能保住最多的原始细节。