WebGL绘图

不羁岁月 提交于 2019-12-08 14:19:14

WebGL绘图

基本的几何图元有:三角形、线和点精灵,3D模型都是通过这些几何图元组成的。WebGL中有两个绘制图元的方法:gl.drawArrays()gl.drawElements()

图元

  • 三角形

    WebGL中绘制三角形有三种方式:gl.TRINGLES(独立三角形)gl.TRINGLE_STRIP(三角形带)glTRINGLE_FAN(三角形扇)

    对于一系列点(v0、v1、v2、......),独立的三角形每三个点组成一个三角形((v0,v1,v2)、(v2,v3,v4)、......);三角形带每次将当前三角形的后面两个顶点与下一个顶点组成三角形((v0,v1,v2)、(v1,v2,v3)、......);三角形扇除掉第一个顶点,后面的每两个顶点与第一个顶点组成三角形((v0,v1,v2)、(v0,v3,v4)、......)

  • 线

    WebGL中绘制线有三种方式:gl.LINES(独立线)gl.LINE_STRIP(线带)gl.LINE_LOOP(线环)

    对于一系列点(v0、v1、v2、......),独立线每两个点组成一条线((v0,v1)、(v2,v3)、......);线带每次将当前线的后面一个顶点与下一个顶点组成三角形((v0,v1)、(v1,v2)、......);线环与线带类似,线环最后一个顶点与第一个顶点相连。

  • 点精灵

    点精灵就只有一种类型:gl.POINTS。可以在顶点着色器中使用内置变量gl_PointSize设置点精灵的大小。

WebGL绘图方法

  1. drawArrays()

    void drawArrays(GLenum mode, GLint first, GLsizei count);
    • mode定义了所要渲染的图元类型
    • first定义数组的那个索引作为渲染的第一个索引
    • count定义需要使用的顶点数
  2. drawElements

    void drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset);
    • mode定义所要渲染的图元类型
    • count定义了绑定到gl.ELEMENT_ARRAY_BUFFER目标上的索引数
    • type定义了元素索引的类型,可指定的类型有gl.UNSIGNED_BYTEgl.UNSIGNED_SHORT
    • offset定义绑定到gl.ELEMENT_ARRAY_BUFFER目标的缓冲中的偏移量,索引从此处开始
  3. 退化三角形

    退化三角形是指三角形中至少有两个索引是相同的,因此退化三角形的面积为0.在绘制三角形带时,若多个三角形带之间存在不连续性,可以采用退化三角形的方式,添加额外的索引来保持三角形带的连续性。例如(v0,v1,v2)与(v3,v4,v5)不连续,可以在中间插入两个索引(v2,v3),从而构造四个退化三角形(v1,v2,v2)、(v2,v2,v3)、(v2、v3、v3)、(v3、v3、v4)。退化三角形会被GPU检测并删除。

类型化数组

Js中没有内置的二进制处理的功能,为了处理二进制数据,将二进制数据保持在长度固定的数组缓冲中

var buffer = new ArrayBuffer(8);

这样就得到一个8字节的缓冲。但无法直接对缓冲中数据进行处理,需要创建对应的视图。

var viewFloat32 = new Float32Array(buffer);
var viewUint16  = new Uint16Array(buffer);

分别创建了一个Float32的视图和Uint16格式的视图。Float32占4个字节,所以viewFloat32数组长度为2,数组的索引分别对应buffer的前4个字节区域和后四个字节区域。viewUint16数组的索引对应区域分割方法一致。

交叉存放顶点数据

顶点可能含有多种数据,例如位置、颜色等。对于致谢不同类型的数据,可以通过两种方式处理:

  • 把每类数据放到不同的WebGLBuffer中,被称为数组结构。
  • 把所有数据都放在一个WebGLBuffer中,被称为结构数组(交叉顶点数组)。

数组结构的使用:

例如要存储顶点的位置信息和颜色信息,则缓冲数组的格式为

顶点1 顶点2 顶点3
(x,y,z,r,g,b,a) (x,y,z,r,g,b,a) (x,y,z,r,g,b,a)

首先计算一个顶点占多少个字节:3*4+4*1=16。为顶点分配空间并创建颜色和位置的视图

var buffer = new ArrayBuffer(16*count); // 每个顶点占字节数*顶点数
var positionView = new Float32Array(buffer);
var colorView = new Uint8Array(buffer);

写数据的时候通过视图写数据

var i,k;
var positionInFloats = 0;       // 按照Float32格式划分缓冲的索引
var positionInBytes  = 12;      // 按照Uint8格式划分缓冲的索引
for(i=0,k=0;i<count;i++){
    positionView[0+positionInFloats] = data[k++];
    positionView[1+positionInFloats] = data[k++];
    positionView[3+positionInFloats] = data[k++];
    colorView[0+positionInBytes] = data[k++];
    colorView[1+positionInBytes] = data[k++];
    colorView[2+positionInBytes] = data[k++];
    colorView[3+positionInBytes] = data[k++];
    positionInFloats += 4;
    positionInBytes += 16;
}

绑定缓冲数据

var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!