—— 3D 网页游戏技术栈培训 · 从 WebGL 到 Three.js ——

Web 3D 的觉醒

第二十一本做完 2D 手游后,老板盯上了「免下载」的玩法——发个链接就能玩的 3D 网页游戏!小哲问:浏览器里做 3D?那不是要装插件吗?周师傅说:WebGL 让浏览器原生支持 3D,Three.js 让 3D 开发像搭积木。这一本,从 WebGL 原理到 Three.js 实战,把 Web 3D 技术栈完整走一遍。

🎮 ⚡ 🧱 🖥️ 🎥 ✨ 🏗️ 🕹️ ⚡ 🚀
序 章

点开即玩的 3D 世界

Web 3D 全景:WebGL → Three.js → 游戏引擎 → 上线
🧑‍💻
小哲

师傅!老板看了别人的 3D 网页游戏——免下载、点开就玩,转发还方便!「我们也做一个!」可浏览器里做 3D,不是要装 Flash 插件吗?

🧙
周师傅

Flash 是上古时代了——现在浏览器原生支持 WebGL(把 GPU 能力开放给网页),不用装任何东西。Web 3D 技术栈分四层:

  • 底层:WebGL(浏览器 3D API——像浏览器的「OpenGL」)。
  • 引擎:Three.js(最流行的 Web 3D 库——搭积木式开发)。
  • 框架:Babylon.js / PlayCanvas / React Three Fiber(游戏级/工程级)。
  • 平台:微信小游戏 / H5 页面——分发与上线。

来,十站路线——

1
WebGL 基础浏览器 GPU 接口、GLSL、渲染管线——底层原理
2
Three.js 入门Scene/Camera/Renderer、Mesh、灯光——第一个 3D 场景
3
场景搭建场景图、PBR 材质、灯光类型、贴图纹理
4
相机交互透视/正交相机、轨道控制器、Raycaster 拾取
5
动画物理requestAnimationFrame、骨骼动画、物理引擎
6
模型资产glTF/GLB、Blender 导出、Draco/KTX2 压缩
7
游戏引擎Babylon.js、PlayCanvas、React Three Fiber、Cocos
8
交互 UI输入、HUD、点击拾取、WebXR 初识
9
性能优化Draw Call、实例化、LOD、图集、遮挡剔除
10
加载发布首屏优化、CDN、微信小游戏、上线指标
🧙
周师傅

记住一句话:Web 3D = WebGL(GPU 接口)+ Three.js(引擎)+ 模型资产 + 性能优化——第二十一本的渲染知识在这里换个平台重演。走,第一站,看浏览器怎么「长」出 GPU。

第 1 站

WebGL:浏览器的 3D 能力

WebGL · Canvas · GLSL · 渲染管线 · 着色器

WebGL 是浏览器给网页开的「GPU 后门」——网页代码能直接指挥显卡画 3D。虽然日常开发不直接写它,但懂它才能懂 Three.js 在干什么。

🧙
周师傅

WebGL 三件事:

  • Canvas + WebGL 上下文:网页的「画布」上拿 GPU 绘制上下文——`canvas.getContext('webgl')`。
  • GLSL 着色器:GPU 上跑的着色语言——顶点着色器(位置变换)+ 片元着色器(像素颜色)——第二十一本渲染管线的浏览器版。
  • 渲染管线:顶点 → 光栅化 → 片元 ——和桌面 3D 完全同一条流水线(第 2 站渲染管线老朋友)。

关键认知:WebGL 是「底层 API」,写起来非常原始(几百行才能画个三角形)——所以没人直接写,都用 Three.js 封装。WebGL2 是升级版(支持更多特性)。

WebGL 最小示例(为什么没人直接写)
【画一个三角形需要……】
  ① 创建着色器程序(GLSL 代码 30 行)
  ② 准备顶点数据(缓冲)
  ③ 写渲染循环(requestAnimationFrame)
  ④ 处理矩阵(数学 50 行)
  → 300 行代码画个三角形 —— 所以用 Three.js!

【GLSL 着色器(了解语法)】
  // 顶点着色器:决定顶点画在哪
  void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
  // 片元着色器:决定像素什么颜色
  void main() {
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);   // 红色
  }

【WebGL vs WebGPU(未来)】
  WebGL:当前标准(Three.js 主力支持)
  WebGPU:新一代 API(更现代、性能更强)——未来方向
  → 学 Three.js 不用关心底层,引擎两个都兼容

【浏览器兼容】
  WebGL 支持率 98%+(所有现代浏览器)
  → 「免安装点开即玩」的硬件基础就是它

【技术栈全景(四层)】
  底层:WebGL / WebGPU
  引擎:Three.js(最流行)
  框架:Babylon.js / PlayCanvas / React Three Fiber
  平台:H5 / 微信小游戏 / 小程序

