在WebGL中以RGB格式创建纹理时出错

时间:2018-07-29 16:22:05

标签: javascript 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的width和height参数,所以我有一个4px x 1px的纹理,然后可以与gl.RGB一起使用,但是2px x 2px的纹理则不能。我在这里出什么毛病/误解了?

1 个答案:

答案 0 :(得分:2)

由于WebGL 1.0基于OpenGL ES 2.0 API,因此我将引用OpenGL ES 2.0 refpages glPixelStorei

  

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.pixelStoreigl.UNPACK_ALIGNMENT参数设置为1:

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
]))