1. 项目基线与挑战设定:三个模型写同一个 3D 游戏
最近不少群友都在讨论 Step 5 Preview 这个新工具,加上 DeepSeek V4 Pro 和 GLM5.3 这两大模型的热度,很多人都在观望:到底哪家写代码更顶用?与其听厂商吹牛,不如拉出来遛遛。我这次干脆搞了个狠活:让它们仨各自从零写一个完整的小型 3D 游戏,同一个需求、同样的约束条件,全程只靠 AI 生成,我负责跑代码、改 bug、记录过程。
先说下我选型。Step 5 Preview 不是传统意义上的大模型,它更像一个集成的开发环境或中间层编译器,能把自然语言直接映射到可执行逻辑,这跟直接用 ChatGPT 聊天是完全不同的使用体感。DeepSeek V4 Pro 就不用多说了,老牌硬货,国内开发者天天用它写业务代码,代码生成密度高、上下文咬合能力强。GLM5.3 最近则是借着 GLM5.3 flashx 和部署相关的话题火得不行,尤其大家都在传它的推理能力又进化了,vLLM 部署生态也日趋完善,所以必须放进这次的角斗场。
游戏目标我定得很具体:做一个基于 Three.js 的网页版 3D 采矿生存游戏,玩家第一人称在方块地形上行走、挖矿、收集资源,并能在简单的阳光场景里看到阴影和光照变化。为什么选这个?因为 3D 游戏开发工具链长,涉及 3D 数学、渲染管线、碰撞检测、循环与事件系统,远比写个 CRUD 接口难度高。这个题目对三个模型的代码组织能力、API 记忆准确度和 bug 自愈能力都是不小的考验。
1.1 3D 游戏开发工具选型:从架构到画布
四个维度限制好,可以让比赛更公平。第一是技术栈,必须用纯前端实现,Three.js r160 以上版本,不能用后端服务;第二是文件组织,允许生成多个模块文件,但最终必须能直接在浏览器里跑起来;第三是交互要求,支持 WASD 移动、鼠标视角旋转、点击挖矿;第四是视觉效果,要求有太阳、方向光阴影、雾效和简单的天空盒。
在动手之前,我先规划了一下这项目在现实中该怎么做。常规做法是:引入 three.js,先初始化场景 Scene、相机 Camera、渲染器 Renderer,再写一个 Perlin 噪声或 simplex 噪声函数生成地形高度图,用 BufferGeometry 构建方块网格,之后还要处理射线检测 Raycaster 来实现点选挖矿,最后把玩家的移动和重力逻辑塞进 requestAnimationFrame 循环里。这里最阴间的部分是碰撞检测,如果只做地形高度跟随,很容易整个掉出地图。
1.2 三个模型的参赛身份卡
- Step 5 Preview:以 IDE 插件模式运行,目标是类“自然语言即代码”的低代码逻辑,我好奇它对 3D 工程的理解是不是足够深。
- DeepSeek V4 Pro:标准的大模型,上下文窗口给足,我模拟正常开发者的用法,让它一口气出代码。
- GLM5.3:同等级别的大模型,我故意在提问时混杂了 GLM5.3 flashx 和 vllm 部署辅助信息,测试它在复杂条件下是否会被带跑偏。
这里插个很重要的经验:让大模型写游戏时,提问的粒度决定代码的可用性。你直接说“给我一个 3D 游戏”多半会收到一个 Demo 但极其粗糙的产物,但我如果分模块去委派任务,比如先生成“地形生成模块”,再生成“用户控制模块”,它们各自完成的部件逻辑耦合度会显著降低,这对我后续改造很重要。
2. 开场白:三个模型的方案设计与代码骨架差异
第一次指令我完全一致,任务描述就是“用 Three.js 写一个第一人称 3D 采矿游戏,地形为 100×100 的方块网格”。这三个模型的响应速度都不慢,但方案差异相当大。
| 维度 | Step 5 Preview | DeepSeek V4 Pro | GLM5.3 |
|---|---|---|---|
| 文件结构 | 单一 HTML 文件 | 拆成 scene.js、terrain.js、player.js、main.js 四个文件 | 单文件但内部注释详尽 |
| 噪声算法 | 内置了简单的正弦波叠加 | 实现了标准的 Perlin 噪声 | 使用了基于梯度的 Simplex 噪声 |
| 挖矿逻辑 | 支持射线检测,但参数写死 | Raycaster 参数完整,可复用 | 封装了独立的 Raycasting 类 |
| 初始可运行度 | 能跑,但阴影错位 | 跑不起来,窗口未加载 | 能跑,但 FPS 低到感人 |
DeepSeek V4 Pro 给的文件结构最工程化,拆分成多个模块是符合大型项目的思维,但问题也来了——它竟然忘了在 terrain.js 里导入THREE对象,导致整个页面白屏。这个错误很典型,实际上就是因为大模型在长上下文中生成多个关联文件时,会因为注意力分散而遗漏 import 语句。GLM5.3 则显得更保守,所有代码放一个 HTML 文件,而且它考虑了性能,采用了 Simplex 噪声,只是它在每一帧都重新计算了所有方块,导致帧率直接跌到个位数。
Step 5 Preview 给的方案更另类。它直接把渲染循环抽成了一个独立的状态机层,内部生成大块缓存并重绘,这在思路上很聪明,从源头避免了重新计算的性能损失。但它的问题在于默认的方块大小是 1×1×1 的 CubeGeometry,光影贴图却挂在 2×2×2 的方块上,肯定会出现阴影跟模型脱节的视觉 bug。这也是很多 AI 生成 3D 代码的通病,对几何尺寸不够敏感,材质和光照矩阵匹配混乱。
2.1 为什么 Step 5 的架构思路值得关注
个人观点,AI 写 3D 代码最难的不是语法,而是对运行时的掌控。普通的 LLM 写出来的代码,看起来像一段静态规范,每个模块只在乎输入输出正确,完全不在乎这个世界是怎么被渲染出来的。Step 5 Preview 更像是带了一点“执行意识”。
我这次给了它一个非常规的追加要求:“把整个循环拆成状态机,主循环里只做 state.update() 和 state.render()”。这个要求对于大部分模型来说过于抽象,但 Step 5 Preview 居然跑出了“地形生成状态、挖掘状态、人物移动状态”的分离逻辑。这样的代码对我后续做二开极其友好,只需往状态里加方法即可,相对大模型的简单堆叠要好维护得多。
2.2 实操中的注入命令参考
如果你是照着复现,用 DeepSeek V4 Pro 时,建议把“工程化”这层要求说得更具体。我第二次重新拉取 DeepSeek 版本时,改用了这样的指令:
现在拆分地形、玩家控制、输入处理三个模块,并确保在三个模块中彼此通过一个全局的 GAME 命名空间通信,不要把 THREE 对象散落在各个作用域而没有导入,请给出完整的 init 顺序说明。加了这一句之后,DeepSeek 的表现就正常了许多,说明它不是在能力上弱于另外两个,它只是太喜欢以“标准但没有边界”的方式输出结果了。你叫它写多个文件,它就真的各写各的文件,甚至不像人类工程师那样统一确认接口参数。而 GLM5.3 在这方面更像一个“同步型”选手,它习惯于把代码平铺在一起,好处是极易复制运行,坏处是扩展性堪忧。
3. 核心环节实战:从渲染管线到物理系统的逐步修复
现在进入最容不得马虎的部分,3D 游戏开发的核心环节。我把三方生成的代码都跑了一遍,然后用统一的修复目标——要求它们最终输出一个能在 60 帧左右流畅运行、能解析碰撞并显示阴影的成品。这里就暴露出很多技术细节上的取舍问题。
3.1 地形渲染与性能优化的现实博弈
GLM5.3 里有个很要命的问题:它用完整的方法绘制 100×100 个独立的小方块。10000 个网格的绘制调用,对大部分 PC 浏览器来说都是灾难,DirectX 的 draw call 一多就直接把 CPU 压垮。这在 WebGL 里尤其明显,因为它无法复用缓存,每个 Mesh 都要单独提交纹理和矩阵。
我直接对它下达了强制优化指令,要求“把地形简化为单一 BufferGeometry,仅根据高度图生成顶点坐标,在顶点着色器里做位移偏移”。这个提示抛出去后,GLM5.3 的响应出奇地好,它居然能识别出来要构建一个叫做TerrainGeometry的类,并自动填充了位置数组和法线数组,这个方法是对的——顶点搅动比逐个方块渲染的效率高出一到两个数量级,因为 GPU 只需要处理一张大的网格。
相关核心代码片段的正确形态通常长这样,注意SetAttribute的参数:
const geometry = new THREE.BufferGeometry(); const positions = []; const indices = []; const size = 100; for (let x = 0; x <= size; x++) { for (let z = 0; z <= size; z++) { const y = getHeight(x, z); positions.push(x, y, z); } } for (let i = 0; i < size; i++) { for (let j = 0; j < size; j++) { const a = i * (size + 1) + j; const b = a + 1; const c = a + size + 1; const d = c + 1; indices.push(a, b, d, a, d, c); } } geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setIndex(indices); geometry.computeVertexNormals();我实际跑过后结果表明,这个优化完全可行,画面帧数瞬间从 8 帧提升到 50 帧以上,可见很多大模型不是不会优化,而是默认只会写概念上的“功能正确”代码,不会主动考虑性能边界。
3.2 光照和材质的坑:为什么我的太阳老是黑脸
光照系统算是我这次踩得最疼的坑。三个模型对光源的理解都不差,但一落到实际屏幕上,问题就接二连三地出现。DeepSeek 给的代码直接使用了MeshLambertMaterial(一种不支持镜面反射的材质),这本来没错,但它却开了阴影映射castShadow = true,结果渲染时地面全黑,因为 Lambert 材质不带高光,环境光又给得不足,相当于在房间里只开了一个探照灯。
更隐蔽的问题是 Step 5 Preview 的默认渲染器竟然用的是WebGLRenderer去渲MeshStandardMaterial(一种基于物理的材质),如果你没有给场景添加PMREMGenerator来处理环境贴图,渲染出来的所有物体都会像蒙了一层猪油,灰蒙蒙的。要解决这个演示级的 bug,需要手动在renderer上设置physicallyCorrectLights和outputEncoding,或者干脆把材质统一改成MeshPhongMaterial平衡光照与外观。
我的最终选择是引导三个模型全部使用MeshPhongMaterial搭配半球光HemisphereLight加直射光DirectionalLight。这个组合是我操机多年验证过的“最不容易翻车”的三件套,半球光提供基础的环境底色,直射光提供明暗对比,Phong 材质给一点 specular 反光,物理氛围一下就出来了,也不会像 Standard 材质那样依赖环境贴图。
3.3 碰撞与挖矿的数学应用
第一人称视角的坑其实集中在相机控制上。很多生成代码会让相机跟着角色平移,但忘了鼠标旋转也会造成世界坐标系翻转,导致玩家发动手柄时会像喝醉酒一样平移。正确做法是不要动相机的position,而是用 Euler 角度分解到目标方向向量上。
挖矿的核心则是 Raycaster,这地方 Step 5 Preview 写出了我预想之外的 bug——它在raycaster.ray.intersectObjects(scene.children)里直接把整个场景的物体都加入了计算,导致挖掘方块时经常会选到远处的天空球或者玩家自身的碰撞体。这个其实是每个新手都会犯的经典错误,解决方案很简单,过滤掉不可拾取的物体,只留地形网格的 Mesh 数组。我把这个修正命令直接发给了 GLM5.3,它给了我一个很标准的filteredTargets函数。
所以这里给大家一个提示:交互动效必须明确指定目标检测列表,否则在大模型生成的代码里,射线检测极大可能检测到所有实体,导致逻辑混乱。这也是 3D 游戏开发工具中无可争辩的优化共识。
4. 模型差异深水区:部署生态与业务场景的拉扯
做 3D 游戏有一半的时间并不在写游戏渲染逻辑,而是在调环境。这次三个模型的差异在后半程体现得越来越明显,特别是当你去问它“这个项目怎么本地化部署时”,GLM5.3 就显露出它的强势面。刚才我们提到现在网上都在搜 glm5.3 flash 910b 部署,问“glm5.3 使用 vllm 哪个版本的镜像”,这说明大家已经开始在海量算力环境上自托管了。
如果你也打算用 vllm 来跑 GLM5.3 模型做完全本地化的代码推理,必须注意它和普通模型部署的差异。针对这块我做过拆解,它不像一些老架构那样能直接对接默认的 transformer 接口,你要特别注意 prompt chat template 的替换,如果未正确加载配置文件,生成内容会出现各种续写胡言乱语的情况。
在实际操盘中,我建议大家在环境内编排类似的逻辑:
# 拉取镜像时尽量选与 vllm 0.6.x 匹配的版本 # 启动命令参考: python -m vllm.entrypoints.openai.api_server \ --model glm-model-path \ --tensor-parallel-size 4 \ --max-model-len 8192 \ --trust-remote-code这里的--trust-remote-code参数千万不要省,缺少了它,很多内部代码被识别为“不可信”而根本无法加载。
不过要注意的是,真正的高手在写前端业务时,并不会真去拉一个大模型在本地跑。如果只是为了写 Three.js 页面,用 API 调用 30 秒就能拿到结果,何必大费周章做本地部署。你自我部署的目的是为了隐私和降本,而不是为了触发 IDE 补全。这点思路别搞反了。
话说回来,这次动用 GLM5.3 给游戏做道具识别时,它的长序列理解让我很意外。我问它“在玩家挖掘 10 个铁矿后,自动在右上角生成一个铁锭图标”,这种游戏内视觉状态转换的需求,一般的模型会生硬地返回一段假设代码片段,但 GLM5.3 会主动在前 5 行就判断好状态变量,并在后面同步调整 HUD 的显示位置。这种“编程意识”是更接近人类工程师习惯的。
4.1 关于 doubao-seed-2.0-code 的横向比对
不少人在搜索时会把 doubao-seed-2.0-code 与 glm5.3 并列起来比较。我的实际体会是豆包的代码生成速度极为激进,但如果在 3D 场景这种高度结构化的代码里掺入强状态耦合需求,它的代码有时候会产生不必要的抽象层。反观 GLM5.3 则偏向于注解式编程,生成代码时爱写注释,注释里会把每一步意图都说明白。这个习惯在维护 3D 渲染代码时确实很加分。
但要说代码质量和算法合理性,DeepSeek V4 Pro 在 Raycasting 引用方面更能给出正确的 api 签名。我故意在要求里没给范例,只有 DeepSeek 能准确写出raycaster.setFromCamera(pointer, camera)这一行,说明它在训练数据中确实吃透了三套引擎的资料,而不是单纯拼接。
4.2 从单一游戏看大模型的真实长板
扯远一点,用 3D 游戏作为 AI 编程能力测试用例,比跑分榜单更有参考价值。跑分测试的是“知识的完整度”,而 3D 游戏测试的是“运行时稳定性的判断力”。像 Step 5 Preview 这种带预览模式的执行环境,它能在输出前自己跑一遍分块逻辑,局部纠错能力特别强。但 DeepSeek V4 Pro 和 GLM5.3 这类静态生成工具,更像是一位资深顾问——它给你的意见通常对,但你必须自己执行落地。
所以给项目做选型时,我建议按这个逻辑来:若你在做原型快速验证,Step 5 Preview、以及类似的国产可视化生成器会帮你节省 30% 的无效编译时间。若你在做复杂商业项目、逻辑不允许出一丝错,那还是老老实实让 DeepSeek 出高完整度代码,自己管理构建流程。而 GLM5.3 更适合做“审查员”的角色,挑毛病补漏洞。
5. 常见问题与排查技巧实录
当我实际把三个模型输出的产物揉在一起调试时,也遇到了一些令普通程序员极为崩溃的随机错误。我在这里整理几个高频问题,直接做成速查表,你复现时能少走弯路。
| 报错或现象 | 实际原因 | 排查解决示例 |
|---|---|---|
| 地形渲染全白/全黑 | 材质法线丢失,或光源强度不合适 | 调用geometry.computeVertexNormals()并重新编译材质 |
| 移动时相机从天到地翻转 | camera.up被意外修改 | 固定camera.up.set(0,1,0)并利用四元数控制视角 |
| 挖不到矿但点击有方块高亮 | Raycaster 检测了背景天空球 | 筛选目标数组,只保留地形网格组 |
| 阴影边缘出现锯齿闪烁 | 阴影贴图分辨率不足 | 将renderer.shadowMap.type设置为THREE.PCFSoftShadowMap |
| 角色陷落地形内部 | Y 轴坐标未与高度图对齐 | 用getHeight(x,z)数值重写碰撞和重力逻辑 |
WebGL 报Out of Memory | 每个帧都 new 网格对象 | 使用缓存池或 BufferGeometry 更新法 |
5.1 隐藏在性能优化中的两个魔鬼细节
一个坑是光照矩阵的更新频率。Three.js 中如果开启了renderer.shadowMap.enabled,每次改地图方块都会消耗一定的阴影贴图重渲时间,导致 FPS 瞬间掉到 10 以下。我的实操策略是把挖矿生成的方块临时依附到独立的不投影阴影图层layer = 1,等挖矿事件停止后再合并回主场景。这听起来很冗余,但对帧率的提升是肉眼可见的。
另一个坑大家一定要记住,不要在新版本库里用THREE.Float32BufferAttribute反复setY,不如直接重建一个数组替换 attribute,大模型经常会在一段死循环里更新 position,导致显卡驱动直接准备崩溃。正确的代码大概是geometry.attributes.position.setXY()配合needsUpdate = true的方式。
5.2 三个模型的 Bug 修复风格对比
- GLM5.3:面对报错,喜欢修改调用参数,有种“遇到问题先怀疑入参”逻辑,很少重写底层函数。
- DeepSeek V4 Pro:倾向于整体重构,见错就推倒重来,希望你给它更宽松的约束。
- Step 5 Preview:精通局部补丁,像是做过 3D 调试器一样,能准确指出第 217 行的三个参数位置不对。
如果你是让它们共同协作,那最好的方法就是:让 GLM5.3 审查架构不良实践,让 DeepSeek V4 Pro 输出标准化全部模块,再结合 Step 5 Preview 来做底层的事件循环优化,三管齐下能发挥最大合力。
我用这套组合拳后,游戏的最终版本基本稳定在 60 FPS,代码量大约 3000 行,其中 AI 生成的占 92%,我自己手动修正的部分不到 200 行。这说明现在的大模型完全有能力把硬核 3D 应用从零搭起来,你只要负责明确规格和修量级的 bug 即可。
6. 终点复盘:我实际操盘后的几点判断
三款工具都跑完之后,至少在 3D 游戏开发这个细分场景,我得出了一个可能跟很多人固有印象不一样的结论。大家都觉得 DeepSeek 写套餐化 Java 业务代码天下无敌,但在处理 GPU 渲染循环、状态机联动、物理引擎碰撞这类活时,它的“多文件协作”能力反而成了致命弱点。每一次跨模块引用都会增加它崩溃的概率,而这在 Three.js 这种强依赖全局上下文的领域里非常吃亏。
反倒是 Step 5 Preview 的表现并没有传闻中那么拉胯,它最大的优势不是基础代码生成,而是它的预览会话能记住上一次渲染时的 GPU 对象状态,这有点像你在做一个动态调试器,改一行业直接看全屏效果,特别适合图形学这种“非所见即所得”的开发类型。可它也有局限,只要碰到涉及异步加载资源(纹理贴图 Loader 等待)的复杂场景,它就会生成过于保守的边界检查代码,拖慢加载速度。
GLM5.3 最后的成片质量让我最意外。它生成的游戏画面完整性是三者中最高的,色调整体偏暖,完全是同类 Demo 里挺少见的高级审美倾向。它的性能瓶颈也主要在生成后第一次运行的加载期,在后续逻辑增补上改造成本最低。如果你想要一个“拿到就能开工、改起来不疼”的项目基底,我会第一个推荐 GLM5.3。
我的建议是:别纠结某一家独大,也别轻信网上对新版本的盲目吹捧。你大可直接复刻我这个 3D 游戏实验,把三个模型都塞进去跑一遍。一轮流程下来,你会清晰地看到它们各自的“性格”,也能摸索出最适合你项目风格的工作流。对我个人而言,未来一段时间内,主力用 DeepSeek 做底层架构设计,用 GLM5.3 做快速回退兜底,再用可预览的中间层工具直接调素材和渲染。这一套组合我基本已经焊死在开发流程里了。