WebGL 术语

  • WebGL:浏览器 GPU 接口——网页 3D 的地基。
  • Canvas:网页画布——GPU 绘制的载体。
  • GLSL:GPU 着色语言——顶点/片元着色器。
  • 渲染管线:顶点→光栅→片元——第二十一本同款。
  • WebGL2 / WebGPU:升级版 / 下一代——未来方向。
  • 兼容性:98%+ 浏览器支持——免安装基础。
  • 别直接写:太原始——用 Three.js 封装。

本站收获:WebGL = 浏览器给网页的 GPU 后门(Canvas + GLSL + 渲染管线)。懂原理但别直接写——它太原始,这正是 Three.js 存在的意义。WebGPU 是未来方向。

第 2 站

Three.js:引擎入门

Scene/Camera/Renderer · Geometry/Material/Mesh · Light

Three.js 是 Web 3D 的事实标准(80% 以上项目用它)。核心就六个对象:场景、相机、渲染器、几何体、材质、网格——记住它们,你就入门了。

🧙
周师傅

Three.js 六大核心对象:

  • Scene(场景):装所有物体的「世界容器」。
  • Camera(相机):观察视角(PerspectiveCamera 透视——近大远小,游戏标配)。
  • Renderer(渲染器):WebGLRenderer——把场景画到 Canvas。
  • Geometry(几何体):形状——BoxGeometry(立方体)、SphereGeometry(球)。
  • Material(材质):表面属性——颜色、金属度、粗糙度。
  • Mesh(网格):几何体 + 材质 = 一个「可见物体」。

再加 Light(灯光)——没光的世界是黑的(第二十一本光照老朋友)。

Three.js 第一个场景(30 行搞定)
import * as THREE from "three";

// ① 场景
const scene = new THREE.Scene();

// ② 相机(透视:75° 视角,近远裁剪)
const camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);         // 放在(0,2,5)

// ③ 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

// ④ 物体:几何体 + 材质 = 网格
const geometry = new THREE.BoxGeometry(1, 1, 1);       // 立方体
const material = new THREE.MeshStandardMaterial({ color: 0x2dd4bf });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);                                        // 放进场景

// ⑤ 灯光(没光 = 全黑)
scene.add(new THREE.AmbientLight(0xffffff, 0.5));       // 环境光
const dir = new THREE.DirectionalLight(0xffffff, 1);    // 方向光
dir.position.set(3, 5, 3);
scene.add(dir);

// ⑥ 动画循环(第二十一本游戏循环!)
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.y += 0.01;          // 每帧转一点
    renderer.render(scene, camera);
}
animate();

【六大对象一句话】
  Scene 装世界 / Camera 看世界 / Renderer 画世界
  Geometry 形状 / Material 表面 / Mesh 可见物
  → 万事万物都是「几何+材质」组合进场景

【Hello 之后学什么】
  官网示例库(threejs.org/examples)——最好的教材
  常用:导入模型、动画、粒子、后处理特效

Three.js 术语

  • Scene / Camera / Renderer:世界 / 视角 / 画笔——三件套。
  • Geometry / Material / Mesh:形状 / 表面 / 可见物体。
  • Light:灯光——没光全黑。
  • PerspectiveCamera:透视相机——近大远小。
  • requestAnimationFrame:浏览器动画循环——游戏循环的 Web 版。
  • MeshStandardMaterial:PBR 标准材质——物理真实。
  • scene.add:物体入场景——世界构建器。

本站收获:Three.js = Scene(世界)+ Camera(视角)+ Renderer(画笔)+ Mesh(几何+材质)+ Light(光)。30 行代码一个会转的 3D 立方体——引擎把 WebGL 的 300 行封装成了 6 个概念。

第 3 站

场景搭建:材质与光照

场景图 · PBR 材质 · 灯光类型 · 贴图纹理

场景不止一个立方体——要地面、要房子、要氛围。场景图组织层次、PBR 材质让表面真实、灯光决定氛围。这一站,把「世界」搭出来。

🧙
周师傅

场景搭建三件事:

  • 场景图(Scene Graph):物体的「父子树」——爸爸移动,孩子跟着动(角色=身体节点,武器=子节点;和游戏引擎的场景树同款)。
  • PBR 材质:物理真实渲染——金属度/粗糙度/贴图,让物体「像真的」(MeshStandardMaterial)。
  • 灯光类型:Ambient(环境光,全局补光)、Directional(方向光,太阳)、Point(点光,灯泡)、Spot(聚光灯,舞台)——组合打光出氛围。

贴图(Texture):颜色图/法线图/粗糙度图——细节不用建模,贴图来补(第二十一本贴图老朋友)。

