用 Codex 连接 Blender,我做了一块可以走进楼宇的大屏

0 阅读25分钟

我用 Codex 串起了 Vue 3、Three.js 和 Blender MCP,做了一套以武汉光谷为产业背景的三维楼宇大屏。打开页面,先看到城市和湖泊;点击示范园区,镜头向园区推进;再进入 A1 科创大厦,视角落到玻璃塔楼和退台裙房。左侧的信息也随观察尺度变化,从园区概况切换到楼宇档案和空间利用。

这篇文章想展开讲讲它是怎么做出来的:为什么要分三层,怎样确定设计方向,Codex 如何连接 Blender,第一轮画面偏平时如何处理,以及烘焙、材质、景观和前端交互怎样一步步接到一起。

在线体验 · 项目源码

项目为演示作品。园区、楼宇位置和经营指标均为演示设定;区域轮廓、道路、湖泊与点位为概念空间,不代表真实测绘或运营数据。文中配图分别标注为 AI 设计终稿和浏览器实际页面。

一、背景:从“看数据”,走到“看懂空间”

做楼宇展示时,几组数字很容易列出来:楼有多少栋、建筑面积有多少、出租率是多少、入驻了多少企业。但如果继续问“这些楼分别在哪里”“重点楼宇周边有什么”“园区里的公共空间怎么组织”,就需要一张能够建立空间关系的画面。

我给项目设定的使用场景是招商展示与汇报。最初先确定了“园区总览 → 重点楼宇”两个层级,让用户从楼宇分布进入具体建筑。后续再向外补上城市区域,把园区放进更大的产业空间,逐渐形成现在的三层浏览路径:

城市区域 → 园区总览 → 重点楼宇。

城市区域负责交代尺度。湖泊、道路和连续街区构成背景,示范园区是其中一个明确的入口。进入园区后,八栋楼和中央公共空间成为主角;继续进入 A1,建筑立面、裙房和经营信息占据主要视野。

我希望用户在切换过程中一直知道自己正在看哪里。因此三层之间需要保持清楚的对象关系:园区中的 A1 和近景里的 A1 必须是同一栋建筑,点击 C1 后浮卡和左侧摘要必须一起更新,城市页面里的园区经营指标也要与园区页面一致。

这些要求让技术问题很快具体起来:模型怎样命名?数据从哪里来?三层要加载几份模型?切换时相机怎么动?卡片怎样跟随建筑,又不挡住导航?每个问题都直接影响体验,不能等画面做完后再补。

二、设计:先生成两套概念,再收敛成统一的视觉方向

1. 最早的选择:暗色夜景,还是浅色日景?

正式建模之前,我先在 Codex 的工作流程里整理业务内容和视觉要求,再用图像生成工具分别探索两种概念方向。最初只针对园区总览和重点楼宇两个层级,每种方向各生成两张,共四张概念图。

A 方案是深色建筑沙盘,采用夜景表达。 深蓝底色压住背景,中央园区靠暖色窗光、景观灯和青蓝轮廓凸显出来。关键指标放在顶部,业务信息分布两侧,建筑和中央景观成为画面中心。

早期 A 方案园区概念:暗色夜景与双侧信息栏

图 1|早期 A 方案:深色夜景园区概念,用于比较构图、灯光和信息密度。

B 方案是浅色建筑展陈,采用日景表达。 左侧集中放信息,右侧留出更完整的建筑与景观视野;淡蓝玻璃、浅色建筑、自然树木和柔和阴影构成主体。它的阅读方向更接近看一张带解说的建筑展示图。

早期 B 方案园区概念:浅色日景与左侧集中信息栏

图 2|早期 B 方案:浅色日景园区概念。此时的光线、文案和楼宇标注还会继续修订。

把两张图放在一起,很容易看到选择风格时究竟在选什么:A 用灯光把园区从夜景中提出来,B 用日光和留白展示建筑;A 把信息铺在顶部与两侧,B 把阅读集中到左栏。这会影响场景能占多大、用户先看哪里,也会影响后续的材质与灯光制作。

这里的暗色和浅色是前期设计候选方向。最终沿浅色 B 方案继续深化,网页中的视觉也由这个方向逐渐收敛。

2. 选中方向后,还要把概念图里的问题改掉

