ArrayBuffer
撰写时间:2023-08-06
修订时间:2026-04-08
VBO中存储的数据类型为ArrayBufferView,它是ArrayBuffer的视图。
关于ArrayBuffer,详见本站的ArrayBuffer。
在本章中,我们结合WebGL应用的特性,初步讨论相关内容。
ArrayBuffer
ArrayBuffer是一个通用的、固定长度的二进制缓冲区。它是由多个字节的数据所组成的数组。
ArrayBuffer有一个byteLength属性,代表该对象的字节长度,即多少字节。上面的构造函数,创建了一个字节长度为0的实例。
我们可以在ArrayBuffer的构造函数中传入一个表示字节的数值,以创建一个特定长度的实例。其数据被初始化为相应的0值。
视图
不能直接访问ArrayBuffer的中的数据。因此,如果我们试图查看其内容,将显示undefined:
在Chrome浏览器中运行以下代码:
将在浏览器的Console中输出:
可以看到,对于2个字节的ArrayBuffer,可以由2个Int8Array构成、或2个Uint8Array构成、或1个Int16Array构成。这类似于C语言中使用一个char指针指向一个int的数据类型,以便独立地访问int变量中的每个字节。
我们将上面的Int8Array、Uint8Array、Int16Array这些类型化数组称为ArrayBuffer的视图(view)。也就是说,对于同一个数据,可以根据需求,使用不同的视图将其内在数据转换为不同的数据类型,并依视图的格式进行读写。
注:还有另外一种称为DataView的视图,提供了以特定字长读取或设置缓冲区数据的方法,但由于这种需求较少,故本章不涉及该类的内容。
下面,我们通过类型化数组Uint8Array来访问ArrayBuffer:
我们取Uint8Array为视图。由于buffer的字长为2,而一个Uint8Array的字长为1,因此buffer的内容依此视图被分为元素为[0, 1]两个元素的数组。view的byteOffset为0,表示当前指针前向buffer的第0个字节;length为2,对应于view这个对象共有2个元素。
类型化数组
上面可以看出,视图Uint8Array的原型是TypedArray。
类型化数组 (typed array) 是一种类似于数组的视图,用于表现其所包含的二进制的数据缓冲区。
各种类型化数组
类型化数组共有12种,详见下表。
| 类名 | 值域 | 字长 | Web IDL |
|---|---|---|---|
| Int8Array | [-128, 127] | 1 | byte |
| Uint8Array | [0, 255] | 1 | octet |
| Uint8ClampedArray | [0, 255] | 1 | octet |
| Int16Array | [-32768, 32767] | 2 | short |
| Uint16Array | [0, 65535] | 2 | unsigned short |
| Int32Array | [-2147483648, 2147483647] | 4 | long |
| Uint32Array | [0, 4294967295] | 4 | unsigned long |
| Float16Array | [-65504, 65504] | 2 | N/A |
| Float32Array | [-3.4E38, 3.4E38] | 4 | unrestricted float |
| Float64Array | [-1.8E308, 1.8E308] | 8 | unrestricted double |
| BigInt64Array | [-263, 263-1] | 8 | bigint |
| BigUint64Array | [0, 264-1] | 8 | bigint |
从值域来看,WebGL应用中,对于表示顶点位置、顶点颜色等浮点数值,一般使用Float32Array即可;对于顶点索引,一般使用Uint16Array即可。
构造函数
类型化数组共有4种构造函数。
指定元素个数的构造函数
在构造函数中传入一个整数,以指定数组的元素个数。
注意细微的区别。ArrayBuffer的构造器参数表示字节数,而类型化数组构造器的参数表示元素个数。这是因为ArrayBuffer没有涉及具体的数据类型,无法表示共有多少个特定类型的元素,因此只能用总共的字节数来表示。而对于每种类型化数组,其属性BYTES_PER_ELEMENT已含有每个元素多少字节的信息,因此,只要指定共有多少个元素,就能计算出总的字节长度。
上面的代码new Int8Array(8)创建了一个共有8个元素的Int8Array数组,每个元素的字长为1字节,因此其byteLength等于1 * 8 = 8个字节。
代码new Int16Array(8)创建了一个共有8个元素的Int16Array数组,每个元素的字长为2字节,因此其byteLength等于2 * 8 = 16个字节。
因此,对于一个特定的类型化数组ta,其byteLength表示该类型化数组共占用多少个字节,其与length(数组元素数量)与BYTES_PER_ELEMENT(每个数组元素所占用的字节数)的公式如下:
指定数组数据的构造函数
在构造函数中传入一个数组,以作为类型化数组的内容。
我们之前的例子使用最多的就是这种方式。
指定其他类型化数组的构造函数
在构造函数中传入另一个类型化数组。
对于这种方式,两个类型化数组的元素数量及其数据一致,但由于各自的BYTES_PER_ELEMENT不一样,导致最后的byteLength不一样。
指定ArrayBuffer的构造函数
这种方式,是以2种类型化数组的视图来共享同一个数据缓冲区。