搭建一个小场景
// 场景图:父子关系(爸爸动,孩子跟着动)
const player = new THREE.Group();            // 空组(身体)
const head = new THREE.Mesh(sphereGeo, skinMat);
head.position.y = 1.7;                        // 相对身体的位置
player.add(head);                             // 头是身体的子节点
scene.add(player);                            // 身体进场景
player.position.x += 1;                       // 移动身体 → 头跟着走!

// PBR 材质:物理真实
const metal = new THREE.MeshStandardMaterial({
    color: 0xc0c0c0,
    metalness: 0.9,       // 金属度:高 = 金属
    roughness: 0.1,       // 粗糙度:低 = 光滑反光
});

// 贴图:细节靠贴图补(不用建模)
const woodTex = new THREE.TextureLoader().load("wood.jpg");
const floor = new THREE.Mesh(
    new THREE.PlaneGeometry(20, 20),
    new THREE.MeshStandardMaterial({ map: woodTex })  // 贴图材质
);
floor.rotation.x = -Math.PI / 2;              // 地面躺平
scene.add(floor);

// 灯光组合(氛围)
scene.add(new THREE.AmbientLight(0xffffff, 0.3));     // 全局补光
const sun = new THREE.DirectionalLight(0xffeedd, 1);  // 太阳
sun.position.set(10, 20, 5);
scene.add(sun);
const lamp = new THREE.PointLight(0xff8800, 1, 10);   // 暖灯泡
lamp.position.set(2, 3, 2);
scene.add(lamp);

【打光三原则】
  全局环境光:保证不黑
  主光(方向光):立体感来源(侧上 45°)
  点缀光(点/聚光):氛围与焦点
  → 灯光数量少而精(每盏灯都是渲染成本)

场景术语

  • 场景图(Scene Graph):父子树——爸爸动孩子跟。
  • Group:空容器——组织物体层级。
  • PBR 材质:物理真实——金属度/粗糙度。
  • 灯光类型:环境/方向/点/聚光——组合出氛围。
  • 贴图(Texture):颜色/法线/粗糙度——细节靠贴图。
  • 打光三原则:环境 + 主光 + 点缀——少而精。
  • 每灯成本:灯越多渲染越贵——灯光要节制。

本站收获:场景搭建 = 场景图(层级)+ PBR(真实)+ 灯光(氛围)+ 贴图(细节)。材质和光照决定「质感」——同样的模型,打光不同,感觉完全不同。

第 4 站

相机与交互:玩家视角

透视/正交 · 轨道控制器 · Raycaster · 点击拾取

玩家怎么看 3D 世界?相机怎么控制?点击怎么「捡起」物体?——相机 + 射线拾取是 Web 3D 交互的两大核心。

🧙
周师傅

交互两件事:

  • 相机控制透视相机(近大远小——游戏/真实感)vs 正交相机(平行投影——2.5D/建筑);轨道控制器(OrbitControls):鼠标拖拽旋转/滚轮缩放——「3D 查看器」标配。
  • 点击拾取(Raycaster 射线):鼠标点击 → 从相机发一条射线 → 检测和哪些物体相交 → 拾取点击的物体——「点选」交互的灵魂。

游戏视角:第一人称(相机在角色眼睛)、第三人称(相机跟在角色后面)——相机是「玩家的眼睛」。

相机控制与点击拾取
// 轨道控制器(鼠标旋转/缩放——3D 查看器标配)
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;          // 惯性手感

// Raycaster:点击拾取(点选交互的灵魂)
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();

renderer.domElement.addEventListener("click", (e) => {
    // 屏幕坐标 → 归一化设备坐标
    pointer.x = (e.clientX / innerWidth) * 2 - 1;
    pointer.y = -(e.clientY / innerHeight) * 2 + 1;

    raycaster.setFromCamera(pointer, camera);   // 从相机发射线
    const hits = raycaster.intersectObjects(scene.children, true);
    if (hits.length > 0) {
        console.log("点到了:", hits[0].object.name);
        highlight(hits[0].object);              // 高亮被点中的
    }
});

【相机两种选型】
  透视(PerspectiveCamera):近大远小——真实感(游戏)
  正交(OrthographicCamera):平行投影——2.5D/俯视策略

【游戏视角】
  第一人称:相机 = 角色眼睛(射击/FPS)
  第三人称:相机跟在角色后(动作/RPG)
  → 相机跟随:每帧 lerp 平滑跟随角色位置

【Raycaster 应用】
  点击拾取(选物体/捡装备)
  悬停高亮(鼠标指哪亮哪)
  拖拽移动(抓住物体跟着走)
  → 所有「鼠标和 3D 世界互动」都是它

