问题描述
我在 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,"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,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,glCtx.canvas.height]
});
}
cntrl.add(pmtrs,"ir",1).onChange(finsh);
cntrl.add(pmtrs,"or","rt",3).onChange(finsh);
cntrl.add(pmtrs,"br",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);
}
</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,-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,1.0);
} else {
float tf = texture(u_original,v_texcoord).a;
f_color = vec4(1.0 - tf,1.0 - tf,1.0);
}
}
</script>
解决方法
所以 AFAIK 的问题是您不能在条件中使用纹理查找,否则它们会破坏您的变量
来自the GLSL ES 1.0 spec附录 A
6 次纹理访问
在非均匀条件块的主体内访问 mip 映射纹理会给出未定义的 价值。非一致条件块是在编译时无法确定其执行的块 时间
和the GLSL ES 3.0 spec第 8.8 节
某些纹理函数(非“Lod”和非“Grad”版本)可能需要隐式导数。 隐式 导数在非统一控制流中未定义和顶点纹理提取。
换句话说,您需要在 fs_warp
着色器中移动此行
float tf = texture(u_original,v_texcoord).a;
在 if
语句之外。
不幸的是,它是否会得到糟糕的结果取决于 GPU,所以如果你不走运,你不会遇到这个问题,但你的一些用户会。幸运的是,您遇到了这个问题,因此您可以解决它。