使用pixelStorei与texImage2D实现精灵动画时最后一行出现异常色边
WebGL精灵动画4×4纹理最后一行颜色边缘问题排查与解决
问题描述
- 实现的WebGL精灵动画整体可用,采用4×4纹理布局
- 仅当纹理坐标的YY值为3(对应最后一行帧)时,出现奇怪的颜色边缘
- 怀疑与透明度相关,已参考相关方案仍未解决
核心代码片段
顶点着色器
attribute vec2 a_position; attribute vec2 a_texCoord; varying vec2 v_texCoord; void main() { gl_Position = vec4(a_position, 0.0, 1.0); v_texCoord = a_texCoord; }
片段着色器
precision mediump float; uniform sampler2D u_texture; varying vec2 v_texCoord; uniform vec2 u_frameSize; // 单帧大小:1/4, 1/4 uniform vec2 u_frameOffset; // 当前帧偏移:(xx/4, yy/4) void main() { vec2 texCoord = v_texCoord * u_frameSize + u_frameOffset; vec4 color = texture2D(u_texture, texCoord); // 透明度裁剪 if (color.a < 0.1) { discard; } gl_FragColor = color; }
动画控制代码(JS)
const frameCount = 16; // 4×4共16帧 let currentFrame = 0; function updateFrame() { const xx = currentFrame % 4; const yy = Math.floor(currentFrame / 4); // 计算帧偏移 const frameOffset = [xx / 4, yy / 4]; gl.uniform2fv(u_frameOffset, frameOffset); console.log(`当前帧偏移:xx=${xx}, yy=${yy}, offset=[${frameOffset}]`); currentFrame = (currentFrame + 1) % frameCount; requestAnimationFrame(updateFrame); }
正常帧偏移日志示例
当前帧偏移:xx=0, yy=0, offset=[0, 0] 当前帧偏移:xx=1, yy=0, offset=[0.25, 0] 当前帧偏移:xx=2, yy=0, offset=[0.5, 0] 当前帧偏移:xx=3, yy=0, offset=[0.75, 0] 当前帧偏移:xx=0, yy=1, offset=[0, 0.25] ... 当前帧偏移:xx=3, yy=3, offset=[0.75, 0.75]
解决方案
1. 修正纹理采样边界计算
最后一行帧的纹理坐标上限接近1.0,WebGL默认线性过滤会采样到纹理外部内容,导致颜色异常。给边缘留微小偏移量,避免边界采样:
const textureSize = 4; const borderOffset = 0.001; // 微小偏移,避免边界采样 const frameSize = [(1 - borderOffset * textureSize)/textureSize, (1 - borderOffset * textureSize)/textureSize]; const frameOffset = [ (xx + borderOffset)/textureSize, (yy + borderOffset)/textureSize ];
2. 设置纹理Wrap模式为CLAMP_TO_EDGE
避免重复采样边缘像素:
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);
3. 调整透明度裁剪阈值
原阈值0.1可能误裁半透明边缘,适当降低阈值:
if (color.a < 0.05) { discard; }
4. 确认纹理导入格式
确保纹理使用正确格式导入,避免格式转换导致的边缘失真:
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
内容的提问来源于stack exchange,提问作者Nikola Lukic
相关产品推荐
相关产品推荐