第一轮图很容易让人先被气氛吸引。认真逐项看时,才会发现 AI 生图没有自动守住所有对象与数据约束。

例如,总览指标写着八栋楼,但场景中当时只有七个楼栋身份能被清楚核对;近景里出现过“建筑高度:24 层”这样的字段与单位错配;部分产业比例和楼宇属性由图像生成过程补出,也需要回到规划中核对。总览与近景虽然都叫 A1,塔楼宽高、裙房退台和周边关系也还需要收敛。

于是 B 方案继续修订:在规划中固定八个楼宇 ID 与相对排布,调整取景,让八栋楼都能核对;把“楼层数”和面积、出租率的口径分清楚;模块展示的是软件研发等类别,就使用“入驻产业”这个标题;对当时未定义的比例不直接照抄进数据。

光线也改过一轮。浅色初稿的金黄阳光与高光偏强,后续向中性、柔和日光收敛,同时保留古铜色翼片和局部暖反射。近景里一处与数值不符的比例条,也通过局部修订改成出租率文字行,让图形表达和数据保持一致。

这一阶段让我把“选风格”和“修内容”分开处理。浅色方向确定后,继续沿这个方向修改具体问题,比每次不满意就重新生成一套完全不同的画面更容易积累结果。

3. 从两层概念,补成三层完整设计

园区与楼宇的 B 方案修订并确认方向后,继续推进完整整屏设计;后续再补城市层,把“区域 → 园区 → 楼宇”的入口、导航和阅读路径连起来。经过后续调整,形成当前城市、园区、楼宇三张设计终稿。

三张终稿固定了当前的空间构图、信息内容和共同视觉语言,后续建模与前端都围绕它们推进。前面的 A/B 图片保留为设计探索的过程记录。

城市层的重点是“园区在哪里”。大面积水域、道路和建筑群建立城市尺度,青蓝色边界圈出概念区域,金色强调示范园区。产业楼宇、配套服务和园区入口分成不同点位,让用户能读出空间层次。

园区层的重点是“这里有什么”。A1 作为主塔楼,和 B1、B2 形成高层组团,其余五栋低层楼围绕公共空间分布。喷泉、草坪、步道、廊架和树木填充楼与楼之间的空间。建筑不再只是一个个孤立体块,而有了入口、路径与活动场所。

楼宇层的重点是“这栋楼有什么特点”。镜头靠近 A1,修长塔楼、古铜色竖向翼片、三级退台裙房与屋顶绿化成为识别特征。左侧信息也进入楼宇尺度:楼层数、建筑面积、出租率、企业数,以及已租、可租和空置面积。

4. 给信息和三维场景安排各自的位置

三层都采用暖白色信息面板、青绿色强调色、深色文字和柔和日光。右上角固定三层导航,左侧承载需要阅读的数据,右侧留给空间和操作。

我比较在意的是信息密度。大屏里很容易多放几个模块,结果场景被挤小,数字也没有重点。这个项目把园区概况收敛为四项核心指标,再用六项横向柱状图表达产业构成。六条柱子共用 0–40% 标尺,读者能直接比较长度,不需要逐个读数。

图标也统一为实心体系,让楼宇、面积、出租率和企业数形成稳定的视觉对应。切换到楼宇层后,这组表达继续沿用,用户能把注意力放到对象变化上。

画布以 1920 × 1080 为设计基准。前端根据窗口尺寸等比缩放 UI,额外的宽屏空间交给三维场景,避免只把一张固定尺寸的大屏居中后,在两侧留下没有用途的空白。

5. 先定义数字,避免设计和模型各说各话

规划中,园区有八栋楼、24 万平方米建筑面积和 216 家企业。A1 为 24 层、4.8 万平方米建筑面积、42 家企业。其中 24 层明确拆为三级裙房与 21 层塔楼。

这些数字有相互关系:园区面积来自各栋楼的汇总,出租率由已租面积除以可租面积得到,产业占比由各类企业数除以企业总数得到。设计阶段就把口径写清楚,后面修改建筑外形时,经营指标不会跟着被随意改动。

同时保留无数据模式:使用同一层布局,把经营数值替换为空值、占位符和说明。这既是页面状态的一部分,也能检查组件里有没有偷偷写死的演示数字。

三、过程:模型、光照和交互是怎样一轮轮接起来的

