首页 > 解决方案 > 使用 RGB 格式在 WebGL 中创建纹理时出错

问题描述

尝试从具有 RGBA 格式的数据创建 1px x 4px 纹理,如下所示:

const texture = gl.createTexture()
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
  255, 0, 0, 255,
  0, 255, 0, 255,
  0, 0, 255, 255,
  255, 255, 0, 255
]))
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)

但是尝试对 RGB 格式执行相同的操作,如下所示:

const texture = gl.createTexture()
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 4, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array([
  255, 0, 0,
  0, 255, 0,
  0, 0, 255,
  255, 255, 0
]))
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)

在 Firefox 中出现此错误:

错误:WebGL 警告:texImage2D:所需上传的数据比可用数据多:(需要 3 行加 1 个像素,可用 3 行加 0 个像素)

Chrome中的这个错误:

WebGL:INVALID_OPERATION:texImage2D:ArrayBufferView 不够大,无法请求

交换 gl.texImage2D 的宽度和高度参数,这样我就有了一个 4px x 1px 的纹理,然后可以使用 gl.RGB,但是 2px x 2px 的纹理没有。我在这里做错了什么/误解了什么?

标签: javascriptwebgl

解决方案


由于 WebGL 1.0 基于 OpenGL ES 2.0 API,我将参考OpenGL ES 2.0 refpagesglPixelStorei

GL_UNPACK_ALIGNMENT

指定内存中每个像素行开头的对齐要求。允许的值为 1(字节对齐)、2(与偶数字节对齐的行)、4(字对齐)和 8(行从双字边界开始)。

UNPACK_ALIGNMENT对齐参数的初始值为4。

如果指定宽度为 4 像素的 RGB 纹理,则 3 * 4 = 12 字节中的一行大小。
如果纹理的高度为 1,则纹理的预期大小为 12 * 1 = 12。

但是,如果您指定 RGB 纹理的像素为 1,则 3 * 1 = 3 字节中的一行大小。
如果UNPACK_ALIGNMENT是 4,那么这个大小对齐到 4 个字节。
如果纹理的高度为 4,则纹理的预期大小为 4*4 = 16 字节。

第二种情况与用于初始化纹理的数据数组不匹配,这会导致错误。

要解决这个问题,您必须将纹理的每一行对齐到 4 个字节:

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 4, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array([
    255, 0,   0,   0, // add 1 byte for alignment to 4 bytes
    0,   255, 0,   0, // add 1 byte
    0,   0,   255, 0, // add 1 byte
    255, 255, 0,   0  // add 1 byte
]))

或通过以下方式将gl.UNPACK_ALIGNMENT参数设置为 1 gl.pixelStorei

gl.pixelStorei( gl.UNPACK_ALIGNMENT, 1 )
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 4, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array([
    255, 0,   0,
    0,   255, 0,
    0,   0,   255,
    255, 255, 0
]))

推荐阅读