《WebGL权威指南》学习笔记-进阶

/post/webgl-advanced article cover image

立方体

三维物体与二维图形的显著区别就是,三维物体具有深度也就是Z轴绘制时需要考虑他们的深度信息(depth infromation)

视点和视线

绘制三维场景到二维屏幕上其实是绘制观察者看到的世界需要考虑观察方向可视距离,观察者所处的位置称为视点(eye point)从视点出发沿着观察方向的射线称作视线(viewing direction)

  • <Primary>视点(eyeX,eyeY,eyeZ)</Primary>:观察者所在的三维空间中位置,视线的起点
  • <Primary>观察目标点(atX,atY,atY)</Primary>:被观察目标所在的点,视线从视点出发,穿过观察目标点并继续延伸,只有同时知道观察目标点和视点,才能算出视线方向
  • <Primary>上方向(upX,upY,upZ)</Primary>:最总绘制在屏幕上的影像中的方向,只是确定观点和观察点,观察者还是可能以视线为轴旋转的,所以为了将观察者固定住还需要指定上方向

由观察者的视点、观察目标、上方向三个矢量组成的叫视图矩阵(view matrix),通过cuon-matrix.jsMatrix4.setLockAt(视点, 观察目标点, 上方向)通过矩阵 x 顶点计算最终渲染位置

js
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'uniform mat4 u_ViewMatrix;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = u_ViewMatrix * a_Position;\n' +
  '  v_Color = a_Color;\n' +
  '}\n';

function main() {
  // ...
  var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
  if (!u_ViewMatrix) {
    console.log('Failed to get the storage locations of u_ViewMatrix');
    return;
  }

  var viewMatrix = new Matrix4();
  viewMatrix.setLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0);
  gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
  // ...
}
//...

在视图矩阵的基础上组合变换矩阵被称为模型矩阵:

  • <Primary>旋转后顶点坐标</Primary> = 旋转矩阵 x 原始顶点坐标
  • <Primary>"从视点看上去"的旋转后顶点坐标</Primary> = 视图矩阵 x 旋转后顶点坐标
  • <Primary>变换视点矩阵</Primary> = 模型矩阵 x 原始顶点坐标
js
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'uniform mat4 u_ViewMatrix;\n' +
  'uniform mat4 u_ModelMatrix;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = u_ViewMatrix * u_ModelMatrix * a_Position;\n' +
  '  v_Color = a_Color;\n' +
  '}\n';

var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
if(!u_ViewMatrix || !u_ModelMatrix) {
  console.log('Failed to get the storage location of u_viewMatrix or u_ModelMatrix');
  return;
}

var viewMatrix = new Matrix4();
viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0);

var modelMatrix = new Matrix4();
modelMatrix.setRotate(-10, 0, 0, 1);

gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

<模型视图矩阵> = <视图矩阵> x <模型矩阵>进而演化成<模型视图矩阵> x <顶点坐标>在js中提前计算避免不必要的开销

js
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'uniform mat4 u_ModelViewMatrix;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = u_ModelViewMatrix * a_Position;\n' +
  '  v_Color = a_Color;\n' +
  '}\n';

var viewMatrix = new Matrix4();
viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0);

var modelMatrix = new Matrix4();
modelMatrix.setRotate(-10, 0, 0, 1);

// 使用矩阵库方法相乘
var modelViewMatrix = viewMatrix.multiply(modelMatrix);

gl.uniformMatrix4fv(u_ModelViewMatrix, false, modelViewMatrix.elements);
//...

可视范围正射类型

三维物体只有在可视范围之内时,WebGL才会绘制它,范围以外的对象并不会展示出来是降低程序开销的手段,人类也只能看到眼前水平视角大约200度左右,水平视角、垂直视角和可视深度定义了可视空间(view volume)

常见的可视空间:

  • <Primary>长方体可视空间</Primary>:也称盒状空间,由正射投影(orthographic projection)产生,由前后近裁剪面(near clipping plane)远裁剪面(far clipping plane)确定
  • <Primary>四棱锥/金字塔可视空间</Primary>:由透视投影(perspective projection)产生

可视空间透视投影

近大远小的深度感被称为透视感。在正射投影的可视空间中,不管三角形与视点的距离是远是近,它有多大,那么画出来的就有多大,为了打破这条限制可以使用透视投影可视空间,他将使场景具有深度感

在使用透视投影矩阵后,WebGL能够自动将距离远的物体缩小显示,从而产生深度感,透视投影可视空间也有视点、视线、近裁剪面和远裁剪面,这样空间内的物体才会被显示,可视空间外的物体则不会显示。那些跨越可视空间辩解的物体则只会显示其在可视空间内的部分