Skip to content

3D 游戏开发基础

预计阅读 25 分钟
版本信息
最后更新:2026-07-09 · 适用基础库:≥ 3.9.0 · 微信开发者工具:稳定版 1.06+

微信小游戏虽然以 2D 休闲游戏为主,但 Unity 和 Cocos Creator 3.x 都支持 3D 渲染。理解 3D 基础原理有助于在需要时做出正确的技术决策。本章以前端视角切入,帮助你建立 3D 核心概念体系。


前端 3D 经验 vs 游戏 3D

前端对比:CSS 3D vs 游戏 3D
维度前端 CSS 3D / Three.js游戏引擎 3D
坐标系CSS: 屏幕左上角,Z 轴向屏幕内游戏: 通常 Y-up,Z 指向屏幕外
变换transform: rotate/translate/scale模型矩阵(Model Matrix)
投影CSS perspective: 800px透视投影矩阵
渲染管线GPU 自动合成(Composite Layer)顶点着色器 → 光栅化 → 片段着色器
光照CSS lighting-color 有限支持Phong / PBR / 全局光照

关键差异: 前端 3D 本质上是"CSS 为 2D 元素添加 3D 视觉效果";游戏 3D 需要对整个渲染管线有底层理解。如果你用过 Three.js,你会对大部分概念感到熟悉——Three.js 本质上是对 WebGL 的封装,与游戏引擎的 3D 渲染是同一套底层原理。


3D 数学基础速览

向量 (Vector)

向量在游戏中最常用于表示位置、方向、速度、法线

typescript
// 3D 向量基本运算
class Vec3 {
  constructor(
    public x: number,
    public y: number,
    public z: number
  ) {}

  // 加法:位置偏移
  add(v: Vec3): Vec3 {
    return new Vec3(this.x + v.x, this.y + v.y, this.z + v.z)
  }

  // 缩放:改变速度大小
  scale(s: number): Vec3 {
    return new Vec3(this.x * s, this.y * s, this.z * s)
  }

  // 点积:判断朝向、计算夹角
  dot(v: Vec3): number {
    return this.x * v.x + this.y * v.y + this.z * v.z
  }

  // 叉积:计算法线、垂直方向
  cross(v: Vec3): Vec3 {
    return new Vec3(
      this.y * v.z - this.z * v.y,
      this.z * v.x - this.x * v.z,
      this.x * v.y - this.y * v.x
    )
  }

  // 长度
  get length(): number {
    return Math.sqrt(this.x ** 2 + this.y ** 2 + this.z ** 2)
  }

  // 归一化(单位向量,只保留方向)
  normalize(): Vec3 {
    const len = this.length
    return len > 0 ? this.scale(1 / len) : new Vec3(0, 0, 0)
  }
}

// 实战应用
const playerPos = new Vec3(0, 0, 0)
const enemyPos = new Vec3(10, 5, 0)

// 方向向量(从玩家指向敌人)
const direction = new Vec3(
  enemyPos.x - playerPos.x,
  enemyPos.y - playerPos.y,
  enemyPos.z - playerPos.z
).normalize()

// 判断敌人是否在玩家前方(点积 > 0 表示在前方)
const playerForward = new Vec3(0, 0, 1) // 玩家面朝 Z+ 方向
const isInFront = playerForward.dot(direction) > 0

矩阵 (Matrix)

矩阵用于变换:位移(Translate)、旋转(Rotate)、缩放(Scale)。在 WebGL/OpenGL 中使用 4×4 矩阵统一表示所有变换。

┌                        ┐
│ 1  0  0  tx │  列主序中 tx/ty/tz 是位移分量
│ 0  1  0  ty │
│ 0  0  1  tz │
│ 0  0  0  1  │
└                        ┘

前端类比:

  • transform: translate(100px, 0) ≈ 位移矩阵
  • transform: rotate(45deg) ≈ 旋转矩阵
  • transform: scale(2) ≈ 缩放矩阵
  • transform: matrix(a, b, c, d, tx, ty) ≈ 2D 仿射矩阵(3D 的简写版)

四元数 (Quaternion)

四元数是旋转的另一种表示方式,避免万向节死锁 (Gimbal Lock)。你不需要理解四元数的数学推导,只需知道:

typescript
// 欧拉角:直观但可能万向节死锁
// node.eulerAngles = new Vec3(0, 90, 0)  // 绕 Y 轴旋转 90°

// 四元数:数学稳定但不够直观
// node.rotation = Quaternion.fromEuler(0, 90, 0)

// 四元数插值(Slerp)实现平滑旋转过渡
// node.rotation = Quaternion.slerp(from, to, 0.5) // 两个旋转间插值 50%

3D 渲染管线

从前端 DOM → Layout → Paint → Composite 到游戏 3D 的 Vertices → Shaders → Rasterize → Pixels

