看起来像抗锯齿故障的白色像素

White Pixels In What Looks Like Antialiasing Glitch

我在 Firefox 中看到红色形状边框周围有一些白色像素:

这是 R 附近区域的放大图。

我期待的

我得到了什么

但是片段着色器代码基本上只是检查一些条件,如果为真则写入一个红色像素,如果为假则写入来自背景图像的信息。没有实施抗锯齿。所以我想知道,这些人工制品是从哪里来的?

twgl.setDefaults({ attribPrefix: "a_" });
const bdrSz = 50;
const cntrl = new dat.GUI();
const glCtx = twgl.getContext(document.createElement("canvas"));
const imgLc =
  "https://upload.wikimedia.org/wikipedia/commons/8/85/BlackRock_wordmark.svg";
// const imgLc =
//   "https://upload.wikimedia.org/wikipedia/commons/8/8e/Panasonic_logo_%28Blue%29.svg";
const pmtrs = { ir: 0.3, or: 0.4, rt: 2, br: 0.1, ri: 10 };
const width = 1200;
let buffr;
let dmnsn;
let pgInf = {
  blr: twgl.createProgramInfo(glCtx, ["vs", "fs_blur"]),
  wrp: twgl.createProgramInfo(glCtx, ["vs", "fs_warp"])
};
let qBInf = twgl.primitives.createXYQuadBufferInfo(glCtx);
let imgTx;
function nrmlz(arr) {
  let sum = arr.reduce((v, w) => v + w[0] * w[1], 0);
  return arr.map((v) => v[0] / sum);
}
function rendr(fbi, pi, u) {
  twgl.bindFramebufferInfo(glCtx, fbi);
  twgl.drawObjectList(glCtx, [
    {
      programInfo: pi,
      bufferInfo: qBInf,
      uniforms: u
    }
  ]);
}
function prepr() {
  let img = new Image();
  img.crossOrigin = "Anonymous";
  img.src = imgLc;
  img.onload = function () {
    let ctx = document.createElement("canvas").getContext("2d");
    ctx.canvas.width = glCtx.canvas.width = width;
    ctx.canvas.height = glCtx.canvas.height =
      (img.height * (width - 2 * bdrSz)) / img.width + 2 * bdrSz;
    buffr = twgl.createFramebufferInfo(
      glCtx,
      [
        {
          internalFormat: glCtx.R32F
        }
      ],
      ctx.canvas.width,
      ctx.canvas.height
    );
    document.body.append(glCtx.canvas);
    ctx.drawImage(
      img,
      bdrSz,
      bdrSz,
      ctx.canvas.width - 2 * bdrSz,
      ctx.canvas.height - 2 * bdrSz
    );
    imgTx = twgl.createTexture(glCtx, { flipY: 1, src: ctx.canvas });
    compt();
  };
}
function compt() {
  let bra = Math.max(2, Math.floor(pmtrs.br * glCtx.canvas.height));
  let knl = twgl.createTexture(glCtx, {
    height: bra,
    internalFormat: glCtx.R32F,
    src: nrmlz(
      Array(bra)
        .fill()
        .map((_, i) =>
          Array(bra)
            .fill()
            .map((_, j) => [
              Math.exp(-((i / bra) ** 2 + (j / bra) ** 2)),
              i == 0 && j == 0 ? 1 : i == j || i == 0 || j == 0 ? 4 : 8
            ])
        )
        .flat()
    ),
    width: bra
  });
  rendr(buffr, pgInf.blr, {
    u_kernel: knl,
    u_radius: bra,
    u_resolution: [glCtx.canvas.width, glCtx.canvas.height],
    u_texture: imgTx
  });
  finsh();
}
function finsh() {
  rendr(null, pgInf.wrp, {
    u_blurred: buffr.attachments[0],
    u_original: imgTx,
    u_innerRadius: pmtrs.ir,
    u_outerRadius: pmtrs.or,
    u_ratio: pmtrs.rt,
    u_refIndex: pmtrs.ri,
    u_resolution: [glCtx.canvas.width, glCtx.canvas.height]
  });
}
cntrl.add(pmtrs, "ir", 0, 1).onChange(finsh);
cntrl.add(pmtrs, "or", 0, 1).onChange(finsh);
cntrl.add(pmtrs, "rt", 0, 3).onChange(finsh);
cntrl.add(pmtrs, "br", 0, 0.1).onChange(compt);
cntrl.add(pmtrs, "ri", -10, 10).onChange(finsh);
prepr();
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script id="vs" type="x-shader/x-vertex">
  #version 300 es
  in vec4 a_position;
  in vec2 a_texcoord;
    
  out vec2 v_texcoord;

  void main() {
    v_texcoord = a_texcoord;
    gl_Position = a_position;
  }
</script>
<script id="fs_blur" type="x-shader/x-fragment">
  #version 300 es
  precision highp float;

  in vec2 v_texcoord;

  uniform sampler2D u_kernel;
  uniform int u_radius;
  uniform vec2 u_resolution;
  uniform sampler2D u_texture;

  out vec4 f_color;

  void main() {
    float sum = 0.0;
    for(int i = -u_radius + 1; i < u_radius; i++) {
      for(int j = -u_radius + 1; j < u_radius; j++) {
        sum += texture(u_kernel, vec2(abs(i), abs(j)) / float(u_radius)).r *
          texture(u_texture, v_texcoord + vec2(i,j) / u_resolution).a;
      }
    }
    f_color = vec4(sum, 1.0, 1.0, 1.0);
  }
</script> 
<script id="fs_warp" type="x-shader/x-fragment">
  #version 300 es
  precision highp float;

  in vec2 v_texcoord;

  uniform sampler2D u_blurred;
  uniform sampler2D u_original;
  uniform float u_innerRadius;
  uniform float u_outerRadius;
  uniform float u_ratio;
  uniform float u_refIndex;
  uniform vec2 u_resolution;

  out vec4 f_color;

  void main() {
    vec2 ref = v_texcoord + u_refIndex * (
      texture(u_blurred, v_texcoord + vec2(0, 1) / u_resolution).r -
      texture(u_blurred, v_texcoord + vec2(0, -1) / u_resolution).r +
      texture(u_blurred, v_texcoord + vec2(1, 0) / u_resolution).r -
      texture(u_blurred, v_texcoord + vec2(-1, 0) / u_resolution).r
    );
    float len = length(2.0 * (ref - 0.5) / vec2(u_ratio, 1));
    if(u_innerRadius < len && len < u_outerRadius) {
      f_color = vec4(1.0, 0.0, 0.0, 1.0);
    } else {
      float tf = texture(u_original, v_texcoord).a;
      f_color = vec4(1.0 - tf, 1.0 - tf, 1.0 - tf, 1.0);
    }
  }
</script> 

据我所知,问题是您不能在条件中使用纹理查找,否则它们会破坏您的变量

来自the GLSL ES 1.0 spec附录A

6 Texture Accesses

Accessing mip-mapped textures within the body of a non-uniform conditional block gives an undefined value. A non-uniform conditional block is a block whose execution cannot be determined at compile time

the GLSL ES 3.0 spec第8.8节

Some texture functions (non-“Lod” and non-“Grad” versions) may require implicit derivatives. Implicit derivatives are undefined within non-uniform control flow and for vertex texture fetches.

换句话说,您需要在 fs_warp 着色器中移动此行

float tf = texture(u_original, v_texcoord).a;

if 语句之外。

不幸的是,它是否会得到不好的结果取决于 GPU,所以如果你不走运,你不会 运行 进入这个问题,但你的一些用户会。幸运的是你 运行 解决了这个问题,所以你可以解决它。