更新于 

附录G:世界坐标系和本地坐标系

使用专用三维建模工具构建模型的优势

之前只要绘制模型就需要在 initVertexBuffers 里手动写入大量的数据:

比如MultiJoinModel程序的模型数据全都写在程序里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var vertices = new Float32Array([
0.5, 1.0, 0.5, -0.5, 1.0, 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, 0.5, // v0-v1-v2-v3 front
0.5, 1.0, 0.5, 0.5, 0.0, 0.5, 0.5, 0.0,-0.5, 0.5, 1.0,-0.5, // v0-v3-v4-v5 right
0.5, 1.0, 0.5, 0.5, 1.0,-0.5, -0.5, 1.0,-0.5, -0.5, 1.0, 0.5, // v0-v5-v6-v1 up
-0.5, 1.0, 0.5, -0.5, 1.0,-0.5, -0.5, 0.0,-0.5, -0.5, 0.0, 0.5, // v1-v6-v7-v2 left
-0.5, 0.0,-0.5, 0.5, 0.0,-0.5, 0.5, 0.0, 0.5, -0.5, 0.0, 0.5, // v7-v4-v3-v2 down
0.5, 0.0,-0.5, -0.5, 0.0,-0.5, -0.5, 1.0,-0.5, 0.5, 1.0,-0.5 // v4-v7-v6-v5 back
]);

// Normal
var normals = new Float32Array([
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back
]);

// Indices of the vertices
var indices = new Uint8Array([
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);
而使用建模工具允许对基本三维图形进行各种操作:
  • 组合
  • 形变
  • 顶点数量调整
  • 顶点间隔优化
  • 等等
本地坐标系与世界坐标系的关系
本地坐标系与世界坐标系的关系

本地坐标系

本地坐标系(local coordinate system)

创建三维模型需要知道模型原点 (0.0, 0.0, 0.0)在哪,比如:

  • 立方体的原点就在 中心
  • 太阳或月亮等球体的原点在 球心
游戏角色模型的原点

大部分都位于 脚部
Y轴 垂直向上 穿过身体的中线。
这样就可以方便的操纵游戏角色在世界中的位置和动作:

  • y=0 时,游戏角色就站立在地面上
  • 模型沿y轴旋转,即是角色在 转向
  • 沿Z轴或X轴移动角色,即是角色在地面上跑动或滑动
育碧教科书式模型坐标bug
育碧教科书式模型坐标bug
《刺客信条:罗马之下》
《刺客信条:罗马之下》

世界坐标系

世界坐标系(world coordinate system)

也称 全局坐标系 (global coordinate system)
当空间中的物体移动和变化时,不能将世界坐标系本体坐标系分开考虑,
需要将两个坐标系结合起来考虑,即 世界变换

世界变换(world transformation)

即物体本身仍然是基于 本地坐标系
但物体相对世界的变换需要将 本地坐标系 转换到 世界坐标系
这就是世界变换。

LocalAndWorldCoordinate案例主要介绍的是简单的世界变换

LocalAndWorldCoordinate Code
沿本体坐标系旋转基本原理

实际上就是将物体先平移回原点,然后旋转,然后再平移回来,
这本书作者也在书里吐槽:

”为了企鹅像在跳芭蕾舞一样自旋,你需要先把企鹅移到场景原点,旋转,再移回来,真够麻烦的。“

Local && World
未经世界变换的三角形围绕世界y轴旋转
未经世界变换的三角形围绕世界y轴旋转
vertex shader
1
2
// u_MvpMatrix 为视图模型矩阵,其中模型部分直接进行绕Y轴旋转变换
gl_Position = u_MvpMatrix * a_Position
经过世界变换的三角形围绕本体y轴旋转
经过世界变换的三角形围绕本体y轴旋转
vertex shader
1
2
3
4
5
// u_vpmatrix 视图矩阵
// transbackMatrix 将顶点平移回原点的平移矩阵
// u_RotateMatrix 旋转矩阵
// translateMatrix 将顶点从原点平移回坐标位置的平移矩阵
gl_Position = u_vpMatrix * transbackMatrix * u_RotateMatrix * translateMatrix * a_Position;
1
2
3
4
5
6
7
8
9
10
11
12
13
let verticesColors = new Float32Array([
0.0, 0.3, 0.5, 0.3, 0.6, 0.6,
-0.3, -0.3, 0.5, 0.3, 0.0, 0.6,
0.3, -0.3, 0.5, 0.3, 0.0, 0.6,

0.0, 0.3, 0.0, 0.3, 0.8, 0.8,
-0.3, -0.3, 0.0,0.3, 0.0, 0.8,
0.3, -0.3, 0.0,0.3, 0.0, 0.8,

0.0, 0.3, -0.5,0.3, 1.0, 1.0,
-0.3, -0.3, -0.5, 0.3, 0.0, 1.0,
0.3, -0.3, -0.5,0.3, 0.0, 1.0,
])
1
2
3
4
5
6
7
8
9
10
let vpMatrix = new Matrix4()
vpMatrix.setOrtho(
-1.0, 1.0,
-1.0, 1.0,
-1.0, 1.0
).lookAt(
-0.5, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0,1.0,0.0
)

变换与坐标系