WebGL - 几何

  • 简述

    获得 WebGL 上下文后,您必须为图元(要绘制的对象)定义几何并存储它。在 WebGL 中,我们使用 JavaScript 数组定义几何的细节——例如,顶点、索引、基元的颜色。要将这些细节传递给着色器程序,我们必须创建缓冲区对象并将包含数据的 JavaScript 数组存储(附加)到相应的缓冲区中。
    注意:稍后,这些缓冲区对象将与着色器程序(顶点着色器)的属性相关联。
  • 定义所需的几何形状

    使用顶点绘制的 2D 或 3D 模型称为网格。网格中的每个面都称为多边形,多边形由 3 个或更多顶点组成。
    要在 WebGL 渲染上下文中绘制模型,您必须使用 JavaScript 数组定义顶点和索引。例如,如果我们想创建一个位于坐标 {(5,5), (-5,5), (-5,-5)} 上的三角形,如图所示,那么您可以创建一个数组顶点为 -
    
    var vertices = [
       0.5,0.5,    //Vertex 1
       0.5,-0.5,   //Vertex 2
       -0.5,-0.5,  //Vertex 3
    ]; 
    
    几何学
    同样,您可以为索引创建一个数组。上述三角形索引的索引将为 [0, 1, 2] 并且可以定义为 -
    
    var indices = [ 0,1,2 ]
    
    为了更好地理解指数,请考虑更复杂的模型,如 square。我们可以将正方形表示为一组两个三角形。如果 (0,3,1) 和 (3,1,2) 是我们打算用来绘制正方形的两个三角形,那么索引将定义为 -
    
    var indices = [0,3,1,3,1,2];
    
    几何示例
    注意-
    对于绘图基元,WebGL 提供了以下两种方法 -
    • drawArrays() - 在使用此方法时,我们使用 JavaScript 数组传递图元的顶点。
    • drawElements() - 在使用此方法时,我们使用 JavaScript 数组传递图元的顶点和索引。
  • 缓冲对象

    缓冲区对象是WebGL提供的一种机制,表示系统中分配的内存区域。在这些缓冲区对象中,你可以存储你要绘制的模型的数据,对应顶点、索引、颜色等。
    使用这些缓冲区对象,您可以通过其属性变量之一将多个数据传递给着色器程序(顶点着色器)。由于这些缓冲区对象驻留在 GPU 内存中,因此可以直接渲染它们,从而提高性能。
    要处理几何图形,有两种类型的缓冲区对象。他们是 -
    • Vertex buffer object (VBO) - 它保存将要呈现的图形模型的每个顶点数据。我们在 WebGL 中使用顶点缓冲对象来存储和处理有关顶点的数据,例如顶点坐标、法线、颜色和纹理坐标。
    • Index buffer objects (IBO) - 它包含将要呈现的图形模型的索引(索引数据)。
    在定义了所需的几何图形并将它们存储在 JavaScript 数组中之后,您需要将这些数组传递给缓冲区对象,数据将从那里传递给着色器程序。将遵循以下步骤将数据存储在缓冲区中。
    • 创建一个空缓冲区。
    • 将适当的数组对象绑定到空缓冲区。
    • 使用类型化数组之一将数据(顶点/索引)传递到缓冲区。
    • 取消绑定缓冲区(可选)。
  • 创建缓冲区

    为了创建一个空的缓冲区对象,WebGL 提供了一个名为createBuffer()的方法。如果创建成功,该方法返回一个新创建的缓冲区对象;否则它在失败的情况下返回空值。
    WebGL 作为状态机运行。创建缓冲区后,任何后续缓冲区操作都将在当前缓冲区上执行,直到我们解除绑定。使用以下代码创建缓冲区 -
    
    var vertex_buffer = gl.createBuffer();
    
    注意- gl是当前 WebGL 上下文的引用变量。
  • 绑定缓冲区

    创建空缓冲区对象后,您需要将适当的数组缓冲区(target)绑定到它。WebGL 为此提供了一个名为bindBuffer()的方法。

    句法

    bindBuffer()方法的语法如下:
    
    void bindBuffer (enum target, Object buffer)
    
    此方法接受两个参数,它们将在下面讨论。
    target - 第一个变量是一个enum值,表示我们要绑定到空缓冲区的缓冲区类型。您有两个预定义的enum值作为此参数的选项。他们是 -
    • ARRAY_BUFFER表示顶点数据。
    • ELEMENT_ARRAY_BUFFER表示索引数据。
    对象缓冲区- 第二个是在上一步中创建的缓冲区对象的引用变量。引用变量可以是顶点缓冲区对象或索引缓冲区对象。

    例子

    以下代码片段显示了如何使用 bindBuffer() 方法。
    
    //vertex buffer
    var vertex_buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
    //Index buffer
    var Index_Buffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
    
  • 将数据传递到缓冲区

    下一步是将数据(顶点/索引)传递到缓冲区。到目前为止,数据都是数组形式,在将其传递到缓冲区之前,我们需要将其包装在 WebGL 类型数组之一中。WebGL 为此提供了一个名为bufferData()的方法。

    句法

    bufferData() 方法的语法如下:
    
    void bufferData (enum target, Object data, enum usage)
    
    该方法接受三个参数,它们将在下面讨论 -
    target - 第一个参数是一个enum值,表示我们使用的数组缓冲区的类型。此参数的选项是 -
    • ARRAY_BUFFER表示顶点数据
    • ELEMENT_ARRAY_BUFFER表示索引数据
    对象数据- 第二个参数是包含要写入缓冲区对象的数据的对象值。这里我们必须使用类型化数组传递数据。
    usage- 此方法的第三个参数是一个enum变量,指定如何使用缓冲区对象数据(存储的数据)绘制形状。此参数有三个选项,如下所列。
    • gl.STATIC_DRAW - 数据将被指定一次并多次使用。
    • gl.STREAM_DRAW - 数据将被指定一次并使用几次。
    • gl.DYNAMIC_DRAW - 数据将被重复指定并多次使用。

    例子

    以下代码片段显示了如何使用bufferData()方法。假设顶点和索引是分别保存顶点和索引数据的数组。
    
    //vertex buffer
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    //Index buffer
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    
  • 类型数组

    WebGL 提供了一种特殊类型的数组,称为类型化数组,用于传输索引顶点和纹理等数据元素。这些类型化数组存储大量数据并以本机二进制格式处理它们,从而提高性能。WebGL 使用的类型数组是 Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、UInt32Array、Float32Array 和 Float64Array。
    笔记
    • 通常,为了存储顶点数据,我们使用Float32Array;为了存储索引数据,我们使用Uint16Array
    • 您可以使用new关键字创建类型化数组,就像 JavaScript 数组一样。
  • 解除绑定缓冲区

    建议您在使用缓冲区后解除绑定。可以通过传递空值代替缓冲区对象来完成,如下所示。
    
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    
    WebGL 提供了以下方法来执行缓冲区操作 -
    序号 方法与说明
    1
    void bindBuffer(enumtarget,Objectbuffer
    target- ARRAY_BUFFER,ELEMENT_ARRAY_BUFFER
    2
    void bufferData(enum target、long size、enum usage
    target- ARRAY_BUFFER,ELEMENT_ARRAY_BUFFER
    usage- STATIC_DRAW,STREAM_DRAW,DYNAMIC_DRAW
    3
    void bufferData(enumtarget,Object data,enumusage
    targetusage- 与上面的bufferData相同
    4
    void bufferSubData(enumtarget,long offset,Objectdata
    target- ARRAY_BUFFER,ELEMENT_ARRAY_BUFFER
    5 ObjectcreateBuffer()
    6 void deleteBuffer(Objectbuffer
    7
    anygetBufferParameter(enumtarget,enumpname
    target- ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER
    pname - BUFFER_SIZE, BUFFER_USAGE
    8 bool isBuffer(Objectbuffer