WebGL异步/顺序绘制纹理时旧纹理消失问题求助
解决WebGL绘制新纹理时旧纹理消失的问题
问题根源
WebGL是即时渲染模式,默认每次绘制前若执行gl.clear(gl.COLOR_BUFFER_BIT)会清空整个颜色缓冲区,导致之前的绘制内容丢失;另外如果绘制逻辑未限制渲染区域,新纹理会覆盖整个画布,也会造成旧内容消失。
具体解决方案
1. 仅初始化时清除画布
把画布清除操作移到初始化阶段,后续绘制新纹理时不再执行清除:
// 初始化函数(仅执行一次) function initWebGL() { const gl = canvas.getContext('webgl'); // 设置清除颜色并清空画布 gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); // 开启混合(若图片带透明通道,保证叠加效果) gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); // 其他初始化:编译着色器、创建缓冲区等 return gl; } // 绘制单张纹理的函数(每张图片加载完成后调用) function drawTexture(gl, texture, x, y, width, height) { // 绑定目标纹理 gl.bindTexture(gl.TEXTURE_2D, texture); // 传递纹理位置、尺寸等参数给着色器 const program = gl.getParameter(gl.CURRENT_PROGRAM); gl.uniform2f(gl.getUniformLocation(program, 'u_position'), x, y); gl.uniform2f(gl.getUniformLocation(program, 'u_size'), width, height); // 绘制纹理对应的四边形 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); }
2. 通过着色器限制渲染区域
修改顶点着色器,确保新纹理仅渲染到指定位置,不覆盖整个画布:
attribute vec2 a_position; // 纹理局部坐标(0,0)到(1,1) attribute vec2 a_texCoord; uniform vec2 u_resolution; // 画布分辨率 uniform vec2 u_position; // 纹理左上角像素位置 uniform vec2 u_size; // 纹理像素尺寸 varying vec2 v_texCoord; void main() { // 将局部坐标转换为WebGL裁剪空间坐标(-1到1) vec2 pixelPos = u_position + a_position * u_size; vec2 clipSpace = (pixelPos / u_resolution) * 2.0 - 1.0; clipSpace.y = -clipSpace.y; // 翻转Y轴,匹配画布坐标系 gl_Position = vec4(clipSpace, 0.0, 1.0); v_texCoord = a_texCoord; }
3. 异步加载与叠加绘制流程
每张图片加载完成后创建纹理,调用绘制函数叠加到画布对应位置:
const imageUrls = ['img1.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg']; const positions = [[0,0], [200,0], [0,200], [200,200]]; // 四张图的拼接位置 imageUrls.forEach((url, index) => { const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { // 创建并配置WebGL纹理 const texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); // 绘制到指定位置 const [x, y] = positions[index]; drawTexture(gl, texture, x, y, img.width, img.height); }; img.src = url; });
关键注意点
- 禁止在每次绘制前调用
gl.clear,仅初始化时执行一次。 - 若使用透明图片,必须开启混合模式保证叠加效果。
- 着色器需正确计算纹理渲染位置,避免覆盖整个画布。
内容的提问来源于stack exchange,提问作者Seth Lutske
相关产品推荐
相关产品推荐

