Day 112 · BOSS 战 — 3D 车间 2.0:十天资产拧成一件作品
第 16 周收官。今天把 Day 106-111 攒下的全部资产——真实模型、贴图质感、阴影描边、关键帧动画、加载降级——拧成"3D 车间 2.0"。上午组装(全效果整合 + 布局 + 交互),下午验收(功能清单 + 性能 + 降级演练 + 边界定稿)。结束时,你拥有阶段 3 的第二件可展示作品,以及"资产工程"这套能在简历上写、面试里讲的能力。
目录
一、BOSS 战定位:组装不是重写
1.1 今天干什么、不干什么
✅ 今天做:
1. 全效果装配:模型 + 贴图 + 环境 + 阴影 + 描边 + 动画(只接线不重写)
2. 健壮性:加载进度 + 降级回退 + 释放验证(Day 111 直接入库)
3. 边界定稿:boundary-three-vue.md v2(补"资产/加载态"节)
4. 双验收:功能清单 + 性能表,留档进 docs/acceptance/
5. 交付:45 秒演示 + README + 简历条目
❌ 今天不做(记入 Week 17 待办):
粒子系统 / LOD 层级细节 / 自定义着色器 —— Week 17 场景与性能进阶
后处理进阶(辉光/景深/色彩分级)—— Week 17+
WS 实时数据驱动 3D —— 第 6 个月(Week 26+)孪生主线
1.2 复用清单(不许重写)
二、车间 2.0 整体规划(效果清单)
2.1 平面布局(延续 Day 105,新增罐体阵列)
X 轴 →
┌──────────────────────────────────────────┐
│ [泵-01] [泵-02] [冷却塔] [罐体阵列×N] │ ← 上排:真实模型 + 实例化罐体
│ │
│ ┌─────────┐ │
│ │ 地 面 │ 阴影投下 │
│ └─────────┘ │
│ │
│ [风机-01] [风机-02] [主机] │ ← 下排:真实模型
└──────────────────────────────────────────┘
上排真实模型 + 下排真实模型 + 一侧实例化罐体阵列
2.2 效果清单(验收对照)
□ 真实感:GLTF 模型(五步体检后)替代拼装几何
□ 质感:map/normalMap + 环境贴图(金属不再发黑)
□ 氛围:主光阴影(设备踩地)+ OutlinePass(选中描边)
□ 动画:模型自转 / 叶轮转 / 指示灯闪(mixer + clip)
□ 高效:罐体阵列用 InstancedMesh(N 台 = 1 draw call)
□ 健壮:加载进度条 → 失败自动降级几何版 → 卸载零泄漏
三、组装一:全效果装配(Day 106-110 汇总)
引擎的"装配清单"——把十天能力按序接进 scene-engine(Day 111 整合版再扩展):
// src/core/three/scene-engine.ts(Day 112 全效果版:装配清单)
import * as THREE from "three";
import { AssetManager } from "./asset-manager";
import { createAtmosphere } from "./create-atmosphere";
import { createInstancedTanks } from "./create-instanced-devices";
import { attachMixer } from "./animation-mixer"; // Day 110
import { deviceLayout, MODEL_URLS } from "../config/device-layout";
/**
* 3D 车间 2.0 引擎:全效果 + 健壮性(Day 103 契约不变)
* 装配顺序:光照 → 地面 → 环境 → 模型 → 实例化 → 动画 → 氛围 → 交互
*/
export function createSceneEngine(canvas: HTMLCanvasElement) {
// —— 基础(Day 99-100):场景 / 相机 / 渲染器 / 光照 ——
// ...(略,同前)...
// —— 环境贴图(Day 107):金属质感的基础 ——
const pmrem = new THREE.PMREMGenerator(renderer);
scene.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture;
// —— 地面 + 阴影(Day 109)——
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(24, 24),
new THREE.MeshStandardMaterial({ color: 0x16233a, roughness: 0.9 })
);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true; // 接影端
scene.add(floor);
const grid = new THREE.GridHelper(24, 12, 0x00c6ff, 0x16233a);
grid.position.y = 0.01;
scene.add(grid);
// —— 模型资产(Day 108 + Day 111 加载)——
const asset = new AssetManager();
let models: THREE.Object3D[] = [];
let mixers: THREE.AnimationMixer[] = [];
// —— 氛围装配(Day 109:阴影开关 + 描边后处理)——
const atmosphere = createAtmosphere(renderer, scene, camera, canvas);
async function initDevices() {
asset.onProgress = (pct) => emitLoadState({ state: "loading", pct });
asset.onReady = () => startLoop();
asset.onError = () => {
// 降级:几何拼装版(Day 111)——车间不崩
models = buildFallbackWorkshop(deviceLayout);
models.forEach((m) => { scene.add(m); pickables.push(m); });
emitLoadState({ state: "error", pct: 100 });
startLoop();
};
try {
models = await Promise.all(
deviceLayout.map((c) => asset.getModel(MODEL_URLS[c.type]))
);
models.forEach((m, i) => {
m.position.set(...deviceLayout[i].position);
m.userData.deviceId = deviceLayout[i].id;
m.traverse((c) => { if (c instanceof THREE.Mesh) c.castShadow = true; }); // 投影端
scene.add(m); pickables.push(m);
// 模型自带动画(Day 110)
const mixer = attachMixer(m);
if (mixer) mixers.push(mixer);
});
// 实例化罐体阵列(Day 106:1 draw call)
const tanks = createInstancedTanks(scene, TANK_LAYOUT);
pickables.push(tanks); // 实例化也参与拾取(Day 106 第六节)
asset.notifyReadyIfAllDone();
} catch { asset.triggerError(); }
}
// —— 渲染循环(全效果:动画 + 相机 + 后处理)——
const clock = new THREE.Clock();
let rafId = 0;
function startLoop() {
rafId = requestAnimationFrame(function tick() {
const delta = clock.getDelta();
mixers.forEach((m) => m.update(delta)); // 动画(Day 110)
controls.update(); // 相机(Day 104)
atmosphere.composer.render(); // 后处理(Day 109)替代 renderer.render
rafId = requestAnimationFrame(tick);
});
}
return {
bridge: { initDevices, onLoadState(cb) { /* ... */ }, /* resize/setAnimation */ },
events: { on(cb) { /* Day 104 出向桥 */ } },
start() { /* 循环 */ },
dispose() { /* Day 111 全量释放 */ },
};
}
观察装配顺序的依赖关系:环境贴图要先于模型创建(模型材质要采样它)→ 模型要等加载 → 动画要等模型 → 后处理要等场景。顺序即架构——这就是为什么"只接线不重写"比"从头写一遍"更考验理解。
四、组装二:健壮性装配(Day 111)
Day 111 的健壮性直接入库,验收时演练三件事:
① 正常路径:进度条 → 100% → 真实模型车间出现
② 降级路径:改坏模型 URL → 提示"简化模式" → 几何版车间照常交互
③ 释放路径:反复进出页面 30 次 → 显存不涨(Performance/Memory)
这三条是"工程价值"的证明:能正常跑是能力,能降级不崩是职业素养。面试演示时主动展示降级,比被问到才承认强得多。
五、最终验收:功能清单逐项打勾
对照 week16 总览第四节,逐项执行并留档:
□ 功能:真实模型 + 罐体阵列 + 阴影 + 描边高亮 + 动画,可旋转/缩放/点击
□ 质感:环境贴图生效(金属不发黑),纹理清晰——Day 101 对比截图存档
□ 交互:点击设备描边 + 详情面板;hover 反馈;拖拽不误触
□ 动画:设备自转 + 叶轮/指示灯动,帧率变化不影响速度
□ 健壮:断网/加载失败 → 简化模式提示 + 几何版可用
□ 边界:Vue 组件零 Three 依赖;加载态只走 onLoadState;边界文档 v2 定稿
□ 工程:vue-tsc 零报错、资产目录规范、无 CDN
每个勾都留档(截图/录屏/实测表进
docs/acceptance/)——"有证据地通过"是验收与自嗨的区别(Day 70/105 原话)。
六、性能验收与降级演练
性能不够时的排查顺序(本周工具链):draw call(Performance 面板)→ 阴影 mapSize → 贴图尺寸 → 动画 mixer 数量。按此序逐级降,别一上来就砍效果。
七、边界文档定稿(v2)
Day 103 v1 → 今天补"资产/加载态"节,定稿:
# 3D 场景 × Vue 边界决策文档(Day 112 定稿 v2)
## 数据裁决表(Day 103,v2 复核无出入)
## 桥契约(v2 新增加载态)
- SceneBridge 新增 onLoadState(state, pct)——Vue 只消费数字
- AssetManager/模型/贴图全部引擎内部持有,不进 Vue
## 响应式纪律(v2 验证)
- Three 对象普通变量持有;Vue 组件零 Three 依赖(代码扫描确认)
## 反例推演记录(v2 新增)
- "AssetManager 放进 Vue" → 组件里出现 Three 类型,边界破裂
- "资源没等齐就渲染" → 黑屏跳变(Day 111 坑 1)
## 复审触发条件
- 第 6 个月接 WS:updateStates 分频与脏检查
- 设备数 > 500:draw call(实例化/LOD)重审
- 新增模型类型:MODEL_URLS 映射表扩展(与代码解耦)
八、交付资产:演示视频 / README / 简历条目
8.1 45 秒演示脚本
【00:00-00:05】开场:45° 视角车间全景(真实模型 + 阴影 + 环境光)
旁白:"基于 Vue3 + Three.js 的 3D 智慧车间 2.0。"
【00:05-00:15】质感:放大金属罐体 → 转一个角度反光
旁白:"GLTF 真实模型 + PBR 材质:贴图、法线与环境光场。"
【00:15-00:25】动画:叶轮转动 + 指示灯闪烁 + 罐体阵列
旁白:"AnimationMixer 关键帧动画与实例化渲染。"
【00:25-00:35】交互:点击设备 → 描边高亮 + 详情面板
旁白:"OutlinePass 描边选中,Raycaster 拾取联动面板。"
【00:35-00:40】健壮性:Network 断网刷新 → 简化模式提示
旁白:"加载失败自动降级几何版,页面不崩。"
【00:40-00:45】收尾淡出
旁白:"资产工程化:加载、缓存、降级、释放全链路。"
8.2 README 要点
# 3D 智慧车间 2.0 Three.js Workshop v2
一句话:Vue3 + Three.js 的 3D 车间——真实模型、PBR 质感、
阴影描边、关键帧动画、加载降级,引擎与 Vue 边界清晰。