┌─────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│ 顶点着色器    │ → │  图元装配      │ → │  光栅化       │ → │  片段着色器    │
│ (Vertex)     │    │ (Primitive)   │    │ (Rasterize)  │    │ (Fragment)   │
│ 坐标变换      │    │ 点/线/三角面   │    │ 生成像素片段   │    │ 逐像素着色    │
└─────────────┘    └──────────────┘    └──────────────┘    └──────────────┘
glsl
// 顶点着色器 — 运行在每个顶点上
// 将模型坐标变换到屏幕坐标
attribute vec4 a_position;
uniform mat4 u_modelViewProjection;

void main() {
  gl_Position = u_modelViewProjection * a_position;
}

// 片段着色器 — 运行在每个像素上
// 计算最终颜色
uniform vec4 u_color;

void main() {
  gl_FragColor = u_color;
}

光照模型

Phong 光照模型(经典)

最终颜色 = 环境光 + 漫反射 + 镜面反射
          Ambient + Diffuse + Specular
分量含义前端类比
环境光场景基础亮度,无方向body { background: #eee }
漫反射光线直射面更亮无直接前端类比
镜面反射高光/反光box-shadow 的部分效果

PBR(基于物理的渲染)

现代引擎(Unity、Cocos Creator 3.x)使用 PBR,核心参数:

  • Albedo(反照率):物体基础颜色
  • Metallic(金属度):0 = 非金属,1 = 金属
  • Roughness(粗糙度):0 = 镜面,1 = 完全漫反射

微信小游戏 3D 能力现状

技术选型建议

游戏类型推荐方案原因
休闲 2DCocos Creator 3.8.x LTS 2D 模式轻量、热更新友好;2.4.x 仅维护旧项目,不再推荐
3D 轻度(AR 拍照、3D 展示)Cocos Creator 3.8.x包体小(~2MB 引擎)
3D 中度(跑酷、射击)Unity 2022.3 LTS / Unity 6.3 LTS(6000.3.x)+ WX-WASM-SDK生态完善、工具链成熟
3D 重度(开放世界)不建议微信小游戏4MB 主包限制 + WebGL 性能瓶颈

骨骼动画原理

骨骼动画的核心思想:网格顶点随骨骼移动,而非存储每一帧的顶点位置。

骨架 (Skeleton)         蒙皮网格 (Skinned Mesh)
    │                          │
    ├── 根骨骼 (Root)          ├── 顶点位置 (静止姿态)
    ├── 脊椎 (Spine)           ├── 骨骼权重 (每顶点 4 根骨骼)
    ├── 手臂 (Arm L/R)         └── 骨骼索引
    └── 腿 (Leg L/R)

关键概念:

  • 绑定姿态 (Bind Pose):网格刚绑定到骨架时的姿态,作为基准
  • 蒙皮 (Skinning):根据骨骼当前变换,加权计算每个顶点的最终位置
  • 顶点权重:每个顶点最多受 4 根骨骼影响,权重总和 = 1.0

在代码层面你通常不需要手动处理这些——Cocos Creator 和 Unity 都有完整的骨骼动画系统,直接导入 Spines/FBX 即可。


📚 相关阅读


📝 课后练习

练习 1:3D 向量运算实现追逐 AI

题目: 使用向量运算实现一个简单的追逐 AI:敌人始终面向玩家并以固定速度移动。

参考答案:

typescript
class ChaseAI {
  position = new Vec3(0, 0, 0)
  speed = 5 // 单位/秒

  update(dt: number, playerPos: Vec3): void {
    // 计算方向向量
    const direction = new Vec3(
      playerPos.x - this.position.x,
      playerPos.y - this.position.y,
      playerPos.z - this.position.z
    )

    const distance = direction.length

    // 距离太近时停止(避免抖搂)
    if (distance < 0.5) return

    // 归一化方向并乘以速度和时间
    const velocity = direction.normalize().scale(this.speed * dt)

    this.position = this.position.add(velocity)
  }
}
练习 2:评估你的游戏是否需要 3D

题目: 假设你要开发一款「合成大西瓜」类型的物理游戏,请分析选择 3D 还是 2D 的技术考量。

参考答案:

考量维度2D (Cocos 2.4)3D (Cocos 3.8 / Unity)
物理引擎Box2D(成熟稳定)PhysX / Bullet(3D 物理)
渲染性能极低 GPU 占用即使做 2D 也需要 3D 管线开销
包体大小~1.5MB~3-5MB
视觉效果纯 2D 贴图可用 Shader 做光影特效
开发成本低(素材制作快)高(需要 3D 基础)
适配难度低(所有机型友好)中(低端机可能掉帧)

结论: 对于「合成大西瓜」这类游戏,2D 是更合理的选择。3D 的额外开销无法带来对应的体验提升。只有当游戏需要:

  • 3D 视角的沉浸感(如跑酷、射击)
  • 复杂的 3D 碰撞/物理
  • 动态光照和阴影效果

时才值得引入 3D 方案。

用心学习,持续实践