WebGL(四)初入三维世界

在说完矩阵相关的知识后,就可以进入三维世界了。三维世界有两个很基本的东西:
相机:

  • 正交相机就是 正交投影矩阵 * 视图矩阵 * 物体顶点
  • 透视相机就是 透视投影矩阵 * 视图矩阵 * 物体顶点

三维物体:本文就说正方形的绘制,三维物体都是由三角形组成的,两个三角形组成一个面,六个面组成一个正方体,相信大家都知道了。

本文相关的代码在链接的ch7文件夹。

正方体绘制

采用另外一种绘制方式gl.drawElements(),它与之前的gl.drawArrays(),不同,能够避免重复定义顶点,保持顶点数最小。不过,这个新引进一个概念就是,索引,它和数组中的索引概念类似,顶点存在数组中,通过顶点索引写入缓存区,绑定到gl.ELEMENT_ARRAY_BUFFER上。使用方法类似于gl.drawArrays()。

void gl.drawElements(mode, count, type, offset);
参数

  • mode
    这个和gl.drawArrays()的模式一样,分别有七种类型:gl.POINTS、gl.LINE_STRIP、gl.LINE_LOOP、gl.LINES、gl.TRIANGLE_STRIP、gl.TRIANGLE_FAN、gl.TRIANGLES。

  • count

整数型 指定要渲染的元素数量.

  • type

枚举类型 指定元素数组缓冲区中的值的类型。可能的值是:
gl.UNSIGNED_BYTE
gl.UNSIGNED_SHORT
当使用 OES_element_index_uint 扩展时:
gl.UNSIGNED_INT

  • offset

字节单位 指定元素数组缓冲区中的偏移量。必须是给定类型大小的有效倍数.

function initVertexBuffers(gl) {
  // Create a cube
  //    v6----- v5
  //   /|      /|
  //  v1------v0|
  //  | |     | |
  //  | |v7---|-|v4
  //  |/      |/
  //  v2------v3
  var verticesColors = new Float32Array([
    // 顶点坐标和颜色
     1.0,  1.0,  1.0,     1.0,  1.0,  1.0,  // v0 White
    -1.0,  1.0,  1.0,     1.0,  0.0,  1.0,  // v1 Magenta
    -1.0, -1.0,  1.0,     1.0,  0.0,  0.0,  // v2 Red
     1.0, -1.0,  1.0,     1.0,  1.0,  0.0,  // v3 Yellow
     1.0, -1.0, -1.0,     0.0,  1.0,  0.0,  // v4 Green
     1.0,  1.0, -1.0,     0.0,  1.0,  1.0,  // v5 Cyan
    -1.0,  1.0, -1.0,     0.0,  0.0,  1.0,  // v6 Blue
    -1.0, -1.0, -1.0,     0.0,  0.0,  0.0   // v7 Black
  ]);

  // 顶点索引
  var indices = new Uint8Array([
    0, 1, 2,   0, 2, 3,    // front
    0, 3, 4,   0, 4, 5,    // right
    0, 5, 6,   0, 6, 1,    // up
    1, 6, 7,   1, 7, 2,    // left
    7, 4, 3,   7, 3, 2,    // down
    4, 7, 6,   4, 6, 5     // back
 ]);

  // 创建缓冲区对象
  var vertexColorBuffer = gl.createBuffer();
  var indexBuffer = gl.createBuffer();
  if (!vertexColorBuffer || !indexBuffer) {
    return -1;
  }

  //将顶点坐标和颜色写入缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);

  var FSIZE = verticesColors.BYTES_PER_ELEMENT;
  // 将缓冲区顶点数据分配给a_Position 并开启
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if(a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
  gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
  gl.enableVertexAttribArray(a_Position);
   // 将缓冲区颜色数据分配给a_Color并开启
  var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  if(a_Color < 0) {
    console.log('Failed to get the storage location of a_Color');
    return -1;
  }
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
  gl.enableVertexAttribArray(a_Color);

  // 将顶点索引数据写入缓冲区对象
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

  return indices.length;
}
......
//绘制立方体
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

在这里插入图片描述

三维物体的前后关系处理

在真实世界中,如果把盒子一前一后放置在桌子上的话,前面的盒子会挡住部分后面的盒子。但在WebGL默认情况下,不是如此,为了加快绘图,是按照顶点在缓冲区中的顺序来处理它们的,只有先定义远的物体,再定义近的物体,才能产生正确的效果。

隐藏面消除

为了解决上个问题,WebGL提供了隐藏面消除功能。它会帮助我们消除那些被遮挡的表面(隐藏面),这样不用考虑顶点在缓冲区中的顺序,远处的物体自动会被近处的物体遮挡。

  1. 开启隐藏面消除功能
gl.enable(gl.DEPTH_TEST);
  1. 在绘制之前,清除深度缓冲区
gl.clear(gl.DEPTH_BUFFER_BIT);
深度冲突

当两个几何图形或者是两个表面特别接近(比如两个三角形X、Y接近,Z值完全相同)的时候,会出现新的问题,使得表面看起来斑斑驳驳的,这种现象称为深度冲突。WebGL提供一种被称为多边形偏移的机制来解决这个问题。该机制将自动在Z值加上一个偏移量,偏移量的值有物体表面相对观察值视线的角度来确定。

  1. 启动多边形偏移
gl.enable(gl.POLYGON_OFFSET_FILL),;
  1. 在绘制之前指定用来计算偏移量的参数
gl.polygonOffset(1.0,1.0);

以上只是很简单的三维世界,光照,阴影还有其他各种效果,我们都没有考虑,道路艰且长啊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值