交互术语

  • 透视 vs 正交相机:近大远小 vs 平行投影。
  • OrbitControls:轨道控制器——拖拽旋转滚轮缩放。
  • Raycaster:射线检测——点击拾取灵魂。
  • 归一化坐标:屏幕坐标转 NDC——射线计算前提。
  • 第一/第三人称:相机位置决定视角。
  • 相机跟随:lerp 平滑跟随——手感的细节。
  • 悬停高亮:射线 + 材质变色——交互反馈。

本站收获:交互 = 相机(玩家眼睛)+ Raycaster(点击射线)。OrbitControls 让 3D 可浏览、射线让 3D 可操作——「看得见 + 点得中」就是 3D 交互的全部。

第 5 站

动画与物理:世界动起来

requestAnimationFrame · 关键帧/骨骼动画 · 物理引擎 · 碰撞

3D 世界要「活」——物体动起来靠动画,落体弹跳靠物理。这一站,给静止的场景注入生命(第二十一本游戏循环的 Web 版)。

🧙
周师傅

动起来三件事:

  • 动画循环(requestAnimationFrame):浏览器每帧回调(约 60 次/秒)——就是 Web 版的游戏循环(第 2 站见过,这里展开)。
  • 动画类型关键帧动画(补间:位置/旋转插值)、骨骼动画(模型自带动作——导入的角色模型通常带骨骼动画,GLTFLoader 加载后播放)。
  • 物理引擎cannon-es(轻量 3D 物理)/ Ammo.js(Bullet 移植,重量级)——刚体、重力、碰撞自动算(第二十一本物理老朋友)。
动画 + 物理实战
// ① 动画循环(游戏循环的 Web 版)
let last = 0;
function animate(time) {
    requestAnimationFrame(animate);
    const dt = (time - last) / 1000;    // deltaTime!(第二十一本)
    last = time;

    // 关键帧动画:补间插值
    cube.position.y = 1 + Math.sin(time / 500) * 0.5;   // 上下浮动
    cube.rotation.y += dt * 0.5;                        // 匀速旋转

    controls.update();
    renderer.render(scene, camera);
}
animate();

// ② 骨骼动画(导入角色后播放)
gltf.animations;                        // 模型自带动作列表
mixer = new THREE.AnimationMixer(gltf.scene);
const walk = mixer.clipAction(gltf.animations.find(a => a.name === "Walk"));
walk.play();                            // 播放走路动画

// ③ 物理引擎(cannon-es:刚体 + 重力 + 碰撞)
import * as CANNON from "cannon-es";
const world = new CANNON.World({ gravity: new CANNON.Vec3(0, -9.82, 0) });
const ballBody = new CANNON.Body({ mass: 1 });       // 刚体
ballBody.addShape(new CANNON.Sphere(0.5));
world.addBody(ballBody);

function animate(time) {
    world.step(1 / 60);                 // 物理步进
    ballMesh.position.copy(ballBody.position);        // 物理→渲染同步
    renderer.render(scene, camera);
}

【动画 vs 物理分工】
  动画:播放预设动作(走路/攻击——美术做好的)
  物理:实时计算(落体/碰撞/弹跳——引擎算的)
  → 角色走路用动画,石头下落用物理

【物理同步模式】
  物理引擎算位置 → 每帧同步给 Three 网格
  → 「物理世界」和「渲染世界」两个世界对齐

动画物理术语

  • requestAnimationFrame:浏览器动画循环——Web 游戏循环。
  • deltaTime:帧间隔——速度一致性(第二十一本)。
  • 关键帧动画:位置/旋转插值补间。
  • 骨骼动画:模型自带动作——AnimationMixer 播放。
  • cannon-es / Ammo.js:轻量 / 重量级物理引擎。
  • 刚体 + 重力:物理世界的基础。
  • 物理→渲染同步:两个世界的对齐。

本站收获:动起来 = requestAnimationFrame(循环)+ 动画(关键帧/骨骼)+ 物理(cannon 刚体重力)。动画是「美术编排」,物理是「引擎实时算」——两者配合,世界才活。

第 6 站

模型与资产:内容管线

glTF/GLB · Blender 导出 · Draco/KTX2 · 资产加载

3D 内容从哪来?——Blender 建模 → glTF 格式 → 网页加载。模型格式、压缩、加载流程:3D 网页游戏的「内容管线」。

🧙
周师傅

内容管线三件事:

  • glTF(GLB):Web 3D 的标准格式(「3D 的 JPEG」)——几何+材质+动画+场景一包装。GLB 是二进制版(体积小、加载快)——Three.js 官方推荐格式。
  • 建模工具(Blender):免费开源 3D 建模——建模 → 材质 → 绑定骨骼 → 导出 glTF/GLB。
  • 压缩Draco(几何压缩——顶点数据压 80%)、KTX2(纹理压缩——GPU 直接读)、Meshopt(更现代的几何压缩)——Web 3D 加载快的秘诀。
