Shap-E是OpenAI开源的文生3D模型,输入一句提示词就能输出隐式场表示的三维资产。做建筑设计的人第一次用它生成建筑时,通常会很兴奋,但很快发现问题:生成的所谓建筑往往只是一坨看起来像房子的体块,没有明确的层高概念,悬挑大得离谱,柱子和楼板的关系全靠缘分。这并不是Shap-E能力不行,而是它的训练目标里根本没有建筑结构逻辑这个概念。这篇文章就来聊聊,怎么通过规则约束和后处理手段,让Shap-E生成的建筑模型至少在结构层面说得过去。

Shap-E的生成原理与建筑语义缺失的原因
Shap-E与早期的Point-E不同,它直接输出两个神经场:一个是带符号距离函数SDF场,用来表示三维几何,另一个是纹理场,用来给表面上色。生成时模型先通过一个扩散过程在隐式编码空间中采样,再用一个独立的解码器把编码还原成SDF和纹理。这种端到端的方式让生成速度很快,在消费级显卡上几十秒就能出结果。
问题恰恰出在这个隐式表示上。SDF场本质上是一个连续函数,输入空间坐标,输出该点到最近表面的距离。它对几何的描述是纯数学的,不含任何语义信息。对模型来说,一根承重柱和一根装饰柱在SDF上没有任何区别,一块悬挑八米的楼板和一块正常楼板也只是一段距离函数的不同采样结果。训练数据里虽然可能包含大量建筑类3D资产,但扩散模型学到的是表面形态的统计规律,而不是梁柱板的力学关系。
所以当你输入提示词让Shap-E生成一栋框架结构办公楼时,它能给你一个大概有楼层感、有立面开窗感的体块,但无法保证窗洞避开结构柱,无法保证悬挑尺寸合理,更无法保证上下层的柱网对齐。这些约束必须由你在生成之后用规则去补充。
提示词工程:在生成阶段引入结构逻辑
虽然Shap-E不懂力学,但它对几何形态的统计规律掌握得不错,所以第一步是在提示词里把结构意图写明确。经验上有几个要点:第一,明确结构体系和体量特征,比如multiple floors、regular column grid、flat slab这些词能有效提升生成结果的整体规整度;第二,明确悬挑和开洞的克制描述,比如no large cantilever、symmetric facade,避免模型天马行空地生成扭曲形体;第三,用材质和风格词收窄分布,concrete frame office building比单独的modern building更容易得到结构感强的结果。
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
device = "cuda"
model = load_model("transmitter", device=device)
diffusion = diffusion_from_config(load_config("diffusion"))
# 用带有结构语义的提示词约束生成
prompt = ("a modern concrete office building, six floors, "
"regular column grid, symmetric facade, "
"flat roof, no large cantilever, minimal style")
latents = sample_latents(
batch_size=4,
model=model,
diffusion=diffusion,
guidance_scale=15.0, # 提高引导强度,强化提示词约束
prompt=prompt,
)
值得注意的是guidance_scale参数。对建筑类提示词来说,这个值适当调高(15到20之间)会让生成结果更贴合文字描述,形体更规整;调低则容易得到富有变化但结构混乱的结果。概念设计前期可以低引导多采样找灵感,到了要往结构合理性靠拢的阶段,就应该提高引导并配合多批次采样做筛选。
后处理:把隐式场变成可校验的多边形网格
隐式场没法直接做结构校验,第一步是用Marching Cubes把它转成网格。Shap-E提供了配套的解码接口,同时你也可以借助trimesh或pyvista来做后续几何分析。
import numpy as np
import trimesh
from shap_e.diffusion.gaussian_diffusion import karras_sample
# 从latent解码为SDF网格,示例中使用内置接口
g = model.decoder.to_mesh(latents[0].detach().cpu().numpy())
mesh = trimesh.Trimesh(vertices=g.vertices, faces=g.faces)
# 统一单位,假设模型包围盒对应实际40米进深
scale = 40.0 / (mesh.bounds[1][0] - mesh.bounds[0][0])
mesh.apply_scale(scale)
# 基础指标:体积、表面积、包围盒尺寸
print("包围盒尺寸(米):", mesh.extents)
print("体积(立方米):", mesh.volume)
转成网格之后,常用的结构相关检查包括:横截面分析用来验证各楼层的柱网连续性、包围盒长宽高比例用来检查体形是否失衡、悬挑检测通过对比相邻层截面面积判断悬挑幅度。其中最实用的是分层切片:沿竖直方向每隔一定高度切一个截面,统计每个截面的连通域数量和面积,就能定量判断这栋生成的建筑有没有出现楼层断裂、局部悬空这类明显违背结构逻辑的问题。
规则约束校验:用程序化规则把关结构合理性
提示词只是软约束,真正的把关要靠硬规则。思路是把建筑结构的基本常识写成可计算的校验项,逐项检查生成的网格,不通过就丢弃或修正。下面是一套可行的最小校验规则:
import numpy as np
def check_structure(mesh, floor_height=3.6, max_cantilever_ratio=0.35):
z_min, z_max = mesh.bounds[:, 2]
n_floors = int((z_max - z_min) / floor_height)
problems = []
# 规则1:逐层切片,检查连通性
for i in range(1, n_floors):
z = z_min + i * floor_height
section = mesh.section(plane_origin=[0, 0, z],
plane_normal=[0, 0, 1])
if section is None or len(section.entities) == 0:
problems.append(f"高度{z:.1f}米处截面为空,楼层断裂")
continue
# 连通域过多说明出现大量零碎悬空构件
if len(section.entities) > 8:
problems.append(f"高度{z:.1f}米处截面碎片过多")
# 规则2:相邻层截面面积突变检测悬挑
areas = []
for i in range(1, n_floors):
z = z_min + i * floor_height
section = mesh.section(plane_origin=[0, 0, z],
plane_normal=[0, 0, 1])
areas.append(section.area if section else 0.0)
for i in range(1, len(areas)):
if areas[i] > 0 and areas[i - 1] > 0:
ratio = (areas[i] - areas[i - 1]) / areas[i - 1]
if ratio > max_cantilever_ratio:
problems.append(
f"第{i}层截面增幅{ratio:.0%},悬挑疑似超限")
return problems
issues = check_structure(mesh)
print("结构问题:" if issues else "结构校验通过", issues or "")
这套规则可以按项目需求继续扩展。比如加上高宽比限值,一般框架结构高层的高宽比不宜超过5到6;加上开洞率检查,用截面轮廓上的缺口面积占比来估计立面开洞是否过大;再加上底部落地面积检查,防止生成结果头重脚轻。对于不满足规则的结果,有两种处理策略:简单粗暴的做法是丢弃后重新采样,配合批量生成加自动筛选的流水线效率并不低;更精细的做法是定位问题区域后做局部布尔运算修补,比如把悬挑超限的部分裁掉再重新封口,不过这会引入额外的几何处理工作量。
从工具到流程:把Shap-E嵌入概念设计管线
单次生成单次检查的用法价值有限,Shap-E真正的效率优势要靠批量采样加自动筛选来体现。推荐的工作流是:先用低引导强度批量采样二十到五十个方案,快速筛掉几何破碎的结果;再对入围方案做上述结构规则校验,保留三到五个体形合理的候选;最后把候选网格导出为OBJ或GLB,导入Rhino、Blender或结构分析软件做深化。
需要清醒认识的是,Shap-E产出的始终是概念体量,不是可以直接出施工图的东西。它的定位是替代前期手工捏体块的过程,让设计师在几十秒内看到大量体量可能性。结构逻辑这一层,靠提示词给出方向,靠规则校验守住底线,靠后续专业软件完成真正的设计。三者各司其职,这条管线才跑得顺。
另外提一个实践细节:Shap-E生成的网格密度不均匀,在做切片分析前建议先做一次网格重划分和法向统一,否则截面计算的连通域判断容易被细碎三角形干扰,出现大量误报。trimesh的process参数和mesh.fix_normals()可以顺手解决大部分这类问题。把这些细节处理好,Shap-E完全可以成为建筑概念设计阶段一个靠谱的形体探索工具。