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
]; 
Geometry

类似地,您可以为索引创建一个数组。上述三角形索引的索引将为 [0, 1, 2],可以定义为 −

var indices = [ 0,1,2 ]

为了更好地理解索引,请考虑更复杂的模型,例如正方形。我们可以将正方形表示为一组两个三角形。如果 (0,3,1) 和 (3,1,2) 是我们打算用来绘制正方形的两个三角形,则索引将定义为 −

var indices = [0,3,1,3,1,2];
Geometry Example

注意

对于绘制图元,WebGL 提供了以下两种方法 −

  • drawArrays() − 使用此方法时,我们使用 JavaScript 数组传递图元的顶点。

  • drawElements() − 使用此方法时,我们使用 JavaScript 数组传递图元的顶点和索引。

缓冲区对象

缓冲区对象是 WebGL 提供的一种机制,用于指示系统中分配的内存区域。在这些缓冲区对象中,您可以存储要绘制的模型的数据,对应于顶点、索引、颜色等。

使用这些缓冲区对象,您可以通过着色器程序(顶点着色器)的属性变量之一将多个数据传递给着色器程序。由于这些缓冲区对象驻留在 GPU 内存中,因此可以直接渲染它们,从而提高性能。

要处理几何图形,有两种类型的缓冲区对象。它们是 −

  • 顶点缓冲区对象 (VBO) − 它保存要渲染的图形模型的每个顶点数据。我们在 WebGL 中使用顶点缓冲区对象来存储和处理有关顶点的数据,例如顶点坐标、法线、颜色和纹理坐标。

  • 索引缓冲区对象 (IBO) −它保存将要渲染的图形模型的索引(索引数据)。

定义所需的几何图形并将其存储在 JavaScript 数组中后,您需要将这些数组传递给缓冲区对象,然后从缓冲区对象将数据传递给着色器程序。要将数据存储在缓冲区中,请遵循以下步骤。

  • 创建一个空缓冲区。

  • 将适当的数组对象绑定到空缓冲区。

  • 使用其中一个类型化数组将数据(顶点/索引)传递给缓冲区。

  • 取消绑定缓冲区(可选)。

创建缓冲区

要创建一个空缓冲区对象,WebGL 提供了一种名为 createBuffer() 的方法。如果创建成功,此方法将返回一个新创建的缓冲区对象;否则,如果创建失败,则返回一个空值。

WebGL 作为状态机运行。一旦创建了缓冲区,任何后续的缓冲区操作都将在当前缓冲区上执行,直到我们解除绑定。使用以下代码创建缓冲区 −

var vertex_buffer = gl.createBuffer();

注意gl 是当前 WebGL 上下文的引用变量。

绑定缓冲区

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

语法

bindBuffer() 方法的语法如下 −

void bindBuffer (enum target, Object buffer)

此方法接受两个参数,下面将对其进行讨论。

target − 第一个变量是一个枚举值,表示我们要绑定到空缓冲区的缓冲区类型。您有两个预定义的枚举值作为此参数的选项。它们是 −

  • ARRAY_BUFFER 表示顶点数据。

  • ELEMENT_ARRAY_BUFFER 表示索引数据。

对象缓冲区 − 第二个是上一步中创建的缓冲区对象的引用变量。引用变量可以是顶点缓冲区对象或索引缓冲区对象。

示例

以下代码片段显示了如何使用 bindBuffer() 方法。

//顶点缓冲区
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_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 −第一个参数是一个枚举值,表示我们使用的数组缓冲区的类型。此参数的选项为 −

  • ARRAY_BUFFER,表示顶点数据

  • ELEMENT_ARRAY_BUFFER,表示索引数据

对象数据 − 第二个参数是包含要写入缓冲区对象的数据的对象值。这里我们必须使用类型化数组传递数据。

用法 − 此方法的第三个参数是一个枚举变量,用于指定如何使用缓冲区对象数据(存储的数据)来绘制形状。此参数有三个选项,如下所示。

  • gl.STATIC_DRAW − 数据将被指定一次并使用多次。

  • gl.STREAM_DRAW − 数据将被指定一次并使用几次。

  • gl.DYNAMIC_DRAW − 数据将被重复指定并使用多次。

示例

以下代码片段显示如何使用 bufferData() 方法。假设顶点和索引分别是保存顶点和索引数据的数组。

//顶点缓冲区
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

//索引缓冲区
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 数组一样。

解除缓冲区的绑定

建议您在使用缓冲区后解除缓冲区的绑定。可以通过传递一个 null 值代替缓冲区对象来完成,如下所示。

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

WebGL 提供以下方法来执行缓冲区操作 −

Sr.No. 方法和说明
1

void bindBuffer (enum target, Object buffer)

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 (enum target, Object data, enum usage)

targetusage − 与上面的 bufferData 相同

4

void bufferSubData(enum target, long offset, Object data)

target − ARRAY_BUFFER,ELEMENT_ARRAY_BUFFER

5 Object createBuffer()
6 void deleteBuffer(Object buffer)
7

any getBufferParameter(enum target, enum pname)

target − ARRAY_BUFFER,ELEMENT_ ARRAY_BUFFER

pname − BUFFER_SIZE,BUFFER_USAGE

8 bool isBuffer(Object buffer)