目录

WebGL2Fundamentals.org

Fix, Fork, Contribute

WebGL2 顶点索引

这篇文章假设你至少阅读了 关于基础的文章。 如果你没有读过,你应该从那里开始。

这是一篇短文,介绍 gl.drawElements。在 WebGL 中有两个基本的绘制函数。 gl.drawArraysgl.drawElements。 这个网站的文章中,大部分是调用 gl.drawArrays 的。

gl.drawElements 需要一个填充了顶点索引的缓存,然后以此来绘制。

举个例子,我们根据 第一篇文章 来绘制一个矩形,但使用 gl.drawElements

在那里的代码中,我们用两个三角形构建了一个矩形,每个三角形 3 个顶点,一共 6 个顶点。

这是提供 6 个顶点的代码:

var x1 = x
var x2 = x + width
var y1 = y
var y2 = y + height
gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
        x1,
        y1, // 顶点 0
        x2,
        y1, // 顶点 1
        x1,
        y2, // 顶点 2
        x1,
        y2, // 顶点 3
        x2,
        y1, // 顶点 4
        x2,
        y2 // 顶点 5
    ]),
    gl.STATIC_DRAW
)

我们可以使用 4 个顶点来代替:

var x1 = x
var x2 = x + width
var y1 = y
var y2 = y + height
gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
        x1,
        y1, // 顶点 0
        x2,
        y1, // 顶点 1
        x1,
        y2, // 顶点 2
        x2,
        y2 // 顶点 3
    ]),
    gl.STATIC_DRAW
)

但是,我们还需要添加一个存放索引的缓存。 因为 WebGL 必须要 6 个顶点来绘制两个三角形。

为了这么做,我们需要创建另一个缓存,但使用不同的绑定点。 我们使用 ELEMENT_ARRAY_BUFFER 而不是 ARRAY_BUFFER,它使用来存放索引的。

// 创建缓存
const indexBuffer = gl.createBuffer()

// 将这个缓存设置为当前 `ELEMENT_ARRAY_BUFFER`
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)

// 填充数据
const indices = [
    0,
    1,
    2, // 第一个三角形
    2,
    1,
    3 // 第二个三角形
]
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW)

像其它所有 WebGL 中的数据一样,我们需要指定索引的类型。 我们将用 new Uint16Array(indices) 将索引转换成无符号 16 位整型,然后传到缓存。

需要注意的是,与 ARRAY_BUFFER 绑定点不同是全局状态,ELEMENT_ARRAY_BUFFER 绑定点是当前顶点数组的一部分。

在代码中,我们创建并绑定了一个顶点数组,然后设置了索引缓冲区。 这意味着,就像属性一样,无论何时我们绑定这个顶点数组,索引缓冲区也将被绑定。 有关更多信息,请参阅 关于属性的文章

在绘制时,我们调用 drawElements

// 绘制矩形
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
-gl.drawArrays(primitiveType, offset, count);
+var indexType = gl.UNSIGNED_SHORT;
+gl.drawElements(primitiveType, count, indexType, offset);

我们得到了和之前一样的结果,但是只提供了 4 个顶点的数据,而不是 6 个。 尽管我们还是得告诉 WebGL 绘制 6 个顶点,但通过索引我们复用了 4 个顶点的数据。

是否使用这样使用数据取决与你。

值得注意的是,顶点索引不用来绘制含 8 个顶点位置的立方体, 因为通常你会将其它数据关联到每个顶点上,取决与顶点被用的那个面,数据会不一样。 例如,你想给立方体的每个面不一样的颜色,你需要提供每个位置的颜色。 所以,尽管每个顶点被用了 3 次,每个面访问顶点时都需要重复位置信息,每个面关联的不同颜色。 这意味着你需要 24 个顶点来绘制立方体,每个面 4 个,36 个索引来绘制需要的 12 个三角形。

Valid types for indexType above are gl.UNSIGNED_BYTE where you can only have indices from 0 to 255, in which case you'd use new Uint8Array(indices), gl.UNSIGNED_SHORT where the maximum index is 65535 which we used above, and gl.UNSIGNED_INT which has a maximum index of 4294967296 and where you'd use new Uint32Array(indices). 上面的 indexType 的有效类型是gl.UNSIGNED_BYTE索引只能是 0 到 255 之间,在这种情况下,使用 new Uint8Array(indices)gl.UNSIGNED_SHORT,最大索引为 65535,以及gl.UNSIGNED_INT 最大索引为 4294967296,也可以使用“new Uint32Array(indices)”。

有意见或建议? 在GitHub上提issue.
comments powered by Disqus