进入三维世界
三维世界的观察者
立方体是由三角形构成的
在绘制三维物体时,需要考虑
- 物体的 深度信息(depth information)
- 三维世界的观察者
如何定义三维世界的观察者?
需要几个关键信息:
- 他在哪
- 他朝哪看
- 他视野有多宽
- 他能看多远
视点和视线
为了定义一个观察者,需要考虑2点:
- 观察方向
- 可视距离
如何描述观察者的属性?
- 视点(eye point) 观察者的位置
- 视线(viewing direction) 观察者沿观察方向的射线
3项信息可以确定观察者状态:
视点(eye point)
即观察者在 三维空间中的位置,
也即 视线的起点 。
一般使用 ( eyeX, eyeY, eyeZ)表示
观察目标点(look-at point)
即 被观察目标所在的点,可以用来确定视线,
一般使用 ( atX, atY, atZ)表示
同时知道观察目标点和视点就能计算出视线方向。
上方向(up direction)
最终绘制在屏幕上的 影像中的向上的方向。
一般使用 3维矢量( upX, upY, upZ)表示
为什么一定要指定上方向?
答: 区分出观察者以视线为轴旋转的状态(想想你歪头看东西的时候)
视图矩阵(view matrix)
视图矩阵是做什么的?
答: 用来表示观察者的状态,包括视点、观察目标点、上方向等信息。
视图矩阵的使用位置?
答: 在顶点着色器中使用。
为什么要叫视图矩阵?
答: 因为它最终影响的是显示在屏幕上的视图。
Matrix4.setLookAt()
矩阵工具库 cuon-matrix.js 引入的 Matrix4 类型提供了创建视图矩阵的方法:
WebGL中观察者的默认状态
- 视点: (0,0,0)
- 观察点: (0,0,-1)
- 视线: Z轴负方向
- 上方向: Y轴负方向,即(0,1,0)
创建一个表示默认状态的矩阵
1 | var initialViewMatrix = new Matrix4(); |
LookAtTriangles
LookAtTriangles Code
1 |
|
1 | let VSHADER_SOURCE = |
比较变换矩阵与视图矩阵
变换矩阵(以旋转矩阵为例)
着色器程序
1 | attribute vec4 a_Position; |
变换矩阵的计算与传入
1 | let u_rotMatrix = gl.getUniformLocation(gl.program, 'u_rotMatrix'); |
视图矩阵
着色器程序
1 | attribute vec4 a_Position; |
视图矩阵的计算与传入
1 | let u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix'); |
改变观察者的状态 与 对整个世界进行平移和旋转变换,
这二者本质上是 一样 的。
LookAtRotatedTriangles
从指定视角观察旋转后的三角形
这个案例的关键问题在于:
怎么确定旋转矩阵与视图矩阵的使用顺序。
答: 先旋转图形,再移动视角。
下式展示的是 观察变换图形的矩阵计算式 :
1 | resultMatrix = <视图矩阵> * <模型矩阵> * <原始顶点坐标> |
LookAtRotatedTriangles Code
1 |
|
1 | let VSHADER_SOURCE = ` |
模型视图矩阵
模型视图矩阵(model view matrix)
LookAtRotatedTriangle为什么需要改进?
1 | gl_Position = u_ViewMatrix * u_ModelMatrix * a_Position; |
对于每一个顶点,Vertex_Shader都需要重复做一遍矩阵相乘计算。
这显然会造成不必要的开销,最好把这一步提到Js中。
<模型视图矩阵> = <视图矩阵> * <模型矩阵>
gl_Position = <模型视图矩阵> * <顶点坐标>
LookAtRotatedTriangle_mvMatrix Code
Tip1:multiply方法进行矩阵相乘的顺序
mA.multiply(mB) = mB * mA
Tip2:js部分还可以更加简化
1 | let u_mvMatrix = gl.getUniformLocation(gl.program, 'u_ModelViewMatrix'); |
1 | attribute vec4 a_Position; |
1 | let u_mvMatrix = gl.getUniformLocation(gl.program, 'u_ModelViewMatrix'); |
利用键盘改变视点
LookAtTrianglesWithKeys Code
1 |
|
1 | let VSHADER_SOURCE = ` |