texImage2D 接受什么样的数据?

What kind of data does texImage2D accept?

我想使用 WebGL 将一些矩阵计算卸载到片段着色器。

我正在尝试使用 texImage2D 将我的矩阵作为 RGB 二维纹理发送,但我不知道必须如何格式化数据。

我试过这个(对于 2x2 正方形矩阵):

var textureData = new Uint8Array([
  0, 0, 0,  1, 0, 0,
  2, 0, 0,  3, 0, 0
]);
//...
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
  textureData);

但我收到以下错误:

Uncaught TypeError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': No function was found that matched the signature provided.

I'm trying to send my matrix as an RGB 2D texture

恐怕 UNSIGNED_BYTE 无法提供足够的精度,您可能需要使用 OES_texture_float 扩展并将您的纹理创建为浮点纹理。

I don't know how the data must be formated

texImage2D 的可用签名可以在 spec:

中找到
void texImage2D(
    GLenum target,
    GLint level,
    GLint internalformat,
    GLsizei width,
    GLsizei height,
    GLint border,
    GLenum format,
    GLenum type,
    ArrayBufferView? pixels
);

void texImage2D(
    GLenum target,
    GLint level,
    GLint internalformat,
    GLenum format,
    GLenum type,
    TexImageSource? source
);

其中 TexImageSource 类型

ImageBitmap
ImageData
HTMLImageElement
HTMLCanvasElement
HTMLVideoElement

如果您想从像 Uint8Array 这样的类型数组上传数据,您需要使用带有类型数组的 texImage2D 版本。

那个是

void texImage2D(
    GLenum target,
    GLint level,
    GLint internalformat,
    GLsizei width,
    GLsizei height,
    GLint border,
    GLenum format,
    GLenum type,
    ArrayBufferView? pixels
);

您还应该知道,WebGL 和 OpenGL 一样默认将 UNPACK_ALIGNMENT 设置为 4 个字节,这意味着 pixels/texels 的每一行都必须是 4 个字节的倍数。您可以通过调用

将其更改为 1 个字节
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);

我之所以提出这个问题,是因为您要上传一个每个像素 3 个字节的 RGB/UNSIGNED_BYTE 纹理,这意味着如果您上传一个 2x2 像素纹理,则每行是 6 个字节。 WebGL 会将其填充为 8 个字节,因此它将期望一个 14 字节长的缓冲区(第一行仅使用前 6 个字节为 8 个字节,最后一行为 6 个字节。它不关心填充最后一行。如果您将 UNPACK_ALIGNMENT 设置为 1 然后该问题就消失了。

顺便说一句,你可以说它应该默认为 1,但 WebGL 遵循 OpenGL,在 OpenGL 中它默认为 4。