模型导入实战
// 加载 glTF 模型(GLTFLoader)
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";

// Draco 压缩:几何数据先解压
const draco = new DRACOLoader();
draco.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.4.1/");

const loader = new GLTFLoader();
loader.setDRACOLoader(draco);
loader.load("models/robot.glb", (gltf) => {
    scene.add(gltf.scene);              // 模型入场景
    // gltf.animations 模型自带动画(第5站播放)
}, (xhr) => {
    console.log("加载进度:", xhr.loaded / xhr.total * 100 + "%");
});

【glTF 是什么】
  Web 3D 的标准格式(“3D 世界的 JPEG”)
  一个 .glb 文件 = 几何 + 材质 + 贴图 + 动画 + 场景
  → Three.js / Babylon / Unity WebGL 都支持

【资产压缩三件套】
  Draco:几何压缩(顶点位置/法线压 80%)
  KTX2 :纹理压缩(GPU 直接读,省显存省加载)
  Meshopt:现代几何压缩(更小更快)
  → 首屏加载快的幕后功臣(第10站展开)

【内容管线全流程】
  Blender 建模/绑定 → 导出 .glb → Draco/KTX2 压缩
  → 上传 CDN(第10站)→ Three.js 加载 → 场景中使用

【模型来源】
  自建:Blender(免费)/ 建模师外包
  现成:Sketchfab(模型市场)/ Quixel(素材库)
  → 个人开发先用现成模型,练手不卡美术

【坑:格式与兼容】
  老格式(OBJ/DAE):能用但不推荐(无压缩无动画)
  FBX:美术常用但大——转 glTF 再上网页
  → 统一走 glTF/GLB 是 Web 3D 的规矩

资产术语

  • glTF / GLB:Web 3D 标准格式——「3D 的 JPEG」。
  • Blender:免费开源建模工具。
  • Draco:几何压缩——顶点压 80%。
  • KTX2:纹理压缩——GPU 直接读。
  • GLTFLoader:模型加载器——官方标准。
  • DRACOLoader:解压器——先解压再加载。
  • 内容管线:建模→导出→压缩→上传→加载。

本站收获:内容管线 = Blender 建模 → glTF/GLB 导出 → Draco/KTX2 压缩 → CDN 加载。统一走 glTF + 压缩——「模型是 3D 世界的食材,格式是保鲜盒」。

第 7 站

游戏引擎:高层框架

Babylon.js · PlayCanvas · React Three Fiber · Cocos/Unity WebGL

Three.js 是「3D 库」,要做完整的游戏还需要游戏引擎功能(场景管理/输入/UI/物理集成)——这一站,看高层框架怎么选。

🧙
周师傅

框架地图:

  • Three.js:最流行——灵活的 3D 库(渲染为主,其他自己拼)。
  • Babylon.js:游戏引擎级——场景/物理/UI/音频全内置(微软出品,Web 3D 游戏选它更像「引擎」)。
  • React Three Fiber:React 生态的 Three.js——用组件写 3D(「声明式 3D」,React 团队的项目)。
  • PlayCanvas:在线编辑器 + 引擎——像「Web 版 Unity」(可视化拖拽)。
  • Cocos Creator:国内小游戏主力——导出微信小游戏(3D 也支持)。
  • Unity WebGL:Unity 项目导出网页版——适合已有 Unity 项目(包体大)。
框架选型
【框架对比】
  框架            定位            适合
  Three.js       3D 库(灵活)   3D 展示/轻游戏
  Babylon.js     游戏引擎        正经 Web 3D 游戏
  R3F (React)    组件化 3D       React 团队/数据可视化
  PlayCanvas     在线引擎        可视化拖拽
  Cocos Creator  小游戏引擎      微信小游戏(3D 也行)
  Unity WebGL    Unity 导出      已有 Unity 项目

【React Three Fiber(组件化 3D)】
<Canvas>
  <ambientLight />
  <mesh rotation={[0, angle, 0]}>
    <boxGeometry />
    <meshStandardMaterial color="teal" />
  </mesh>
</Canvas>
→ 用 JSX 组件描述 3D 场景(声明式!——第十九本 SwiftUI 同思想)

【选型口诀】
  3D 展示/学习   → Three.js
  正经 Web 游戏  → Babylon.js(引擎功能全)
  React 团队     → React Three Fiber
  微信小游戏     → Cocos Creator(最成熟路径)
  已有 Unity     → Unity WebGL 导出