第一步:用一份规划源,把制作范围固定下来

项目的中心文件是 planning/project.json。楼宇 ID、尺寸、位置、演示指标、相机和运行参数都从这里出发。前端使用的 runtime.json 由脚本派生,模型制作也沿用同一套身份与尺寸约束。

planning/project.json
    ├── 楼宇身份、尺寸与场景参数 → Blender 工程 → GLB
    └── 演示指标、镜头与界面参数 → runtime.json → Vue + Three.js

为什么要先做这件事?因为当楼宇数量、层数和经营数据散落在模型脚本、前端组件与配置文件中,改一次 A1 就要到处找。更麻烦的是,各处看起来都能运行,但已经不是同一个版本。

因此,生成运行配置时会校验逐栋汇总与园区总量是否一致,产业分类的企业数是否合计为 216。前端只做必要派生,例如出租率和空置面积,不额外维护第二份统计值。

这也让后面的任务有了边界:调整 A1 的幕墙,可以改材质和窗后结构;但楼宇身份、24 层定义和经营口径需要保持一致。Codex 每轮修改都有一份可以回查的依据。

第二步:先搭空间骨架,再在 Codex 中接通 Blender MCP

基础场景先建立楼宇体量、道路、地面和相机。此时最重要的是八栋楼能否被辨认,楼间关系是否成立,园区总览和 A1 近景能否由同一个模型解释。

建模时,我先对照下面这张园区设计图,确定主塔楼、低层建筑和中央公共空间的关系。有了这张完整目标图,后续每轮都能检查具体对象的位置与比例。

园区设计终稿:八栋楼宇和中央公共空间

图 3|园区 AI 设计终稿,用于校准楼宇布局与场景构图。

初期画面的粗糙感也很明显:白色体块占比高,地面像铺开的一张平面,窗格重复,楼与环境之间缺少层次。但这时就堆树、加泛光,很容易把真正的构图问题藏起来。所以先对照设计图检查楼宇位置、塔楼投影高度、道路与湖岸,再继续深化表面。

随后通过 Blender MCP 接入本机 Blender。项目里的实际链路是:

Codex
  ↓ 调用项目中的 MCP 客户端
Blender MCP 服务
  ↓ 连接本机 Blender 插件
执行场景检查、建模、UV、烘焙、保存与导出
  ↓
Three.js 加载资产,浏览器查看结果

Codex 在这个流程里既要读代码和规划,也要通过 MCP 查看、修改 Blender 场景。需要批量处理对象时,Python 代码片段由 MCP 工具交给 Blender 执行;项目客户端保留调用参数、返回结果和代码哈希,方便核对实际执行了什么。

我把制作任务拆成小段推进:先检查当前对象和材质,再做一类修改,然后保存工程、导出资产、打开页面。这样一次修改失败时,可以回到具体步骤排查,不必重新猜整个场景出了什么问题。

两种空间尺度也从这里分开:城市使用一份 GLB,园区使用另一份 GLB;园区总览与 A1 近景共用园区模型,通过相机和细节配置切换观察方式。模型对象的业务身份一直保留到网页中。

第三步:画面偏平,先确认到底缺了什么

“再真实一点”很难直接变成一次有效修改。我逐渐把这句话拆成能检查的问题:建筑有没有正确接触地面?檐下和框架接缝有没有暗部?幕墙是有深度的窗,还是整块重复纹理?背景有没有延续到画面边缘?植物是不是只换了颜色,却没有改变轮廓和分布?

有一次排查偏灰问题时,实际检查了阴影深度:被建筑遮挡和未被遮挡的地面,深度关系是正确的。也就是说,太阳阴影确实存在,不能把整个画面的平淡都归为“阴影没打开”。后续需要继续处理材质、静态遮蔽、间接光和环境层次。

这一步帮助我把修改顺序稳定下来:

看到的问题接下来检查什么对应修改
建筑位置、比例不顺相机、体量和空间锚点调整模型与镜头
檐下、接缝缺少层次接触遮蔽和静态光照AO、间接光烘焙
幕墙像平面贴纸窗后几何、纹理使用位置和反射补楼板与隔断,调整材质
园区像空地上摆了几栋楼入口、景观、人物和背景延续补路径、设施、植被与街区

