You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:52:11