看起来像抗锯齿故障的白色像素
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,所以如果你不走运,你不会 运行 进入这个问题,但你的一些用户会。幸运的是你 运行 解决了这个问题,所以你可以解决它。
我在 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,所以如果你不走运,你不会 运行 进入这个问题,但你的一些用户会。幸运的是你 运行 解决了这个问题,所以你可以解决它。