这张表不能替代视觉判断,但能让每轮修改更具体。烘焙因此成为其中一条有明确用途的技术路线。

城市层也按这个顺序拆解。对照下图,先检查湖泊、道路、区域边界和示范园区的位置关系,再继续看街区密度与地表层次。把整张图拆成这些可检查的部分,修改才有落点。

城市设计终稿:湖泊、区域边界与示范园区

图 4|城市 AI 设计终稿,展示不同空间层级需要形成的关系。

第四步:先在 A1 做烘焙样区,把路线跑通

我先选 A1、裙房和相邻广场做技术样区。范围足够小,能够集中看建筑接触面、框架和檐下;同时又包含建筑与地面的关系,适合验证光照贴图接入网页的效果。

Codex 通过 Blender MCP,为石材、框架、铜色构件、屋面和广场准备第二套 UV,再使用 Cycles 分别烘焙 AO 和间接光。

可以把 AO 理解成对局部遮蔽关系的补充:裙房檐下、构件缝隙和建筑接地处应当比空旷表面更暗。间接光则负责静态漫反射层次,让光照能在相邻表面间产生变化。两者结合后,建筑和地面的接触关系有了更多表达手段。

样区的 AO 使用 2048 × 2048 贴图,内嵌到 GLB;网页用的间接光转为 1024 × 1024 的线性 PNG,约 0.55 MB。高精度结果保留在制作侧,网页加载适合运行的版本。

这一轮还明确了哪些对象不应进入烘焙:车辆、人物、喷泉水体和选中高亮会变化,玻璃需要随视角表现反射。这些内容继续交给实时渲染。否则车开走后地面还留着它的阴影,或楼宇选中态被固定到纹理上,画面会立即露馅。

样区还用于比较实时材质、AO 与间接光的组合。先确认 UV、贴图通道、材质绑定和网页显示都接通,再扩大到主场景,可以把风险控制在一块看得懂的区域内。

第五步:把烘焙铺到主场景,也把 UV 问题彻底修掉

技术样区跑通后,烘焙逐步覆盖园区静态地面、建筑和固定设施,并补充城市静态地表 AO。园区铺装进一步在 Blender 中进行 Cycles COMBINED 烘焙,把静态表面的颜色与光照关系写入贴图。

这时出现了开篇提到的问题:地面 UV 重叠。

UV 可以理解成把三维表面展开到二维贴图上的位置。用于重复铺装的纹理坐标可以重复使用,但接收各处不同光照的表面需要有独立的烘焙空间。如果几块地面占据同一片 UV,烘焙时它们会争用同一块图像区域,得到的明暗自然不对应实际位置。

处理方式是回到 Blender,把相关接收面重新整理为联合、无重叠的 UV,再重新烘焙、导出和查看。这个过程比继续试曝光、阴影强度或材质颜色更直接,因为问题发生在贴图与表面的对应关系上。

网页端也需要配合。烘焙 AO、屏幕空间 AO 和实时阴影都可能让表面变暗,需要控制各自强度。实时太阳光继续负责运行中的光照关系,静态贴图负责已确定的接触与间接层次,避免重复叠加后把地面和楼脚压成一片灰黑。

这轮之后,我更重视“修改归属”:UV 错了就修 UV,构图不对就修相机和模型,材质缺少层次就检查材质。每种技术都有具体职责,效果才容易控制。

下面放一张园区实际运行画面,方便观察地面、建筑与景观如何组合起来。它记录的是多轮修改后的整体结果,接下来两步继续展开幕墙和景观的制作。

园区实际运行页面:地面、建筑、景观与产业面板

图 5|园区实际浏览器截图,包含烘焙、幕墙和景观等多轮修改。

第六步:处理幕墙,让 A1 的近景有东西可看

园区远景里看起来成立的玻璃,到了 A1 近景可能就不够用了。整面重复的窗格、均匀反射和随机亮点容易让塔楼变成一块大亮面;越靠近看,重复感越明显。

这一步对照的是 A1 楼宇设计图,重点观察塔楼窗框、古铜色翼片和裙房的进退关系。

A1 楼宇设计终稿:玻璃塔楼、古铜色翼片与退台裙房

图 6|A1 AI 设计终稿,作为楼宇形态、幕墙和近景光照的视觉输入。

