创建WebGL纹理时从颜色缓冲区更新失败问题排查
问题背景
我有一个WebGL纹理,最初用图像像素填充。现在想用颜色数组清空它,编写了createGLTexture函数创建2D纹理,但传入颜色数据时触发错误:
Uncaught TypeError: Failed to execute 'texSubImage2D' on 'WebGL2RenderingContext': Overload resolution failed.at createGLTexture
但使用updateGLTexture函数在纹理创建后更新颜色却能成功实现蓝色清空,疑惑为何创建时调用texSubImage2D失败,两者调用逻辑是否存在差异?
创建纹理函数代码
function createGLTexture(gl, format,intFormat, w, h,wrapType, flip, genMipmaps, data) { var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flip); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,wrapType); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,wrapType); if (genMipmaps === true) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); gl.texStorage2D(gl.TEXTURE_2D, 1, intFormat, w, h); } else { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texStorage2D(gl.TEXTURE_2D, 1, intFormat, w, h); } if (data != null) { gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, format, gl.UNSIGNED_BYTE, data); } if (genMipmaps === true) { gl.generateMipmap(gl.TEXTURE_2D); } return texture; }
初始化颜色代码
//img - 已预加载的图像 var colorData = new Uint8Array(img.width * img.height * 3); for(var i = 0; i < colorData.length;i+=3) { colorData[i] = 0; colorData[i + 1] = 0; colorData[i + 2] = 255; } var tex = createGLTexture(gl,gl.RGB,gl.RGB8,img.width,img.height,gl.CLAMP_TO_EDGE,false,false,colorData);
更新纹理函数代码
function updateGLTexture(gl,texture, format,w,h, genMipmaps, data) { gl.bindTexture(gl.TEXTURE_2D, texture); gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0,w,h, format, gl.UNSIGNED_BYTE, data); if (genMipmaps === true) { gl.generateMipmap(gl.TEXTURE_2D); } gl.bindTexture(gl.TEXTURE_2D, null); }
核心原因:参数缺失导致重载不匹配
你在createGLTexture中调用texSubImage2D时,缺少了宽度和高度参数,而updateGLTexture中的调用参数是完整的。
WebGL2中,当使用TypedArray作为像素数据时,texSubImage2D的正确参数顺序必须包含更新区域的宽高:
gl.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
createGLTexture里的调用跳过了width和height,导致WebGL无法匹配到正确的API重载,触发类型错误;而updateGLTexture中传入了w和h,参数完全匹配,因此执行成功。
解决方案
修改createGLTexture中texSubImage2D的调用,补充宽高参数:
if (data != null) { gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, w, h, format, gl.UNSIGNED_BYTE, data); }
额外说明
即便已经通过texStorage2D为纹理分配了存储空间,使用TypedArray更新纹理时,texSubImage2D仍需明确指定宽高参数——这是WebGL2 API的强制要求,与纹理是否已初始化存储空间无关。
内容的提问来源于stack exchange,提问作者Michael IV