【游戏引擎 vs 3D 库】
  3D 库:只管渲染(Three.js)——其他自己拼
  游戏引擎:渲染+场景+物理+UI+输入+资源管理一体化
  → 做「游戏」选引擎,做「展示」选库

框架术语

  • Babylon.js:Web 3D 游戏引擎——全内置。
  • React Three Fiber:React 组件化 3D——声明式。
  • PlayCanvas:在线可视化引擎——Web 版 Unity。
  • Cocos Creator:小游戏引擎——微信小游戏主力。
  • Unity WebGL:Unity 导出网页——已有项目用。
  • 3D 库 vs 引擎:渲染 vs 一体化——按目标选。
  • 选型口诀:展示 Three / 游戏 Babylon / 小游戏 Cocos。

本站收获:框架 = Three.js(灵活库)+ Babylon(游戏引擎)+ R3F(React 组件)+ Cocos(小游戏)。做展示用库、做游戏用引擎、上小游戏用 Cocos——「选型跟着目标走」。

第 8 站

交互与 UI:游戏操作

输入 · HUD · 点击拾取 · WebXR 初识

游戏要「玩」起来——键盘/鼠标/触屏输入、HUD 界面、和 3D 世界的操作。这一站,把第 4 站的交互扩展成「游戏操作」。

🧙
周师傅

游戏操作四件事:

  • 输入:键盘(WASD 移动)、鼠标(视角/点击)、触屏(虚拟摇杆/手势)——手机游戏触屏优先(第二十一本输入老朋友)。
  • HUD:叠加的 HTML/CSS 界面(血条/分数/按钮)——3D 场景 + 2D HTML UI 两层叠加(第二十一本 HUD)。
  • 点击拾取:Raycaster(第 4 站)——点击 3D 物体捡装备/选单位。
  • WebXR(VR/AR):浏览器原生 VR/AR——未来的 3D 交互(VR 眼镜看 3D 场景、AR 把 3D 放现实里)。
游戏操作实战
// ① 键盘输入(WASD 移动——第二十一本轮询)
const keys = {};
addEventListener("keydown", e => keys[e.code] = true);
addEventListener("keyup", e => keys[e.code] = false);

// 每帧查状态(Update 里轮询)
function update(dt) {
    const speed = 3 * dt;                    // deltaTime 速度一致
    if (keys["KeyW"]) player.position.z -= speed;
    if (keys["KeyA"]) player.position.x -= speed;
    if (keys["KeyD"]) player.position.x += speed;
}

// ② 触屏(手机——虚拟摇杆)
// 触屏坐标 → 摇杆位移 → 角色方向移动(手势检测)

// ③ HUD:HTML 叠在 3D 上
// <div id="hud">金币:<span id="gold">0</span></div>
// CSS: position:fixed; z-index:10;(3D canvas 之上)

// ④ 点击拾取(第4站 Raycaster)——点击敌人开打
renderer.domElement.addEventListener("click", (e) => {
    const hit = pick(e);                     // 射线检测
    if (hit?.object.name === "enemy") attack(hit.object);
});

【输入设计原则】
  键盘:WASD/空格(桌面)
  鼠标:视角拖拽 + 点击
  触屏:虚拟摇杆 + 手势(手机优先)
  → 多端适配:检测设备类型切换输入方案

【UI 与 3D 分层】
  3D 场景(Canvas)+ 2D UI(HTML/CSS)两层
  → 3D 互动用射线,2D 信息用 HTML(开发简单)

【WebXR 初识】
  VR:眼镜看 3D 场景(AR/VR 设备)
  AR:3D 叠到现实(手机摄像头)
  → Three.js 官方 WebXR 支持——未来交互方向

交互 UI 术语

  • 键盘/鼠标/触屏:三端输入——设备适配。
  • 虚拟摇杆:手机移动方案——触屏手势。
  • HUD:HTML/CSS 叠 3D——两层叠加。
  • 点击拾取:Raycaster——捡装备/选单位。
  • WebXR:浏览器 VR/AR——未来交互。
  • 输入轮询:每帧查键——第二十一本 Update。
  • 多端适配:桌面/手机切换输入方案。

本站收获:游戏操作 = 输入(键鼠/触屏)+ HUD(HTML 叠加)+ 射线(点击互动)+ WebXR(未来)。3D 世界 + 2D UI 两层叠加——「3D 互动用射线,2D 信息用 HTML」。

第 9 站

性能优化:60fps 流畅

Draw Call · 实例化 · LOD · 纹理图集 · 遮挡剔除

网页 3D 的性能瓶颈:CPU 提交渲染指令(Draw Call)+ GPU 像素量。低端手机也要 60fps——这一站,Web 3D 性能方法论(第二十一本同款哲学换个平台)。

🧙
周师傅