我把幕墙处理拆成三层。外侧保留玻璃、框架和古铜色竖向翼片;玻璃后增加楼板、墙面、隔断和灯带;办公室图集只用于窗后墙面,提供百叶、家具和灯光细节。三者共同构成展示用的窗后空间。

这种组织方式也保住了建筑身份:A1 仍然是三级裙房加 21 层塔楼,所有细节都加在原来的业务对象下。切到近景后,经营数据、楼层定义和园区中的选择关系继续沿用。

然后再处理光:使用环境反射,补充暖色侧光,让竖向翼片与窗框更容易从背景中分离;提高天空纹理质量并使用线性过滤;加入 SMAA 抗锯齿,减轻细框和建筑边缘的锯齿感。

这里也开始按观察距离分配成本。园区总览没有必要完整绘制所有窗后结构与折射,进入 A1 近景后再启用相关细节,并使用半分辨率的折射缓冲。镜头离建筑多远,决定了哪些内容值得花渲染预算。

进入网页中的 A1 近景,可以同时看到建筑模型与楼宇信息面板。

A1 实际运行页面:塔楼、裙房与空间利用信息

图 7|A1 实际浏览器截图,园区总览与楼宇近景使用同一份模型。

第七步:把楼之间的空间补出来

当楼本身逐渐清楚后,最显眼的问题就转移到了楼与楼之间。只有主楼、几片草地和树,园区仍然像一个摆好的模型。入口、步行路径、公共设施和背景街区决定了空间能否连起来。

南侧两处步行入口就是一个很具体的修正:从 C1/C2、C2/C3 之间连接到南侧人行道,清理遮挡入口的植被,补连续浅石铺装,并与车行道内缘保持 0.5 米净距。路径接到了哪里,需要在模型里检查,不能只在截图上看见一条线就算完成。

人物同样保留米制尺度,在入口、喷泉周边和楼前补充行人,用双腿、手臂和衣服颜色区分轮廓。可见度通过位置与对比改善,比例仍与建筑和道路保持一致。

背景则补上高低错落的办公街区与绿化地块,延续园区外围的城市语言。这样镜头旋转或退远后,主景周围仍有空间延伸。

植被经历了从单一叶簇到共用四树种图集的调整。绿色、浅金黄、近白樱花粉与深绿香樟通过面 UV 选择,并按小区域分布,避免整片树只有一种色调。城市与园区共用这套材质输入,也更容易保持统一。

城市层还补充了 2400 组低矮植被,地表改用低对比、无明显方向的斑驳,移除早期周期性条纹。这样的修改单项看很小,但它们都在减少规则重复带来的人工感。

第八步:让用户能够顺着空间继续操作

前端的分工很直接:Vue 处理当前层级、选中对象、数据模式、导航和面板;Three.js 处理模型、相机、光照、拾取、后期效果与动态对象。

在园区点击楼宇,Raycaster 从相机发出拾取射线,找到模型对象对应的楼宇 ID,更新 Vue 的 selected。浮卡和左侧摘要读取同一个选中对象,因此楼层、面积、出租率与企业数一起变化。

我没有让每次选楼都强制推镜头。点击 B1 或 C1,用户仍留在原来的园区视角继续比较;A1 提供进入重点楼宇的入口。这样既能查数据,也能保留空间探索的连续性。

信息卡的处理比“投影一个三维点”多一步。卡片先尝试对象四周的位置,再检查标签、导航和操作区等障碍物;拥挤时继续寻找边缘空位,并对频繁换边增加惩罚,减少镜头轻微移动时卡片来回跳动。连线从标签边缘连接到卡片边缘,尽量避开正文。

城市到园区的过场则由统一时间线协调。首次进入约 2.8 秒,再次进入约 1.1 秒,A1 返回园区约 0.6 秒。镜头、两个场景的透明度、标签、左侧面板和 KPI 分段交接,用户能看见自己正在从区域尺度靠近园区。

资源加载也参与这条时间线:园区没有准备好时,停在交接位置等待;加载失败则回到城市并提示重试。页面切到后台时暂停推进,系统偏好减少动态效果时缩短过程,避免动画只按固定时间跑完,结果场景还没出现。

城市页面把区域边界、产业楼宇与配套服务点位、园区入口和三层导航放在同一个视野中。静态截图可以看到这些入口的位置,镜头交接与浮卡操作可以在在线页面体验。

