把你的书桌变成3D赛车场:从照片、建模到录屏的手把手教程
拆解 Desk Racer 的完整制作流程,用 Gemini、Blender MCP 和 Three.js 做出可玩的桌面赛车,再录成演示视频。附双语过程视频和逐轮中英文提示词。
Google 开发者关系工程师 Geneviève Huskens 分享一个使用 Gemini 4 Argon 将她的办公桌变成赛车场的炫酷案例:她用手机给自己的办公桌拍了一组照片,随后在 Google Antigravity 环境中调用 Gemini 4 Argon 模型,通过 Agent 任务编排,连接 Blender MCP 与 Three.js,将键盘、显示器和桌面摆件变成了一款可在浏览器中驾驶的 3D 桌面赛车游戏《Desk Racer》。
如果你用手工制作这样的游戏,要安排道具的位置与尺寸、建模和贴材质,再编写驾驶、碰撞和镜头控制。而在这套新流程中,AI 可以直接分析多角度照片中的桌面空间布局,通过模型上下文协议(MCP)向 3D 建模软件注入 Python 脚本生成几何体,自动编写前端渲染与赛车控制代码,并在浏览器运行环境中通过截屏自我审视画面缺陷,分步迭代材质与灯光。
这是她第一次认真制作 3D 项目。跟做时,照片提供布局参考,你决定赛道走向和画面风格,AI 负责把这些要求落实为模型、代码与可玩的场景。
先选路线:在线试玩改编,还是本地自建书桌赛道
先分清各工具的作用:
| 工具 | 在这个项目中做什么 |
|---|---|
| Gemini 4 Argon | 看照片、问清需求、制定计划、编写和修改代码 |
| Nano Banana | 生成概念图与木纹、路面等表面贴图 |
| Blender MCP | 让 Agent 通过 Python 脚本建模,并导出 GLB 道具文件 |
| Three.js | 在浏览器中加载场景、渲染画面并响应驾驶操作 |
只想做简洁的低多边形场景,可以先用 Three.js 的基础几何体,跳过 Blender;需要更细致的道具结构时再加入建模流程。
【路径 A:在线快速体验与改编 (AI Studio)】
无需本地环境 ──> 浏览器打开 Desk Racer ──> 点击「Remix」──> 直接修改赛车速度/赛道颜色
适合:想立刻上手体验操控手感、观察现成代码结构、暂不配置本地环境的读者。
【路径 B:打造自己的书桌赛场 (本地全套管线)】
手机拍自己的桌子 ──> Antigravity / 智能体编排 ──> Blender MCP (建模) ──> Three.js (可玩游戏)
适合:希望将个人工位、卧室书桌转化为专属 3D 场景并录制高质量演示视频的读者。
1. 路径 A:在线体验与改编(无需安装)
官方已在 Google AI Studio 应用库中公开了《Desk Racer》的在线运行页面。在页面中可以直接看到:
- 预览与操作:点击进入游戏,按
W加速,A/D转向,S刹车;按数字键1(跟车视角)、2(座舱视角)、3(桌面全景俯瞰)、4(无人机漫游)自由切换机位;按Enter开启三圈计时挑战。 - 源码与资产入口:页面顶部提供
Preview(实时画面)、Code(Three.js 与物理脚本源码)、Artifacts(模型与贴图资源)以及Remix(分叉复制为自己的云端项目)。 - 改编入口:点击 Remix,把现有作品复制到自己的项目后,可以向助手提出修改需求。先改速度或颜色容易观察效果;要换成自己的书桌,还需重新设计道具布局与资产。
2. 路径 B:从零自建你的专属书桌赛道
自建方案需要模型理解你的真实空间几何。原作者在演示中使用的是结合 Gemini 4 Argon 驱动的 Blender MCP 流程。作者未公布所用无头(Headless)Blender MCP 的具体安装配置,本教程采用有公开安装文档、需要保持 Blender 开启的桌面端 mcp-for-blender 替代路线,配合本地运行的 Three.js 项目实现从照片到游戏的闭环。
账户与环境条件:
在官方演示环境中,Gemini 4 Argon 在 Antigravity 中面向 Google AI Ultra 订阅者开放,而在 AI Studio Build 中面向 Ultra 或绑定结算的付费 Gemini API 用户。由于各平台模型选择器与配额策略会动态调整,请以你当前工作区的实际可用模型为准。如果在 Cursor、VS Code、Claude Desktop 或其他支持 MCP 的编程工具中跟做,通过自然语言调用对应 MCP 协议也可以执行建模与工程构建,需要分别确认该工具的文件编辑、MCP 调用、截图和任务持续执行能力。
第一阶段:配置 Blender MCP 与 Three.js 本地开发环境
要让 AI 替你操作 3D 软件并驱动网页游戏,必须在电脑中建立一条“代码助手 ↔ 3D 建模工具 ↔ 网页渲染环境”的通信管道。
制作过程视频 15 秒处,展示白木纹理桌面、显示器底座、键盘与台灯等待转化的真实道具。
本文的提示词均为跟做而改写的模板;尺寸、灯光数值和帧率目标是教学初值,按自己的桌面实测与电脑表现调整。原视频的录屏和剪辑软件未披露,后面的录制步骤是本文补充。
1. 安装基础依赖与软件入口
在开始之前,请访问对应官方网站下载并安装以下四个基础工具:
- Google Antigravity(或支持 MCP 客户端的编辑器如 Cursor、VS Code、Claude Desktop)。
- Blender 3.0 或更高版本:开源三维建模套件,安装后确认可正常启动进入三维视口。
- Node.js LTS:JavaScript 运行时,自带 npm 包管理器,用于启动本地前端服务器。
- uv 包管理器:用于快速执行 Python 工具包而无需污染系统 Python 环境。
- macOS 终端安装:若系统中已配置 Homebrew,执行
brew install uv;若未安装 Homebrew,可在终端直接执行官方安装脚本:curl -LsSf https://astral.sh/uv/install.sh | sh - Linux 终端安装:
curl -LsSf https://astral.sh/uv/install.sh | sh - Windows PowerShell 安装:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
- macOS 终端安装:若系统中已配置 Homebrew,执行
2. 安装与激活 Blender MCP 插件
我们将使用社区开源项目 mcp-for-blender,它通过本地 TCP Socket 让外部智能体可以向 Blender 注入 Python 脚本并取回几何数据。
在终端中执行以下命令自动安装插件到 Blender:
uvx mcp-for-blender install-addon
安装完成后,进行如下操作:
- 打开 Blender,点击顶部菜单栏 Edit(编辑)→ Preferences(偏好设置)→ Add-ons(插件)。
- 在右上角搜索框输入
MCP for Blender,勾选启用该插件。 - 回到 3D 视口,在英文输入法状态下按键盘上的
N键,呼出右侧侧边栏。 - 找到 MCP for Blender 选项卡,确认状态显示为已启动或点击 Start MCP Server(默认监听本地端口为
9876)。 - 在后续的所有生成过程中,请保持 Blender 窗口处于开启状态。
3. 配置 Antigravity MCP 连接
在 Antigravity 中,你可以通过项目级配置文件或全局配置文件接入该服务:
- 全局配置路径:
~/.gemini/config/mcp_config.json - 项目专属路径:项目根目录下的
.agents/mcp_config.json
在现有的 mcpServers 键内追加(注意保留已有其他服务配置):
{
"mcpServers": {
"blender": {
"command": "uvx",
"args": ["mcp-for-blender"],
"env": {
"BLENDER_HOST": "localhost",
"BLENDER_PORT": "9876"
}
}
}
}
排错提示:如果在启动时提示找不到命令 spawn uvx ENOENT,说明 GUI 编辑器未继承系统终端的环境变量。在 macOS/Linux 终端中运行 which uvx(Windows PowerShell 运行 where.exe uvx),将输出的绝对路径(如 /opt/homebrew/bin/uvx 或 C:\Users\username\.local\bin\uvx.exe)替换配置中的 "command": "uvx"。
连通性检查点:
完全重启 AI 编辑器,向智能体发送一条测试指令:"请调用 blender 工具,读取当前场景信息,并新建一个名为 TestCube 的红色立方体"。如果你看到 Blender 视口中立刻生成了一个红色立方体,并且 AI 正确汇报了物体名称,即表明 3D 控制通道已打通。
4. 创建工程目录并安装 Three.js
先建好项目目录和依赖,确认概念与计划后,再在第四阶段生成 HTML 和游戏代码。
根据操作系统执行目录创建与依赖安装:
- macOS / Linux 终端:
mkdir desk-racer cd desk-racer npm init -y npm install three npm install --save-dev vite mkdir -p public/models mkdir -p public/textures mkdir src - Windows 命令行 / PowerShell:
mkdir desk-racer cd desk-racer npm init -y npm install three npm install --save-dev vite mkdir public\models mkdir public\textures mkdir src
保留 npm install 写入的依赖版本,在 package.json 中合并以下字段;不要整文件覆盖已安装的 dependencies 和 devDependencies:
{
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
工具安装完成、Blender 连通后,继续拍照并确认视觉方向。正式生成游戏代码放在第四阶段。
第二阶段:拍照片,确定赛道外观与尺寸
先用 Nano Banana 做概念图,比较赛道绕哪些物体、灯光偏暖还是偏冷、赛车显得多小。选定一版后,后续建模和灯光调整就有共同参照。
1. 拍摄实物照片与多模态参考素材
参考素材可以是照片、草图,或约 15 秒的绕物视频。这次先拍清楚桌面全貌与关键道具,照片足够作为起点。
拍摄实物照片时,把握以下 4 个要点:
- 光照均匀充足:选择室内均匀明亮光线下拍摄,避免大面积死黑阴影干扰对物体边缘轮廓的提取。
- 全景布局照片:站在桌前拍 1~2 张包含整张书桌全貌的视角照片,明确显示器底座、键盘、鼠标与杯子之间的相对距离与朝向。
- 局部关键物特写:贴近键盘按键、台灯支架各拍 1 张特写,记录物体的厚度与材质反光特征。
- 清理无关杂物:移走散乱电线团与纸巾,保留具有明确几何特征的文具或摆件。
概念图生成后,先和 AI 一起评审 2D 概念图并挑选满意的视觉方向,确认后再开始编写 3D 代码。
官方概念构思参考过程(点击展开)
2. 概念图生成提示词
将拍摄的照片上传至多模态图像生成界面,发送以下提示词生成概念图:
模板 1:从桌面实拍照片生成微缩赛车概念图
中文可复制版本:
请分析我上传的书桌照片中的物品布局(显示器、机械键盘、鼠标、台灯摆件)。以这些真实物品为地形障碍,生成一张具有强烈微缩模型玩具质感(Tilt-Shift Macro Photography)的 3D 赛车赛道概念图。
视觉要求:
1. 一辆鲜红色的微型卡丁车正在键盘前方疾驰,车身尺寸与单个机械键帽相仿。
2. 赛道是一条高架曲面轨道,配有红白相间的减速路缘与柔光防撞护栏,轻巧地从显示器支架下方穿过并环绕鼠标。
3. 灯光具有戏剧性对比:暗调房间背景,屏幕背后的深紫色氛围光,机械键盘缝隙透出的青色背光,以及桌面台灯投下的高对比暖白主光。
4. 整体呈现出精致小巧的微缩玩具世界视觉质感。
English Copyable Version (Teaching Adaptation):
Analyze the desktop layout in the uploaded photos (monitor, mechanical keyboard, mouse, desk lamp). Using these real objects as miniature terrain obstacles, generate a 3D racing concept art with strong tilt-shift macro toy aesthetic.
Key requirements:
1. A vibrant red miniature go-kart racing in front of the keyboard, scaled proportionally to single keycaps.
2. An elevated curved track with red-and-white rumble strips and glowing barriers, looping under the monitor stand and around the mouse.
3. Dramatic lighting contrast: dim room ambience, deep purple backlight behind monitor, cyan glow between keycaps, and warm white key light from desk lamp.
4. Premium stylized game aesthetics reminiscent of a micro miniature toy universe.
3. 复杂桌面或多遮挡布局的 2D 空间规划分支(普通桌面可跳过)
对于摆放简单的小书桌,完成概念图后即可直接进入下一阶段。但如果你的桌面布局复杂(例如有多层置物架、双屏幕支架或错综复杂的外设摆件),或者希望赛车道严格贴合真实物体尺寸,还需要实测尺寸作为比例标尺。
先量桌面宽深和主要道具的长宽、高度,再让 Argon 生成带米制尺寸的俯视图 PLAN/layout.svg,并给照片加编号网格。确认物体位置和道路间隙后再建模,避免细节做好了才发现车道穿过键盘。
模板 2:复杂桌面 2D 俯视平面图与米制坐标生成(本文改写)
中文可复制版本:
请查看我上传的书桌照片与实测尺寸。以下以宽 1.2m、深 0.6m 为示例,先让我替换为自己的桌面和道具尺寸,缺少的尺寸向我确认。
因为本场景需要精确贴合物体间隙,请先不要生成任何 3D 网格代码:
1. **生成 2D 矢量平面图**:以米为单位,生成一份顶视图 2D 矢量图并保存至 `PLAN/layout.svg`,明确标注显示器底座、键盘、鼠标与边缘留白的绝对长宽与中心坐标(原点设在桌面几何中心)。
2. **叠加参考编号网格**:写一段轻量脚本或在 SVG 中绘制带编号的 X/Y 米制网格(间距 0.05m),标明计划中的闭环赛道走线与关键转弯控制点。
3. **空间通行检验**:检查键盘与显示器底座之间的预留间隙是否大于赛道宽度(0.08m),确认无阻挡后再输出坐标总结。
完成上述 2D 尺寸验证后,我们再依据这些已锁定的绝对坐标构建 3D 几何网格。
English Copyable Version (Teaching Adaptation):
Review my desk photos and measured dimensions. The example tabletop is 1.2m wide and 0.6m deep; ask me to replace these and supply the measured prop sizes before fixing coordinates.
Since this build requires spatial accuracy, do NOT generate any 3D meshes yet:
1. **Generate 2D Vector Plan**: Create a top-down 2D floorplan in metric units and save it to `PLAN/layout.svg`. Map out the exact bounding boxes and center coordinates for the monitor base, keyboard, mouse, and margins (origin at desk center).
2. **Numbered Reference Grid**: Overlay a numbered X/Y metric grid (0.05m spacing) across the layout, plotting the planned closed track loop and key spline control points.
3. **Clearance Verification**: Verify that the gap between the keyboard and monitor base exceeds the road width (0.08m) without collisions before outputting coordinate tables.
Once we verify these 2D spatial dimensions, we will use these locked coordinates to build the 3D scene.
第三阶段:先问清需求,再分工执行
在 Antigravity 中发送 /grill-me,让模型先问清操控、机位和道具处理方式。确认第二阶段的概念图后,请它写出 PLAN.md 和对应的 /goal 指令,再开始执行。
1. 确认玩法、机位和建模方式
先回答这些会影响实现的问题:
- “赛车的物理操控倾向于轻快灵敏的街机手感,还是带惯性与漂移的模拟手感?”
- “桌面道具是直接用 Three.js 原生几何体拼装,还是通过 Blender MCP 建立带倒角与独立坐标的 GLB 模型?”
- “赛道高架段与键盘、显示器底座之间如何预留落点净空,防止支柱穿模?”
标准执行顺序:
- 输入素材并发起盘问:在 Antigravity 中输入
/grill-me,上传桌面参考照片,要求模型此时先不要写任何 3D 代码。 - 确认概念图:让模型使用第二阶段选中的概念图;需要调整时再生成候选,在聊天窗口或 Markdown 中展示。
- 固化计划与长期目标:开发者确认概念图并回答盘问问题后,让模型将分步执行计划写入
PLAN.md,并生成一段就绪可运行的/goal指令。 - 启动长期自主循环:运行该
/goal指令,模型将围绕“赛车能顺畅跑圈、多机位可用、资产正确加载无报错”等具体检验指标持续推进任务。
2. 三个专业角色的任务分工与防冲突机制
图中是原作的三个子 Agent。跟做时可按下面的文件分工安排任务:
- 3D Desk & Props Architect(道具与场景架构师):负责通过 Blender MCP 编写 Python 脚本,自动化建模显示器底座、键盘与鼠标的低多边形网格,并导出为
public/models/desk-props.glb。 - Nano Banana Texture & Logo Artist(纹理贴图艺术家):负责调用 Nano Banana 生成无缝木纹、沥青及赛道减速带贴图,为 Three.js 提供材质贴图。
- Atmosphere & HUD Engineer(氛围打光与界面工程师):负责配置 Three.js 聚光灯、环境点光源、多机位跟随控制器与基础界面。
防冲突的核心规约: 并行不自动消除冲突。把这三项约定写入计划,由总控检查合并结果:
- 共享单位与坐标系:各角色统一采用米(meters)为单位,遵循 Three.js Y 轴向上坐标约定(Blender 建模时统一映射为 Z=0 桌平面),以桌面几何中心为共享世界原点。
- 清晰的文件边界:子 Agent 各自独立维护专属文件(
props.js、textures.js、lights.js),跨模块修改先交给总控协调。 - 总控智能体合并:由主 Agent 统一在
main.js与track.js中引入各模块资产,并执行射线碰撞与立柱对齐,确保所有部件无缝拼合。
模板 3:项目规划与架构启动
中文可复制版本:
/grill-me 我们将在当前 `desk-racer` 项目中,基于我上传的书桌照片构建一款 3D 网页微缩卡丁车赛车游戏。
请注意:此时请不要编写任何 3D 代码。
请按以下顺序执行:
1. **需求反向盘问**:向我提出关于操控手感(街机 vs 模拟)、光影氛围与桌面道具处理方式的关键澄清问题。
2. **概念图确认**:优先使用我已选中的 Nano Banana 概念图;如尚未确定,则生成赛道走线与关键道具的候选图,在对话中供我确认。你的最终 3D 制作目标是尽可能精确还原这组概念图的风格与布局。在得到我的明确确认前,不要进入编码阶段。
3. **制定计划与生成 /goal**:在我确认概念图并回答问题后,编写包含清晰里程碑的完整 `PLAN.md`,并为我提供一条可以直接执行的 `/goal` 指令,用于启动长时间自主构建循环。
若当前环境支持子 Agent,请将场景道具(Props)、材质贴图(Texture)与灯光交互(Lighting)拆分为并行子角色;若不支持则按阶段顺序执行。
核心交付标准:
- 模块化架构:Three.js + Vite,拆分 `main.js`、`track.js`、`car.js`、`lights.js` 与 `props.js`。
- 控制与机位:W/A/S/D 驾驶操作,数字键 1~4 平滑切换机位。
- 资产与碰撞:通过 Blender MCP 导出 `public/models/desk-props.glb` 并在网页中加载,带状高架赛道具备防止穿模掉落的碰撞体与接地支柱。
English Copyable Version (Teaching Adaptation):
/grill-me Help me plan a miniature browser kart racer based on my desk photos in the `desk-racer` workspace. Hold off on generating 3D code until we agree on the design.
1. Ask about driving feel, camera modes, lighting, and which objects need custom models.
2. Use the Nano Banana concept I have already selected. If none is selected, produce track and prop concepts and show them in chat. Wait for my choice before coding.
3. After I answer the questions and confirm a concept, save a milestone-based plan as `PLAN.md` and propose an executable `/goal` instruction for completing it.
Delegate props, textures, and lighting where subagents are supported; otherwise work through these milestones in sequence.
Deliver a Vite + Three.js project organized into `main.js`, `track.js`, `car.js`, `lights.js`, and `props.js`. Include WASD driving, four smooth camera modes, Blender props exported to `public/models/desk-props.glb`, and an elevated ribbon track with grounded supports and collision boundaries.
第四阶段:先让车跑起来,再加入桌面和高架赛道
按已确认的计划,先做能驾驶的简模,再加载桌面道具,最后检查高架赛道和碰撞。
1. 创建第一个可玩的原型
用 Antigravity 打开刚创建的 desk-racer 文件夹,确认工作区根目录与终端所在目录一致。在新对话的模型选择器中选择自己账户可用的 Gemini 4 Argon。下面的首个原型只用基础几何体,后续再替换为照片里的真实布局。
在首次运行 npx vite 之前,请先使用以下提示词让 Agent 自动编写完整的首个可玩原型。道路设计必须是有实际宽度的平整带状道路,而不是无法平稳落车的圆环管道。
模板 4:建立首个可玩版本代码(启动前执行)
中文可复制版本:
请在当前 `desk-racer` 前端项目中创建首个完整的可玩原型代码。请直接生成以下文件:
1. `index.html`:标准 HTML5 页面,设置全屏无边距样式,引入 `#app` 容器,引入 `/src/main.js` 作为 ES 模块。
2. `src/main.js`:Three.js 主入口。初始化场景、透视摄像机(FOV 60,near 0.02,far 50)、WebGLRenderer(开启阴影与抗锯齿),窗口 resize 动态适配监听。
3. `src/car.js`:白模赛车类。用简单长方体组装赛车车身(红底白顶,尺寸约 0.05m × 0.025m × 0.02m)。实现基于前进速度、角速度与摩擦力阻尼的刚体移动逻辑。监听键盘按键:W 加速、S 刹车与倒车、A/D 左右转向、R 键重置位置与航向。
4. `src/track.js`:基础闭环赛道。生成一条平整的带状赛道网格(Ribbon Mesh,道路宽度 0.08m,厚度 0.005m),环绕桌面中心形成连续闭环曲面,带有简易发车线与红白路缘涂装。
5. `src/camera.js`:摄像机系统。支持 4 组视角平滑跟随切换:按键 1(后方跟车)、按键 2(引擎盖座舱)、按键 3(桌面全景俯瞰)、按键 4(轨道慢速漫游)。
6. `src/lights.js`:基础光源。提供一盏桌面主聚光灯(投射阴影)与一盏暗调环境光。
生成完毕后,请检查代码结构无语法错误,确保无需额外依赖即可直接导入运行。
English Copyable Version (Teaching Adaptation):
Please scaffold the first playable prototype in the current `desk-racer` project by creating the following files:
1. `index.html`: Standard HTML5 boilerplate, reset CSS for fullscreen canvas, `#app` mount container, importing `/src/main.js` as an ES module.
2. `src/main.js`: Main Three.js entry point. Set up scene, perspective camera (FOV 60, near 0.02, far 50), WebGLRenderer with shadows and antialiasing enabled, and a responsive resize handler.
3. `src/car.js`: Whitebox vehicle class. Construct a modular box car (red body, white roof, ~0.05m × 0.025m × 0.02m). Implement basic arcade physics with acceleration, steering yaw, braking, and damping. Bind key inputs: W (throttle), S (brake/reverse), A/D (steer), R (reset position and rotation).
4. `src/track.js`: Basic closed ribbon track. Build a flat drivable ribbon road mesh (width 0.08m, thickness 0.005m) forming a continuous loop around the desk center, complete with a checkered start line and red/white curb striping.
5. `src/camera.js`: Multi-camera rig. Implement smooth lerped switching across 4 modes: Key 1 (Chase Cam), Key 2 (Hood/Cockpit Cam), Key 3 (Top-down Overview), Key 4 (Orbiting Drone).
6. `src/lights.js`: Initial lighting. Add a shadow-casting spotlight and dim ambient light.
Verify clean module exports and syntax correctness so the project runs immediately upon server start.
文件创建完成后,在终端启动本地开发服务器:
npx vite --host 127.0.0.1
终端会输出类似 http://127.0.0.1:5173/ 的本地地址(若 5173 端口被占用会自动递增)。请在浏览器中打开该地址,确认能看到红白赛车停在带状轨道上,按下 W/A/S/D 可以顺畅驾驶移动,按数字键 1~4 可以平滑切换机位。请保持该终端常驻运行。
模板 5:初次启动空白或报错时的排错追问(备用)
中文可复制版本:
启动 `npx vite` 后,浏览器打开控制台出现了运行异常(如页面白屏、未找到 `#app`、Three.js 模块导入错误或着色器报错)。
请按以下步骤检查并修正代码:
1. 确认 `index.html` 中是否正确包含了 `<div id="app"></div>` 与 `<script type="module" src="/src/main.js"></script>`。
2. 检查 `src/main.js` 与各子模块的 `import` 路径是否正确使用了相对路径 `./car.js`、`./track.js` 等。
3. 检查渲染循环 `requestAnimationFrame` 中是否正确更新了车辆位置与摄像机插值变换。
4. 给出排查结论并直接提供修改后的文件内容。
English Copyable Version (Teaching Adaptation):
Upon running `npx vite`, the browser console reports an error (blank screen, missing `#app` container, module resolution failure, or WebGL context error).
Please inspect and patch the codebase according to these checkpoints:
1. Verify `index.html` contains `<div id="app"></div>` and `<script type="module" src="/src/main.js"></script>`.
2. Ensure all module imports in `src/main.js` use proper relative specifiers (e.g., `./car.js`, `./track.js`).
3. Ensure the `requestAnimationFrame` render loop actively updates car kinematics and camera lerp transformations each frame.
4. State the root cause and provide patched code files directly.
2. 调度 Blender MCP 构建独立桌面道具
当白模赛车能在屏幕上受控移动后,向智能体发出指令,让其通过 execute_blender_code 驱动 Blender 自动化生成道具模型。
在编写建模脚本时,切勿将所有物体“全部居中对齐原点”,否则显示器底座、键盘和鼠标会重叠挤压在一起。必须按照参考照片与桌面实际测量尺寸,建立各物体的独立世界坐标。
模板 6:通过 Blender MCP 自动化构建具有独立坐标的桌面道具
中文可复制版本:
请调用本地 Blender MCP 服务的 `execute_blender_code` 工具,执行 Python 脚本为我的赛车游戏生成一套低多边形(Low-Poly)桌面障碍道具:
1. **物体位置与尺寸规划(以米为单位,示例数据可根据实测替换)**:
- **机械键盘(Keyboard)**:位置 `(0, 0.01, 0.12)`,基座尺寸约 0.36m × 0.14m × 0.02m,表面排列简化的键帽阵列,赋予深灰哑光材质。
- **显示器底座与支架(Monitor)**:位置 `(0, 0, -0.22)`,扁平底座配垂直支架,上方悬挂屏幕面板(0.55m × 0.32m),屏幕表面赋予深色反光材质。
- **鼠标(Mouse)**:位置 `(0.24, 0.015, 0.12)`,流线型圆角网格,长约 0.11m、宽 0.06m。
2. **组织与坐标规范**:保持各物体独立名称(`Keyboard`、`Monitor`、`Mouse`),不合并为单个重叠几何体。上面的示例位置采用 Three.js 的 Y 轴向上坐标;写 Blender 脚本时,将 (x,y,z) 映射为 (x,-z,y),以 Blender Z=0 对应桌面。
3. **导出要求**:使用当前项目工程的绝对输出路径,将上述模型组合以二进制 GLB 格式导出至当前项目的 `public/models/desk-props.glb` 文件中。
4. **完成检查**:脚本执行后,请检查导出文件在磁盘上是否存在且大小大于 0 字节,并汇报各个物体的最终世界坐标。
English Copyable Version (Teaching Adaptation):
Please invoke `execute_blender_code` via local Blender MCP to generate low-poly desktop props with independent world coordinates using Python:
1. **Layout & Dimensions (meters, adjustable defaults)**:
- **Keyboard**: Center `(0, 0.01, 0.12)`, base ~0.36m × 0.14m × 0.02m with simplified keycap array, matte dark plastic material.
- **Monitor**: Center `(0, 0, -0.22)`, thin rectangular base, upright riser, widescreen bezel (0.55m × 0.32m) with glossy dark glass material.
- **Mouse**: Center `(0.24, 0.015, 0.12)`, ergonomic low-poly contour (~0.11m × 0.06m).
2. **Scene Hierarchy**: Keep distinct object names (`Keyboard`, `Monitor`, `Mouse`) without collapsing all meshes onto origin. The listed coordinates use Three.js Y-up; map (x,y,z) to Blender (x,-z,y), with Blender Z=0 as the tabletop.
3. **Export Specification**: Use the project's absolute filesystem path to export the props collection as binary GLB directly to `public/models/desk-props.glb`.
4. **Verification**: Confirm file existence on disk, verify file size is greater than 0 bytes, and output the final object transform coordinates.
3. 在 Three.js 中通过 GLTFLoader 加载资产
在 Vite 环境下,public 目录下的静态资源在构建后映射到根目录,因此在 JavaScript 代码中加载路径应写为 /models/desk-props.glb,不应带有 /public 前缀。
同时需要注意坐标系的映射:Blender 导出 glTF/GLB 时通常把 Z 轴向上的场景转换成 glTF 的 Y 轴向上约定;Three.js 的 GLTFLoader 按这套约定加载。加载后无需手工对顶层模型强行追加 props.rotation.x = -Math.PI / 2 等额外旋转,否则会导致双重旋转错误。
在 src/props.js 中编写加载函数,并在 src/main.js 中调用:
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
export function loadDeskProps(scene, onLoaded) {
const loader = new GLTFLoader();
loader.load(
'/models/desk-props.glb',
(gltf) => {
const props = gltf.scene;
props.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
// 若有材质,适当微调粗糙度
const materials = Array.isArray(child.material) ? child.material : [child.material];
materials.forEach((material) => {
if (material && typeof material.roughness === 'number') {
material.roughness = Math.max(material.roughness, 0.4);
}
});
}
});
scene.add(props);
console.log('桌面道具加载成功,包含物体数量:', props.children.length);
if (onLoaded) onLoaded(props);
},
undefined,
(error) => {
console.error('加载桌面模型失败,请检查 public/models/desk-props.glb 是否存在:', error);
}
);
}
在 src/main.js 的 scene 创建后接入加载函数。把依赖道具位置的赛道更新放进回调,避免模型还没加载完就检测支柱落点:
import { loadDeskProps } from './props.js';
loadDeskProps(scene, (props) => {
console.log('道具就绪,现在可以按其实际边界检查赛道与支柱', props);
// 在这里调用项目中已实现的赛道布局/支柱更新函数
});
4. 闭环带状赛道构建与碰撞检测
赛道如果直接平贴在桌面上,不仅视觉上容易与桌面纹理发生共面闪烁(Z-fighting,即两个几何表面在深度缓冲区中因距离过近发生渲染争夺),也无法越过键盘和电线等障碍。
构建高质量立体赛道的要点:
- 平整带状道路(Ribbon Road):使用
CatmullRomCurve3构造三维样条中心线,沿曲线各点的左右横向方向延展生成具有实际宽度的平面网格,附带红白路缘石与边界轻度凸起。 - 高低交叠与立交跨越:根据实际道具高度动态调整控制点高度。例如在穿过显示器底座上方时下潜至接近桌面,而在跨越机械键盘上方时平滑抬高至合适高度。
- 支柱落地检测(Raycasting / Geometry Query):原作者 Geneviève 在实验中曾生成 68 根垂直支柱来支撑高架赛道。在实际跟做时,支柱数量应根据曲线长度动态决定,每根支柱在生成时通过从轨道底部向下发射射线检测实际落点,确保支柱精准落在桌面或显示器底座表面,不会悬空或穿透物体。
- 分段物理碰撞与防穿模:对于高架上下重叠的立体交叉路段,不能仅根据二维平面坐标判断是否在道路上,必须结合赛道段 ID(Segment ID)与局部高度容差进行最近点距离判定。超出护栏边界时施加反弹冲量;按下
R键时,赛车瞬间重置到距离当前位置最近的有效赛道中心线上。
模板 7:闭环带状赛道生成与多层物理碰撞
中文可复制版本:
请在 `src/track.js` 中构建一套环绕桌面物体的闭环带状高架赛道系统:
1. **几何形状**:基于三维样条曲线(`CatmullRomCurve3`)生成闭环带状网格(宽 0.08m,厚 0.004m)。控制点走线避开键盘中心高耸区域,在键盘边缘抬升并从显示器前掠过。
2. **表面重叠防闪烁**:赛道整体最低处抬离桌面至少 0.003m,避免与桌面共面产生 Z-fighting 闪烁。
3. **支撑立柱**:沿高架赛道下沿均匀生成圆柱形支撑柱。每根支柱通过垂直向下射线检测(Raycaster)获取桌面上方实际落点,使支柱牢固连接轨道与桌面表面。
4. **规则与计时**:在赛道上设置起点线(Checkered Finish Line),实现 3 圈计时逻辑、当前圈速与最佳圈速显示、反向逆行警告与归位重置功能。
5. **分层碰撞**:在立体交叉路段,根据车辆当前高度匹配对应层级的赛道碰撞代理,防止赛车从上层立交桥意外吸附或坠落至下层路面。
编写完成后,请在浏览器中驾驶一圈,确认赛车能平稳通过所有弯道与高架桥。
English Copyable Version (Teaching Adaptation):
Please develop an elevated closed ribbon track in `src/track.js` that navigates around desktop obstacles:
1. **Geometry**: Build a closed ribbon road mesh (width 0.08m, thickness 0.004m) driven by a 3D CatmullRom spline. Route control points to elevate over keyboard edges and dip gently near the monitor base.
2. **Coplanar Anti-Z-Fighting**: Offset track elevation at least 0.003m above tabletop surfaces to prevent depth-buffer fighting artifacts.
3. **Support Pillars**: Distribute vertical cylindrical pillars under elevated spans. Use downward raycasting against desk meshes to clamp each pillar base securely onto supporting surfaces.
4. **Lap Rules**: Add a checkered start/finish threshold, a 3-lap countdown timer, current/best lap tracking, wrong-way detection, and an instant reset trigger (`R` key).
5. **Layered Collision Handling**: Implement height-gated collision matching at overpass intersections so the vehicle does not snap onto underlying road segments.
Drive a complete test lap in the browser to ensure smooth cornering across elevated bridges.
第五阶段:缩小赛车,为什么还要拉近镜头
许多初学者做出的桌面场景,玩起来往往像“一辆玩具车在巨大的平整纸盒上滑冰”,无法呈现视频中宏大的微缩沉浸感。这背后的核心在于真实比例推演与镜头近距离透视。
成品视频 45 秒处,车身贴地飞驰,背景按键化作高耸巨石。
1. 真实比例缩放计算(从 1:87 到 1:150)
作者在早期画面中觉得赛车把道路挤得太窄,便将赛车从 1:87 改为 1:150,同时拉近跟随镜头。这里真正要复用的是相对缩放关系:87/150 约为 0.58,而不是给所有项目指定同一个车长。
正确理解这一比例调整的几何与光学原理:
- 环境物理尺寸固定:书桌、显示器、键盘和赛道的绝对尺寸在 3D 世界中保持不变(例如键盘长 0.36 米,赛道宽 0.08 米)。
- 赛车与自身碰撞体等比缩小:赛车本体及其碰撞包围盒从 1:87 缩放至 1:150 时,缩小为原来的 87/150 ≈ 58%。
- 跟随镜头相对偏移同步缩小:摄像机距离赛车的相对偏移向量(如后方距离与上方高度)同样乘上 58% 的系数。由于摄像机的视野角(FOV)保持不变,赛车在屏幕画面中所占的像素比例基本维持恒定。
- 相对可行驶路面变得更宽:相对于缩小后的赛车,赛道的相对宽度变成了原来的 150/87 ≈ 1.72 倍。道路几何没有改变,车却有了更多相对空间。
- 近裁剪面(camera.near)的调整联动:当镜头贴近微型赛车时,若
camera.near设为 0.1 米,赛车车尾或引擎盖极易被摄像机近平面切掉造成穿模。可从0.01~0.02米试起,按镜头实际距离调整,并观察远景深度精度。
在光学原理中,物体在画面中的张角满足: θ = 2 arctan(S ÷ 2D) 其中 S 为物体物理尺寸,D 为物体到镜头的距离。当摄像机贴近微型赛车时,距离赛车仅有数厘米之遥;而由于镜头位置在空间中随之放低,原本平铺在桌面的键盘按键在低机位俯仰角下迎面扑来,低机位让按键显得高大。最后还要从实际机位检查构图与遮挡。
你可以通过下方交互模拟器调节参数,直观观察镜头距离、物体比例与渲染视野之间的动态联动:
保留左边的 1:87 作为参照,改变右边的比例。先只缩车,再勾选镜头补偿,观察赛车的屏幕占比。图中道路与车辆采用理想透视示意。
车身和镜头偏移都变为原来的 58.0%,赛车屏幕大小保持不变;道路相对赛车宽度变为 1.72 倍。
教学假设:视野角固定、车和镜头同轴,车宽投影与“实体宽度 ÷ 镜头距离”成正比。百分比以调整前为基准;道路图用同深度平面示意,实际游戏还需检查跟随角度、遮挡与碰撞。
模板 8:赛车比例、碰撞体与近裁剪面联动微调
中文可复制版本:
请对 `src/car.js` 与 `src/camera.js` 执行比例优化,将赛车模型比例从 1:87 调整至 1:150 微缩规格:
1. **车体尺寸与碰撞体**:读取当前车体边界,按原尺寸的 87/150 等比缩小一次;碰撞包围盒和车轮离地检测距离同样乘 87/150,记录修改前后尺寸。
2. **跟随镜头偏移**:机位 1 的相对偏移向量和机位 2 的车体局部坐标都乘 87/150;保持 FOV 不变,比较前后截图中的赛车屏幕占比。
3. **裁剪面适配**:在 `src/main.js` 中将摄像机 `camera.near` 设置为 `0.01`,防止特写机位切除赛车网格。
4. **速度参数适配**:微调最大前进速度(约 0.8 m/s)与转向角速度,避免缩小车身后速度显得过快、难以控制。
请通过截屏检查赛车贴近按键时的画面构图与驾驶手感。
English Copyable Version (Teaching Adaptation):
Please refine scale parameters across `src/car.js` and `src/camera.js`, adapting the vehicle from 1:87 down to 1:150 micro scale:
1. **Vehicle & Colliders**: Read the current bounds and multiply vehicle dimensions, collision bounds, and ground-check distances by 87/150 exactly once. Record before/after dimensions.
2. **Camera Offsets**: Multiply the chase-camera offset vector and cockpit local coordinates by 87/150. Keep FOV fixed and compare vehicle screen occupancy before/after.
3. **Near Clipping**: In `src/main.js`, configure `camera.near = 0.01` to prevent clipping artifacts during tight macro shots.
4. **Kinematic Tuning**: Recalibrate top speed (~0.8 m/s) and turn rates to ensure realistic acceleration without visual teleportation at micro scales.
Verify visual framing against keycaps and validate handling responsiveness via test screenshots.
第六阶段:调材质与灯光,用截图检查画面
让 3D 网页场景脱离白模塑料感,核心在于三项相互配合的工作:给模型赋予符合物理规律的 PBR 材质贴图、建立主光与环境补光层次,以及通过截图反馈让独立的视觉批评智能体(Adversarial Critic)排查缺陷并指导修改代码。
制作过程视频 105 秒处,Critic 指出高光过曝、木纹黄橙过饱和和跟车背景过黑,并给出修改建议。
1. 真实材质贴图(Texture Mapping)
单靠单一基础色会让场景显得非常廉价。先生成或准备木纹与路面的无缝颜色贴图,再按需要补粗糙度贴图与法线贴图。PBR 材质用这些不同图像分别描述颜色、表面粗糙程度与微小凹凸;普通颜色图片不能直接代替法线贴图。
在 Antigravity 的图像生成工具中调用 Nano Banana(或在 AI Studio 的图像生成界面上传照片),要求输出“无缝平铺木纹”和“无缝平铺路面颗粒”两张材质图,固定俯视、均匀光照,不带赛道透视和文字。分别保存为 desk_wood.png 与 track_asphalt.png。若 Agent 暂无生图工具,先在图像界面下载文件,再放进工程目录继续。
请注意:贴图文件应存放于 public/textures/ 目录下(如 desk_wood.png、track_asphalt.png)。在 Three.js 中通过 TextureLoader 读取。贴图是赋予 3D 网格微观凹凸反光质感的手段,不应将 2D 平面图片误当作立体几何使用。
模板 9:PBR 纹理贴图加载与材质赋予
中文可复制版本:
请在 `src/textures.js` 中创建纹理加载模块,并为游戏对象分配真实的 PBR 材质:
1. **贴图路径**:先从 `/textures/desk_wood.png` 和 `/textures/track_asphalt.png` 加载已保存的无缝颜色贴图,并按颜色图设置 sRGB。粗糙度贴图、法线贴图与金属贴图仅在文件真实存在时加载;没有时先用材质数值,不添加无效路径。
2. **纹理重复与包裹**:为贴图设置 `wrapS = wrapT = THREE.RepeatWrapping`,针对长条赛道适当设置重复采样频率(如沿走向重复 40 次),防止贴图被严重拉伸变形。
3. **材质参数**:
- 桌面:`MeshStandardMaterial`,赋予深棕木色,粗糙度 0.65,微弱镜面反射。
- 赛道:深灰沥青质感,粗糙度 0.8;若已有正确法线贴图,再加入颗粒细节。
- 赛车:高光红色烤漆,粗糙度 0.25,金属度 0.4。
导出 `applyMaterials(scene)` 函数并在 `src/main.js` 中调用。
English Copyable Version (Teaching Adaptation):
Please implement a texture loading module in `src/textures.js` to assign PBR materials across scene meshes:
1. **Asset Paths**: Load the saved color textures `/textures/desk_wood.png` and `/textures/track_asphalt.png` with sRGB color space. Load roughness, normal, or metal maps only when their files exist; otherwise use material values and avoid missing URLs.
2. **Wrapping & Repeat**: Configure `wrapS = wrapT = THREE.RepeatWrapping`. Adjust UV repetition along the elongated track mesh (e.g., repeat 40 times longitudinally) to eliminate pixel stretching.
3. **Material Tuning**:
- Tabletop: `MeshStandardMaterial`, warm walnut tint, roughness: 0.65, subtle specular sheen.
- Track: Charcoal asphalt, roughness: 0.8; add normal detail only when a valid map is available.
- Go-kart: Glossy racing red coat, roughness: 0.25, metalness: 0.4.
Export `applyMaterials(scene)` and hook it into `src/main.js`.
2. 三层复合氛围光源、交互控制面板与里程碑画廊
参考原演示的暖台灯、紫色环境与青色键盘,可以在自己的项目里从三组灯光开始调:
- 主光源(Key Light):模拟桌面台灯的暖黄色聚光灯(
SpotLight,色温约 3200K),斜向下照射桌面核心区域,开启阴影投射。 - 显示器背光(Rim / Ambient Light):在显示器后方放置一盏深紫色或冷青色的点光源(
PointLight),勾勒屏幕外轮廓并照亮暗部墙面,拉开景深。 - 电竞发光装饰(Accent Light):在机械键盘键帽间隙设置微弱的发光材质或面光源(Emissive Glow),营造微型玩具赛场的科技感。
为了辅助开发者把握画面演进,官方指南推荐了两套轻量级辅助工具:
- 截图画廊:每个里程碑保存一组带版本的截图。让 Agent 把
progress.html放在项目根目录,图片放在public/progress/;开发服务器运行时,用相同地址和端口打开/progress.html查看变化。 - 实时参数调试面板与真实 JSON 导出:在页面中嵌入带有滑块的轻量控制面板,实时调整光照强度、阴影偏置与粗糙度。选定满意数值后,通过“复制 JSON 配置”按钮将参数直接复制到系统剪贴板,由 Agent 回写固化到
src/lights.js中,并在录屏前隐藏或移除控制面板。
模板 10:光源配置、交互式调试控制面板与进度画廊
中文可复制版本:
请在 `src/lights.js` 中完善三层复合光源系统,并在页面中添加调试控制面板与进度记录画廊:
1. **光源组织**:
- 主台灯:`THREE.SpotLight`(暖黄色 `#fff4e0`,强度 2.5,投射阴影,设置合理 shadow.camera 范围)。
- 显示器环境光:`THREE.PointLight`(深紫色 `#6b21a8`,强度 1.2,置于显示器背面)。
- 键盘缝隙氛围:低强度点光源或自发光材质(青色 `#06b6d4`)。
2. **进度画廊(`progress.html`)**:每个开发里程碑完成后,自动捕获 4 张关键截图(全景、细节特写、贴地低视角、线框图),保存至 `public/progress/` 并在 `progress.html` 中以时间线展示,明确标注版本号与生成时间。
3. **交互调试面板与真实剪贴板复制**:在页面右上角添加轻量级控制面板(主灯强度、聚光角度、阴影 bias、色温、曝光度)。面板底部提供「复制 JSON 配置」按钮,点击时调用 `navigator.clipboard.writeText(JSON.stringify(config, null, 2))` 将当前参数真正复制到剪贴板(而非仅仅控制台打印)。
4. **配置固化**:提供明确的使用流程:当我把调优后的 JSON 粘贴回对话时,直接将其更新为 `src/lights.js` 中的默认参数,并在成片录制前提供隐藏或移除面板的开关。
English Copyable Version (Teaching Adaptation):
Please build a composite three-tier lighting setup, an interactive debug GUI, and a progress gallery in `src/lights.js`:
1. **Hierarchy**:
- Desk Spotlight: `THREE.SpotLight` (warm tone `#fff4e0`, intensity: 2.5, castShadow: true, properly bounded shadow camera frustum).
- Monitor Rim Light: `THREE.PointLight` (deep violet `#6b21a8`, intensity: 1.2, placed behind monitor panel).
- Keyboard Glow: Cyan accent point light (`#06b6d4`) or material emissive highlights.
2. **Progress Gallery (`progress.html`)**: After each milestone, capture 4 viewport screenshots (overview, detail close-up, low-angle ground check, wireframe view) into `public/progress/` and index them in `progress.html` with version numbers and timestamps.
3. **Interactive GUI & Real Clipboard Copy**: Embed lightweight on-screen sliders for spot intensity, penumbra, shadow bias, exposure, and color. Add a "Copy Settings as JSON" button that invokes `navigator.clipboard.writeText(JSON.stringify(config, null, 2))` to truly copy active settings to the system clipboard (not just console.log).
4. **Bake Defaults**: Establish a clear workflow: once I paste back the exported JSON, bake those values into `src/lights.js` as permanent defaults, and provide a toggle to hide or remove the debug GUI before final recording.
3. 独立“对抗性视觉批评家”(Adversarial Critic)自查循环
让另一个 Critic 子 Agent 看实际运行截图,再把问题交回编写代码的 Agent 修改。它与人一起检查四种画面:
- 全景:构图、赛道走向和遮挡。
- 特写:木纹、路面、高光和贴图拉伸。
- 低机位:车轮与支柱是否接地。
- 线框图:网格结构与穿插;碰撞还要靠驾驶和几何检测确认。
原指南用“列出至少 3 项缺陷、达到 9/10”推动早期迭代。实际跟做时,让 Critic 报告真实问题和对应文件,修复后重新截图;画面达到你确认的风格,且能跑圈、切换机位、加载资产,才结束本轮。在 AI Studio Build 中,也可把这些截图直接发到对话里,请 Gemini 批评并修改。
官方 Adversarial Critic 评审流程示例(点击展开)
模板 11:独立 Critic 子智能体多机位审查与代码修复
中文可复制版本:
请启动一轮独立的对抗性艺术总监批评家(Adversarial Visual Critic)子智能体评审流程:
1. **渲染 4 组检查截图**:
- 3/4 俯视全景:展示整体空间构图与赛道走向。
- 局部特写:检查键盘键帽与沥青表面纹理。
- 贴地低机位:检查赛车与支柱接地情况,确保无悬空漂浮。
- 几何线框图:检查 3D 拓扑结构与潜在穿模点。
2. **严苛挑刺清单**:请批评家子 Agent 审查全部 4 张截图,列出实际发现的具体视觉缺陷(如高光泛白过曝、阴影边缘锯齿断裂、模型浮空或材质平淡),并给出修改意见。
3. **定位修复与停止依据**:
- 定位至 `src/lights.js`、`src/textures.js` 或 `src/track.js` 执行代码修改。
- 重新捕获截图进行复验。未发现问题时不要凑数。画面符合已确认的概念方向,赛车可跑完全程、机位平滑、资源加载无报错后结束本轮。
English Copyable Version (Teaching Adaptation):
Please invoke an independent Adversarial Visual Critic subagent review pass for the current scene:
1. **Render 4 Verification Screenshots**:
- 3/4 Overview: Demonstrating overall layout and track composition.
- Close-up: Inspecting keycap textures and asphalt grain.
- Low Angle: Inspecting vehicle contact and pillar bases to eradicate floating objects.
- Wireframe View: Verifying clean 3D topology and potential collision intersections.
2. **Defect List**: Have the Critic subagent inspect all 4 screenshots, itemizing the visual flaws actually present (e.g., specular blowouts, shadow acne/detachment, floating meshes, or flat materials) with targeted remediation advice.
3. **Targeted Patching & Exit Criteria**:
- Apply fixes directly across `src/lights.js`, `src/textures.js`, or `src/track.js`.
- Re-capture screenshots for verification. Do not invent defects once they are fixed. End the round when the image matches our approved direction and multi-lap driving, camera modes, and asset loading pass.
4. 调光卡住时,先生成同机位目标图
如果反复改参数仍不知道该往哪里走,把当前场景截图交给 Nano Banana,让它生成保持同一机位和物体布局的 2K 目标图。先隐藏按钮、滑块和 HUD(速度、圈数等界面文字),避免它把界面文字画成场景中的标牌。
再把当前截图与目标图一起交给 Argon,比较阴影、木纹、反光和暗部,修改真实的 3D 几何、材质与灯光。目标图负责指明方向;转动镜头、驾驶赛车后,改进仍应成立。
模板 12:生成同机位目标图(先做)
中文可复制版本:
隐藏 UI 按钮、调试滑块与 HUD,在当前项目的 3~5 个关键机位各保存一张清晰的 3D 截图,注明机位和版本。
将每张截图交给 Nano Banana 生成 2K 目标图:提升自然光照、桌面木纹、路面质感、反光与空间层次,保持原始相机视角、构图和物体布局。
按机位保存原截图与目标图,并把实际文件路径和预览发给我。若布局发生变化,重新生成后再进入代码修改。
English Copyable Version (Teaching Adaptation):
Switch off the interface buttons, debug GUI, and HUD. Save clear screenshots from 3–5 useful camera positions, labeling the camera and revision.
For each view, ask Nano Banana for a 2K reference image with improved lighting, desk grain, road texture, reflections, and depth. Preserve the camera framing and object arrangement.
Save each source/reference pair and show me previews with their actual paths. Regenerate references that alter the layout before changing the game code.
模板 13:对照目标图修改 3D 代码(确认目标后执行)
中文可复制版本:
对照同机位的当前 Three.js 截图与已确认的 Nano Banana 2K 目标图,列出阴影、桌面木纹、车身反光和背景暗部的具体差异。
根据差异修改现有项目的几何体、材质和灯光,定位 src/lights.js、src/textures.js、src/main.js 或实际使用的模型文件。
不要把目标图贴成平面背景。完成后在原机位重新截图,并旋转镜头、驾驶一圈,确认效果在实时 3D 中成立。将改动和前后画面发给我。
English Copyable Version (Teaching Adaptation):
Use matching camera views to compare our live Three.js captures with the approved Nano Banana 2K references. Identify differences in shadows, wood grain, kart reflections, and the darker background.
Update the existing geometry, materials, and lights in src/lights.js, src/textures.js, src/main.js, or the model files actually used by this project.
Keep the reference image out of the scene background. Capture the original views again, rotate the camera, and drive a lap to confirm the improvement survives in real-time 3D. Show the edits and before/after captures.
第七阶段:测帧率,再决定房间做多细
当赛车在书桌上顺畅滑行时,很多开发者会产生一个想法:“我能不能顺便把整间书房的窗户、书架、沙发全做进 3D 场景里?”
在 3D 实时渲染中,应当避免在玩家视线外的非核心区域堆砌高面数几何体。优化前应先检测当前的性能瓶颈(帧时间、DrawCalls 绘制调用次数、阴影 Pass 与贴图显存),再根据瓶颈类型做针对性优化。在普通电脑上,可先以 30fps 作为可玩的平稳基准,测量瓶颈后再针对性调优争取更高帧率。
优化策略核心:
- 核心区域保留细节:赛车和闭环赛道所在的核心桌面区域(直径 1.2 米内)保留 PBR 材质与主灯动态阴影。
- 背景远景暗调压制:房间四周的墙壁、书架仅用极简扁平几何体搭建轮廓,完全关闭投射与接收阴影,让主光源的自然衰减掩映在黑暗中,避免产生额外的阴影计算开销。
- 合并静态网格(DrawCall 优化):键盘的上百个按键若每个都是独立 Mesh,会导致每帧产生上百次绘制调用。应在 Blender 建模阶段或 Three.js 初始化阶段,使用
InstancedMesh或将按键合并(BufferGeometryUtils.mergeGeometries)为单个网格。 - 单一道具面数控制:单个桌面小道具控制在 500~2000 个面以内,整张桌面的总面数建议控制在 5 万面以下。控制面数需配合阴影通道与纹理分辨率综合测试。
模板 14:性能指标测量与瓶颈针对性优化
中文可复制版本:
请对当前 `desk-racer` 前端渲染性能执行指标测量与针对性优化:
1. **指标检测**:在页面中引入轻量性能监控器,实时显示当前 FPS、每帧时间 ms 与 `renderer.info.render.calls`(绘制调用次数)。
2. **排查瓶颈与光源减负**:测量主要开销属于 CPU 绘制调用瓶颈还是 GPU 填充率/阴影瓶颈。确保场景中仅保留 1 盏主聚光灯开启 `castShadow = true`,禁用显示器环境光的额外阴影通道。
3. **静态网格合并**:检查机械键盘模型。如果键帽由大量单独网格构成,请将其合并或转换为 `InstancedMesh`,对比合并前后的 DrawCalls 测量数值。
4. **运行验收**:在浏览器中连续跑圈测试,以 30fps 作为平稳运行的体验基准(在独立显卡上向 60fps 调优),消除急转弯与视角切换时的掉帧卡顿。
English Copyable Version (Teaching Adaptation):
Please profile rendering performance for `desk-racer` and apply targeted optimizations:
1. **Telemetry**: Add a lightweight stats overlay tracking FPS, frame delta (ms), and `renderer.info.render.calls` (DrawCalls).
2. **Bottleneck Audit & Shadow Pruning**: Determine whether performance is bounded by CPU DrawCalls or GPU fill-rate/shadow passes. Ensure strictly ONE primary spotlight casts dynamic shadows; disable shadow casting on auxiliary monitor fill lights.
3. **Mesh Merging**: Inspect keyboard keycaps. If composed of dozens of individual meshes, batch them via `BufferGeometryUtils.mergeGeometries` or `InstancedMesh`, comparing DrawCall measurements before and after.
4. **Acceptance Test**: Run a continuous multi-lap driving benchmark to verify smooth performance above the 30fps baseline (targeting 60fps on capable GPUs) without stutter during high-speed cornering.
第八阶段:切换机位,录成演示视频
精彩的演示视频不需要复杂的后期特效,关键在于机位节奏与视角的交替调度。
成品演示视频 0 秒处,显示器、台灯与发光键盘共同构成桌面赛车场。
1. 游戏中必须实现的 4 组机位控制
在代码中通过数字键监听,让摄像机在不同的挂载节点间平滑过渡:
- 机位 1(后跟车视角 / Chase Cam):摄像机平滑插值(Lerp)跟随在赛车正后方上方,体验高速过弯与路缘震颤。
- 机位 2(微距贴地座舱 / Cockpit Cam):将摄像机固定在赛车前端车顶,迎面扑来巨大的键盘按键与台灯立柱,产生微缩世界的反差冲击。
- 机位 3(桌面宏观俯瞰 / Tabletop View):固定在高处俯视整张桌面,展示盘旋高架赛道的整体走向与桌面空间布局。
- 机位 4(环绕漫游无人机 / Drone Cam):缓慢沿大半径圆周旋转,展现三维光影与错落的高架结构。
进阶提示(原作完整控制体系):原作面板还有 1~9 号机位与快捷键:
Enter开始计时、WASD驾驶、Space手刹漂移、Shift加速、R赛车复位、ESC呼出设置、M开关引擎声,以及按P键开启沿轨道自动巡航。读者在首次跟做时,模板仅实现基础的 1~4 号机位与核心驾驶逻辑即可,无需强求首版就包含自动巡航等进阶功能。
模板 15:平滑多机位切换控制器
中文可复制版本:
请在 `src/camera.js` 中实现平滑的摄像机控制器,支持按键 1、2、3、4 在不同视角间平滑插值过渡(使用 Vector3.lerp 与 Quaternion.slerp):
1. **键 1 - 跟车视角**:目标位置位于赛车后方 0.08m、上方 0.035m,注视点朝向赛车前方 0.05m 处。
2. **键 2 - 座舱第一人称**:目标位置固定在赛车前罩上方 0.008m,注视正前方。
3. **键 3 - 桌面全景俯瞰**:固定在桌面中心上方 0.8m、斜侧 0.5m 处,静态俯视整张书桌。
4. **键 4 - 无人机环绕**:以桌面中心为圆心,按 0.15 rad/s 的角速度缓慢自转巡航。
确保切换视角时画面不会产生瞬间生硬瞬移,过渡平滑度在 0.6~0.8 秒左右完成。
English Copyable Version (Teaching Adaptation):
Implement a smooth camera controller in `src/camera.js` supporting keys 1, 2, 3, 4 with lerped transitions (Vector3.lerp and Quaternion.slerp):
1. **Key 1 - Chase Cam**: Offset 0.08m behind, 0.035m above the vehicle, looking 0.05m ahead.
2. **Key 2 - Cockpit View**: Mounted directly 0.008m above vehicle hood, looking straight forward.
3. **Key 3 - Overview**: Stationary vantage point 0.8m above and 0.5m offset from desk center, overlooking the track.
4. **Key 4 - Orbit Drone**: Slow orbit around desk center at 0.15 rad/s.
Smooth transitions across states within ~0.6–0.8s without sudden position snaps.
2. 本地生产构建验证(无需公网发布即可录屏)
在开始录屏前,建议先测试生产环境打包构建,确保资产路径无误且脱离开发服务器也能稳定运行:
# 1. 编译生产代码至 dist/ 目录
npx vite build
# 2. 预览生产版本
npx vite preview --host 127.0.0.1
在浏览器中打开预览地址(通常为 http://127.0.0.1:4173/),进行完整的试驾测试。逐一检查模型、贴图和驾驶行为,确认生产构建中的路径与运行结果,无需配置公网域名或部署服务器,即可在本地直接完成录屏。
3. OBS 录屏手把手配置指南
可用开源的 OBS Studio:
- 隐藏调试控件:在正式录制前,按演示需求将页面上的调试滑块面板与 HUD 文本隐藏(可设置快捷键如
H或ESC切换显示),保持画面干净纯粹。 - 添加画面捕获来源:
- 打开 OBS,在底部「来源」面板点击
+号。 - 选择 窗口采集(Window Capture),在下拉菜单中直接选中你正在运行赛车游戏的浏览器窗口;如果捕获出现黑屏,可改选 显示器采集(Display Capture) 并截取对应屏幕。
- 打开 OBS,在底部「来源」面板点击
- 画布与帧率配置:
- 打开 OBS 设置 → 视频 选项卡。
- 将「基础(画布)分辨率」与「输出(缩放)分辨率」统一设置为
1920×1080。 - 「常用 FPS 值」建议先设置为 30;如果你的电脑显卡运行充裕且录制不产生掉帧,再提升至 60。
- 音频来源与电平检查:
- 原作还接入了 Gemini Omni Flash 生成的赛车引擎音。Google 发布博客
- 在「音频混音器」中确认有声音输入。若录制网页背景音乐与赛车引擎音效,添加「应用程序音频采集」或「桌面音频」。
- 观察绿色电平跳动,避免红色爆音破音。
- 重要提示:macOS 原生的
Shift + Command + 5工具可在“选项”中选择麦克风,不能把这个选项当作系统声音输入。若需录制游戏内部声音,可在 OBS 中按当前系统版本添加系统/应用音频来源并查看电平。
- 10 秒试录排查:
- 点击「开始录制」,在浏览器中驾驶赛车并切换机位,录制 10 秒后点击「停止录制」。
- 打开录像保存目录,播放检查:画面有无黑屏、有无卡顿掉帧、音画是否同步。
- 录制格式与转码(Remux):
- 在 OBS 设置 → 输出 中,将录像格式设置为
MKV(防止电脑突然死机导致整个视频损坏)。 - 录制完成后,点击 OBS 顶部菜单栏 文件 → 录像重封装(Remux Recordings),选择录好的 MKV 文件,即可重封装为各大剪辑软件直接识别的通用
MP4格式。
- 在 OBS 设置 → 输出 中,将录像格式设置为
4. 60~80 秒成片剪辑镜头表建议
以下是本文根据游戏特性推荐的分镜头剪辑节奏:
- 0~10s(全景开场):机位 3(桌面全景俯瞰)。静态展示停在发光键盘旁的微缩赛车与整张桌面的深邃光影,浮现游戏标题。
- 10~35s(加速飞驰):机位 1(后跟车视角)。起步加速,连续漂移绕过鼠标垫,展示赛车冲上高架桥越过键盘的连续动态。
- 35~55s(微距特写):机位 2(贴地座舱视角)。镜头几乎贴着机械键盘键帽与显示器立柱飞掠而过,强化微缩尺度的速度冲击感。
- 55~75s(冲线定格):赛车冲过终点线触发三圈计时完成提示(若游戏中实现了结算界面可弹出,未实现则以冲线动作收尾),平滑切入机位 4(无人机漫游)环绕整张书桌定格。
- 导出规范:在剪辑软件(如剪映、DaVinci Resolve 或 Premiere)中导出为 H.264 编码、AAC 音频、1080p 分辨率的 MP4 视频。
避坑指南:常见报错与应对方案
在跟随本指南实战过程中,你可能会遇到以下典型问题:
| 现象与报错 | 核心原因分析 | 正确排查与修正方法 |
|---|---|---|
MCP 连接失败Connection refused / port 9876 |
Blender 中的插件服务未开启,或 Blender 窗口已被关闭。 | 打开 Blender,按 N 呼出侧边栏,检查 MCP for Blender 选项卡,确认显示运行中或点击 Start MCP Server 并保持软件开启。 |
命令行报错spawn uvx ENOENT |
编辑器或 IDE 未能从 GUI 环境读取到系统终端的 PATH 变量。 | 在系统终端运行 which uvx(Windows 运行 where.exe uvx)获取绝对路径,在 mcp_config.json 中用绝对路径替换 uvx。 |
模型加载 404404 Not Found /models/... |
Three.js 读取路径误写了 /public 前缀,或静态文件未放置在 public/models/ 目录下。 |
在 Vite 项目中,将读取路径统一写为 /models/desk-props.glb,确认文件真实存在于项目的 public/models/ 目录且文件体积大于 0。 |
| 画面闪烁(Z-fighting) 赛道或桌面出现斑驳条纹 |
赛道底面与桌面完全共面(深度缓冲区精度不足争夺渲染)。 | 在 src/track.js 中将赛道基底整体抬高 0.003m 以上,或在材质中开启 polygonOffset: true。 |
| 阴影断裂或漂浮(Acne / Peter Panning) | 阴影偏置(shadow.bias)设置不当,过小引起自阴影伪影,过大引起脱节。 | 在调试面板中微调实际投影光源的 light.shadow.bias,检查阴影分辨率和覆盖范围;聚光灯调整角度与 near/far,方向光调整正交范围。 |
| 页面启动黑屏白屏 控制台提示找不到 #app |
index.html 缺少挂载节点,或执行 npx vite 前未生成 src/main.js。 |
使用第四阶段“建立首个可玩版本代码”模板生成 HTML 与 JavaScript 文件,确保模块引用路径正确后再启动开发服务器。 |
| 录屏无游戏内部声音 录制出的视频只有外界噪音 |
使用了 macOS 原生录屏且未配置系统音频采集驱动。 | 改用 OBS Studio,添加「应用程序音频采集」或「桌面音频」,观察混音器电平跳动后再录制。 |
从第一个能跑圈的版本开始
先拍自己的书桌,确认概念图与计划,再做出能完整跑圈的简模。这个版本稳定后,逐项加入道具、贴图和灯光,每次都保存截图与代码版本,最后试录 10 秒再正式录制。
实操带走包
滚动查看原始 Markdown,复制后可按团队实际系统与政策修改。
正在载入 Markdown…
把你的书桌变成3D赛车场:从照片、建模到录屏的手把手教程
Google 开发者关系工程师 Geneviève Huskens 把自己的键盘、显示器和摆件变成了浏览器赛车游戏《Desk Racer》。手工制作要逐件建模,再编写驾驶、碰撞和镜头;这次,她让 AI 把这些工序连起来。
照片提供外观与布局参考。人仍要确认尺寸、玩法和效果,AI 则通过工具执行任务,并根据真实运行画面继续修改。
从照片到游戏,怎样一步步落地?
拍整桌全景与道具特写;用 Nano Banana 生成 2D 概念图,确认赛道走线、配色与微缩感。
用 /grill-me 问清操控、机位与建模方式,整理 PLAN.md;用 /goal 持续推进。先做能跑圈的白模版本。
Gemini 通过 Blender MCP 执行 Python 脚本生成桌面道具;导出 GLB,由 Three.js 加载,接上赛道、驾驶、碰撞与跟车镜头。
补材质和灯光;保存进度画廊。独立 Critic 找出过曝、浮空或穿模,把问题交回 Agent 修改代码并重拍。
检查能跑圈、切机位和加载资产;测帧率,合并重复按键网格、减少投射阴影的灯。先试录 10 秒,核对画面与游戏音效,再录成片。
并行分工,怎样避免互相改坏?
把道具、贴图、灯光交给不同角色。统一单位、原点和坐标轴约定;每个角色负责自己的文件,再由主 Agent 组装检查。教程给出这套协作规约,避免模型接不上、代码互相覆盖。
好画面来自“运行—看图—改代码”
检查全景构图、特写材质、低机位接触面和线框空间关系。调光卡住时,生成同机位目标图作对照,再把效果做回真实 3D 场景。目标图提供方向,不能代替可驾驶的场景。
一个关键技巧:车做小,镜头也拉近
作者将赛车从 1:87 改为 1:150,桌子和赛道尺寸保持不变。跟车镜头一起拉近,画面中的车就不会显得过小。
87 ÷ 150 ≈ 0.58
150 ÷ 87 ≈ 1.72
开始跟做时,先守住这三件事
先让车能跑,再追求漂亮。照片不能保证精确尺寸;测量、建模和截图检查仍要逐步验证。原演示生成过 68 根支柱,实际数量随你的赛道长度决定。
区分原作者做法与教程补充。原作者的无界面 Blender MCP 配置未公开;本文给出需要保持 Blender 打开的社区插件路线。录屏设置也是跟做建议。
工具权限先确认。在线可先试玩或 Remix;自建需配置 Antigravity、模型权限与本地工具。无需一开始就把完整房间做出来。