性能五板斧:

  • Draw Call:渲染指令数——1000 棵树 = 1000 次调用 = 卡;实例化(Instancing):相同的树一次调用画 1000 棵(第二十一本同款概念)。
  • LOD(多级细节):远的用低模、近的用高模——第二十二本地图瓦片 LOD 的 3D 版。
  • 纹理图集(Atlas):多张贴图合成一张——减少切换绑定。
  • 遮挡剔除(Frustum Culling):屏幕外的物体不渲染——Three.js 默认开启视锥剔除。
  • 显存/内存:纹理压缩(KTX2)、释放不用的资源——防低端机爆显存。
性能优化实战
【帧预算(60fps = 16.7ms/帧)——第二十一本同款】
  渲染 8ms + 逻辑 3ms + 物理 2ms + 余量
  → 用浏览器 Profiler(Performance 面板)先测量

【实例化(Instancing):1000 棵树一次画】
const count = 1000;
const instanced = new THREE.InstancedMesh(geometry, material, count);
// 设置每棵的位置/旋转/缩放
for (let i = 0; i < count; i++) {
    const m = new THREE.Matrix4().makeTranslation(x[i], y[i], z[i]);
    instanced.setMatrixAt(i, m);
}
scene.add(instanced);
// → 1 次 Draw Call 画 1000 棵树(vs 1000 次)

【LOD(多级细节)】
new THREE.LOD()
  .addLevel(highModel, 0)      // 近处:高模
  .addLevel(midModel, 30)      // 中距离
  .addLevel(lowModel, 80);     // 远处:低模
// 相机近了自动换高模——性能与画质平衡

【性能排查流程】
  ① Performance/Profiler 采样 → 找热点帧
  ② 是 Draw Call 多?→ 实例化/合批/图集
  ③ 是像素多?→ LOD/遮挡剔除/降分辨率
  ④ 是 JS 慢?→ 避免每帧分配/对象池(第二十一本)
  → 先测量再优化(全系列铁律)

【手机特有】
  低端机 GPU 弱:降分辨率渲染(renderer.setPixelRatio)
  发热降频:负载平缓(别瞬间吃满)
  省电:画面静止时降帧率(60→30fps)

【显存管理】
  纹理 KTX2 压缩(第6站)——省显存
  离开场景释放:geometry.dispose()/material.dispose()
应用场景:千元机上的「森林场景」优化

3D 小游戏「森林寻宝」:一开始 500 棵树逐个添加——千元机 15fps 卡成 PPT。整改:InstancedMesh 一次画 500 棵 → Draw Call 从 500 降到 1;远处树用 LOD 低模 → 帧率 55fps。Web 3D 优化的核心就一句话:**让 GPU 少干活**。

性能术语

  • Draw Call:渲染指令数——Web 3D 第一瓶颈。
  • Instancing(实例化):相同物体一次画——千树一画。
  • LOD:远近换模型——细节分级。
  • 纹理图集:多图合一——省绑定切换。
  • 视锥剔除:屏幕外不渲染——Three 默认。
  • 降分辨率:低端机 setPixelRatio——保帧率。
  • 先测量再优化:Performance 定位——全系列铁律。

本站收获:性能 = Draw Call 实例化 + LOD 分级 + 图集 + 剔除 + 显存管理。16.7ms 是每帧预算——「让 GPU 少干活」就是 Web 3D 优化的全部秘密。

第 10 站

加载与发布:上线之路

首屏优化 · 进度条 · CDN · 微信小游戏 · 上线指标

「点开即玩」的承诺靠什么兑现?首屏加载速度!模型再精美,加载 10 秒用户就跑了。这一站,Web 3D 的「最后一公里」。

🧙
周师傅

加载优化四件事:

  • 首屏速度:目标 3 秒内可玩——资源分包(先加载最小场景)+ 进度条(LoadingManager 显示进度)。
  • 资源压缩:Draco/KTX2(第 6 站)+ gzip/brotli(Web 传输压缩)——体积砍半。
  • CDN 分发:模型/纹理放 CDN(就近下载)——全球加速(第二十一本/二十二本 CDN 老朋友)。
  • 微信小游戏:Cocos 导出(第 7 站)→ 微信平台——国内「免下载」主战场(包体限制 4M 主包 + 分包)。
加载与发布实战
【加载进度条(LoadingManager)】
const manager = new THREE.LoadingManager();
manager.onProgress = (url, loaded, total) => {
    bar.style.width = (loaded / total * 100) + "%";   // 进度条
};
const loader = new GLTFLoader(manager);

【首屏优化策略】
  ① 分包:先加载「开场场景」(小)→ 后台加载正式场景(大)
  ② 骨架场景:先显示天空/地面(几 KB)→ 模型到了再出现
  ③ 压缩:Draco(几何) + KTX2(纹理) + brotli(传输) —— 体积减 70%
  ④ 懒加载:玩家走到哪,加载哪块(区域按需)