城市实际运行页面:区域边界、点位与园区入口

图 8|城市实际浏览器截图,点击示范园区可沿空间路径进入园区层。

第九步:把动态细节做活,再控制它们的成本

交通是很适合让园区“活起来”的细节。项目保留 18 辆演示车辆:9 辆轿车、6 辆 SUV、3 辆轻型货车,配黑、白、红、灰车身。车型有各自尺寸与轮廓,沿外围双向车道运行。

路线从道路规格派生,直线与圆角共同组成闭合路径,车辆位置和朝向沿路线采样。它们共用交通时钟,喷泉也持续更新。动态内容因此有稳定节奏,同时不会参与经营统计或改变楼宇数据。

随着植被、窗后结构和后期效果增加,性能也要跟着看。项目做了几项有明确对象的取舍:城市和园区分层加载;园区与楼宇复用同一模型;总览关闭不必要的近景细节;AO 降低内部采样分辨率;页面隐藏或场景不活跃时跳过绘制。

过场的连续进度还会直接更新少量 CSS 变量,阶段状态才进入 Vue 响应式更新,避免为了每帧透明度变化让整屏组件树反复更新。

本机 1920 × 1080 生产页面连续进行 12 次园区/楼宇往返后,几何计数为 235、纹理计数为 32,保持稳定;循环采样帧间隔 P95 约 34.3 ms。切镜时 draw calls 采样为 259–354。记录这些值的目的,是让增加细节时能看到具体成本,后续有据可查。

第十步:把能打开的工程,整理成能重导的工程

制作过程中,源工程、贴图与导出文件需要一起维护。项目保留城市和园区两份 Blender 工程,所需图像打包到工程,固定材质输入有独立清单,操作记录按阶段保存。当前园区 GLB 约 18.6 MB,城市约 24.2 MB。

我还做了一次独立目录复验:复制保存的工程与源码,通过真实 Blender MCP 加载两份工程、重新导出 GLB,再从规划源生成运行配置,安装锁定依赖并构建网页。重导 GLB 与交付资产的哈希一致,运行配置也一致。

它验证的是保存工程的可重导性。阶段操作有各自的前置场景状态,所以重导从保存好的工程进入,历史记录用于追查每轮修改。

项目记录中,22 项契约与几何测试、生产构建通过;浏览器侧还检查了三层切换、C1 指标同步、城市浮卡、无数据状态以及交通与喷泉。数字、对象和实际操作都要放到一起看。

如果只想运行网页,模型与贴图已随源码提供,前端不需要连接 Blender:

git clone https://github.com/Xxcool/urban-building-dashboard.git
cd urban-building-dashboard/app
npm ci
npm run dev

四、结束:这次制作,真正积累下来的是一条工作路径

回头看这个项目,画面是分很多轮形成的。先生成暗色夜景与浅色日景概念,比较构图和阅读方式;浅色方向修订后,再形成整屏设计并补齐三层空间。制作阶段搭起楼宇和道路关系,调整镜头与体量;A1 样区把 UV、AO、间接光和网页材质接通;主场景继续处理地面、幕墙、植物、入口和背景;最后把选择、浮卡、过场与动态交通连接起来。

Codex 带来的便利,是能在同一个工作上下文里读取规划、修改前端、通过 MCP 操作 Blender,再回到浏览器检查结果。一次关于地面的问题,可以沿着网页材质追到 GLB,再追到 Blender UV;一次关于选中楼宇的问题,也能沿着拾取对象追到业务 ID 和数据快照。

对我来说,最有用的几条经验都很具体:先用空间和相机解释设计图;烘焙先做小样区;出现异常时确认它属于几何、UV、材质还是光照;每轮都保存工程并打开真实页面;增加细节时同时看帧时间与资源计数。

现在打开页面,用户可以从城市进入园区,再靠近 A1,查看对应的空间与经营信息。沿着这条路径,也能看到一张设计图怎样逐渐变成可以探索的三维场景。

欢迎打开在线页面体验,也欢迎交流:你在做实时三维场景时,最先会处理哪种“不真实感”——光照、材质,还是空间中的细节?


体验与源码:在线打开大屏 · 查看 GitHub 仓库