## 快速启动
```bash
npm install
npm run dev
亮点
[x] GLTF 真实模型 + 五步体检(单位/方向/材质兜底)
[x] PBR 材质:贴图 + 法线 + 环境贴图(解决金属发黑)
[x] 阴影 + OutlinePass 描边选中
[x] AnimationMixer 关键帧动画(叶轮/指示灯)
[x] InstancedMesh 罐体阵列(N 台 1 draw call)
[x] 加载进度 + 失败降级 + 零泄漏(边界文档 v2)
### 8.3 简历条目(150 字内)
> **3D 智慧车间**(Vue3 + Three.js,个人项目)
> 构建可交互 3D 工业车间:GLTF 真实模型导入与资产工程化(统一加载管理器、缓存克隆、失败降级);PBR 材质体系(贴图/法线/环境光场);阴影与 OutlinePass 描边高亮;AnimationMixer 关键帧动画;InstancedMesh 实现罐体阵列单次 draw call。设计引擎与 Vue 的边界契约(SceneBridge/SceneEvents),Vue 侧仅持有 id 与加载进度数字,组件零 Three 依赖。全效果稳定 50fps+,断网自动降级不崩溃。
> 简历自检(Day 70/105 纪律):每句都能追问 10 分钟——"资产工程化""失败降级""边界契约"都是你亲手做的,弹药充足。
---
## 九、第 16 周毕业总结与知识图谱
### 9.1 七天上台阶
Day 106 几何进阶 → BufferGeometry 原理 + InstancedMesh(50→1 draw call)
Day 107 材质贴图 → PBR 材质 + 环境贴图(金属不发黑)
Day 108 模型导入 → GLTF/GLB + 五步体检(真实设备进车间)
Day 109 阴影描边 → Shadow + OutlinePass(氛围 + 选中高亮)
Day 110 动画系统 → AnimationMixer(设备动起来)
Day 111 资产集成 → 加载态 + 资源管理 + 降级(健壮性)
Day 112 BOSS 战 → 3D 车间 2.0(全效果 + 双验收 + 交付)
### 9.2 能力对照:Week 15 末 vs Week 16 末
| 能力 | 第 15 周末 | 第 16 周末 |
|------|-----------|-----------|
| 几何 | 内置几何拼装 | BufferGeometry 原理 + 自定义 + 实例化 |
| 材质 | 纯色 Standard | PBR 贴图 + 法线 + 环境光场 |
| 资产 | 无 | GLTF 导入 + 五步体检 + 缓存克隆 |
| 效果 | 三灯照明 | 阴影 + 后处理描边 |
| 动画 | 直接改属性 | AnimationMixer 关键帧 |
| 工程 | 无加载概念 | 加载/进度/降级/释放全链路 |
### 9.3 本周最有价值的三个认知
1. **封装要"知其成本"**(Day 106/108):BoxGeometry 背后是 24 顶点 36 索引,glTF 解析器是几千行——不重写,但要能讲清它替你做了什么。
2. **质感 = 光 + 材质 + 环境**(Day 107/109):环境贴图救金属、阴影让设备踩地——两个"一行配置"是质感的胜负手。
3. **健壮性是最贵的工程能力**(Day 111):加载、降级、释放——这些"不炫但保命"的活儿,是工业现场最看重的品质。
### 9.4 待办清单(Week 17 输入)
粒子系统(扫描线/粉尘/火花——环境氛围)
LOD 层级细节(远景降模,配合上量)
自定义着色器入门(ShaderMaterial——性能与特效的钥匙)
后处理进阶(辉光/景深/色彩分级)
WS 实时数据驱动 3D(第 6 个月主线,边界已预留)
---
## 十、常见坑点(本周汇总)
### 坑 1:效果全开性能崩
排查顺序(第六节):draw call → 阴影 mapSize → 贴图尺寸 → mixer 数量。**逐级降,别一上来砍效果**。
### 坑 2:装配顺序错(环境贴图在模型之后)
症状:模型金属发黑。原因:环境贴图创建晚于模型材质采样。**修法:环境贴图先于模型创建**(第三节依赖关系)。
### 坑 3:阴影 + 描边 + 动画叠加后"哪里不对"
先隔离:关掉描边看阴影,关掉动画看描边——**逐项开关定位问题**,别在叠加态里猜。
### 坑 4:交付日加效果
"再加个辉光""加点雾"——组装日最容易失控。**修法:进 Week 17 待办,今天只验收**(Day 70/105 同款纪律)。
### 坑 5:边界悄悄破洞
验收时发现 Vue 组件 import 了 Three 类型。**修法:"组件零 Three 依赖"是边界验收项,不过关就重构到只走桥**。
---
## 十一、自测挑战
### T1 · 全效果组装(80 分钟)
完成第三、四节:真实模型 + 罐体阵列 + 阴影描边 + 动画 + 加载降级,全效果跑通。俯视/45°/近景各截图留档。
### T2 · 双验收(40 分钟)
完成第五、六节:功能清单逐项打勾 + 性能表填数 + 降级演练。不达标项按第六节排查顺序修复。
### T3 · 边界定稿 + 自检(30 分钟)
定稿 `boundary-three-vue.md` v2,全项目扫描"Vue 组件零 Three 依赖"。
### T4 · 交付资产(40 分钟)
按第八节录 45 秒演示 + README + 简历条目(150 字内)。**给"未来的自己"和面试官各留一份**。
---
## 十二、总结
| 环节 | 要点 |
|------|------|
| 组装 | 只接线不重写:模型→贴图→阴影→动画→健壮性 |
| 装配顺序 | 环境贴图→模型→动画→后处理(依赖即顺序) |
| 双验收 | 功能清单 + 性能表 + 降级演练,逐项留档 |
| 健壮性 | 进度 / 降级 / 释放三件套——工程价值的证明 |
| 边界 v2 | 资产与加载态归引擎,Vue 只拿数字 |
| 交付 | 45s 演示 + README + 简历条目(每句能追问) |
| 待办 | 粒子 / LOD / 着色器 / 后处理进阶 → Week 17 输入 |
---
**🎉 第 16 周毕业。** 你现在拥有:一台有真实模型、PBR 质感、阴影描边、会转会闪、能扛断网的 3D 车间 2.0——这是阶段 3 的核心可展示资产。下一周进入 Week 17:**场景与性能进阶**——粒子系统、LOD、自定义着色器入门。开始第 17 周。