【发布平台】
  H5 页面:任意服务器/CDN 托管 → 链接即玩
  微信小游戏:Cocos 导出 → 微信开发者工具上传 → 审核
  → 国内「免下载」主战场是微信小游戏(社交裂变强)

【上线指标(Web 游戏)】
  首屏时间:< 3 秒(用户耐心上限)
  加载成功率:> 95%(弱网/低端机都能进)
  帧率:主流机型 > 50fps
  留存/分享:玩法 + 加载速度决定分享传播

【技术栈总结(全书串联)】
  底层 WebGL → 引擎 Three.js/Babylon
  → 模型 glTF+压缩 → 交互射线 → 性能实例化/LOD
  → 加载分包+CDN → 平台 H5/小游戏
  → 一条完整的 Web 3D 游戏生产线
应用场景:「森林寻宝」的免下载上线

小哲团队把「森林寻宝」发成微信小游戏:Cocos Creator 开发 → 主包控制 4M(模型分包加载)→ 微信审核通过 → 群里发个链接点开即玩——分享裂变带来 10 万玩家。免下载 + 社交传播 = 微信小游戏的红利(也别忘了合规:版号要求同第二十一本)。

发布术语

  • 首屏时间:< 3 秒可玩——用户耐心上限。
  • LoadingManager:加载进度——进度条实现。
  • 分包/懒加载:先小后大、按需加载。
  • CDN:就近分发——全球加速。
  • 微信小游戏:免下载主战场——4M 主包限制。
  • brotli/gzip:Web 传输压缩——体积砍半。
  • 上线指标:首屏/成功率/帧率/留存。

本站收获:上线 = 分包 + 压缩 + CDN + 进度条 + 微信小游戏。首屏 3 秒是承诺,加载优化是兑现——「点开即玩」四个字,全靠最后一公里。

附录

技术栈速查 + 面试高频题

面试/开发前最后一页

Web 3D 技术栈全景表

环节核心知识点一句话人话
底层WebGL、Canvas、GLSL、渲染管线、WebGPU浏览器 GPU 后门
引擎Three.js、Scene/Camera/Renderer、MeshWeb 3D 事实标准
场景场景图、PBR、灯光、贴图搭世界 + 打光
交互相机控制、Raycaster、OrbitControls看得见 + 点得中
动画物理requestAnimationFrame、骨骼动画、cannon世界动起来
资产glTF/GLB、Blender、Draco、KTX2内容管线
框架Babylon、R3F、PlayCanvas、Cocos游戏引擎选型
交互 UI输入、HUD、射线拾取、WebXR游戏操作
性能Draw Call、Instancing、LOD、图集、剔除让 GPU 少干活
发布首屏优化、CDN、微信小游戏、进度条点开即玩

面试高频题速记

  • WebGL 是什么?→ 浏览器 GPU 接口——网页 3D 的地基(Canvas + GLSL)。
  • Three.js 六大对象?→ Scene/Camera/Renderer + Geometry/Material/Mesh。
  • 为什么用 Three.js 不用 WebGL?→ WebGL 太原始(300 行画三角形)——引擎封装。
  • glTF 是什么?→ Web 3D 标准格式——几何+材质+动画一包(3D 的 JPEG)。
  • 怎么点击 3D 物体?→ Raycaster 射线——相机发线检测相交。
  • Draw Call 太多怎么优化?→ 实例化(InstancedMesh)+ 合批 + 图集。
  • LOD 是什么?→ 远近换模型——性能与画质平衡。
  • requestAnimationFrame 干嘛的?→ 浏览器动画循环——Web 版游戏循环。
  • Draco/KTX2 有什么用?→ 几何/纹理压缩——加载快 80%。
  • 首屏加载怎么优化?→ 分包 + 压缩 + CDN + 进度条 + 懒加载。
底层 WebGL
引擎 Three.js
场景 材质光照
交互 相机/射线
动效 动画物理
资产 glTF 压缩
框架 Babylon/Cocos
性能 实例化/LOD
上线 分包/CDN 🚀
Web 3D = WebGL(GPU 接口)+ Three.js(引擎)+ 模型资产 + 性能优化——
把第二十一本的渲染知识,搬进浏览器的世界。
免下载、点开即玩、链接即传播——
WebGL 打开的是「浏览器里的 3D 世界」,
Three.js 让它从 300 行代码变成 6 个概念;
而真正让世界流畅的,永远是那句老话——让 GPU 少干活。
🎮 ⚡ 🧱 🖥️ 🎥 ✨ 🏗️ 🕹️ ⚡ 🚀 🌳
✌ 语言