我正在使用以下来自 this tutorial 的代码在 WebGL 的片段着色器中对浮点纹理执行线性过滤:
float fHeight = 512.0;
float fWidth = 1024.0;
float texelSizeX = 1.0/fWidth;
float texelSizeY = 1.0/fHeight;
float tex2DBiLinear( sampler2D textureSampler_i, vec2 texCoord_i )
{
float p0q0 = texture2D(textureSampler_i, texCoord_i)[0];
float p1q0 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX, 0))[0];
float p0q1 = texture2D(textureSampler_i, texCoord_i + vec2(0, texelSizeY))[0];
float p1q1 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX , texelSizeY))[0];
float a = fract( texCoord_i.x * fWidth ); // Get Interpolation factor for X direction.
// Fraction near to valid data.
float pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction.
float pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction.
float b = fract( texCoord_i.y * fHeight );// Get Interpolation factor for Y direction.
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
}
在 Nvidia GPU 上,这看起来不错,但在另外两台带有 Intel 集成 GPU 的计算机上,它看起来像这样:
出现了不应该出现的较浅或较深的线条。如果放大,它们就会变得可见,并且放大得越多,它们就越频繁。当非常接近地放大时,它们出现在我正在过滤的纹理的每个纹素的边缘。我尝试更改片段着色器中的精度语句,但这并没有解决。
内置的线性过滤适用于两个 GPU,但我仍然需要手动过滤作为不支持使用 WebGL 对浮点纹理进行线性过滤的 GPU 的后备。
英特尔 GPU 来自台式机酷睿 i5-4460 和配备英特尔 HD 5500 GPU 的笔记本电脑。对于浮点值的所有精度,我从
getShaderPrecisionFormat
得到了 127 的 rangeMin 和 rangeMax 以及 23 的精度。 .关于导致这些工件的原因以及我如何解决它的任何想法?
编辑:
通过更多的实验,我发现减少片段着色器中的 texel 大小变量可以消除这些伪影:
float texelSizeX = 1.0/fWidth*0.998;
float texelSizeY = 1.0/fHeight*0.998;
乘以 0.999 是不够的,但将纹素大小乘以 0.998 可以消除伪影。
这显然不是一个令人满意的修复,我仍然不知道是什么原因造成的,我现在可能在其他 GPU 或驱动程序上造成了伪影。所以我仍然有兴趣弄清楚这里的实际问题是什么。
最佳答案
我不清楚代码试图做什么。它不会再现 GPU 的双线性,因为那将使用以 texcoord 为中心的像素。
换句话说,如实现
vec4 c = tex2DBiLinear(someSampler, someTexcoord);
是 不是 相当于
LINEAR
vec4 c = texture2D(someSampler, someTexcoord);
texture2D
查看像素 someTexcoord +/- texelSize * .5
如 tex2DBiLinear
正在看像素 someTexcoord
和 someTexcoord + texelSize
您没有提供足够的代码来重新提交您的问题。我猜源纹理的大小是 512x1024,但由于您没有发布该代码,我不知道您的源纹理是否与定义的大小匹配。你也没有发布你的目标是什么尺寸。您发布的顶部图像是 471x488。那是你的目标尺寸吗?您也没有发布您正在使用的纹理坐标的代码以及操作它们的代码。
猜测您的源是 512x1024,您的目标是 471x488 我无法重新解决您的问题。
const fs = `
precision highp float;
uniform sampler2D tex;
varying vec2 v_texcoord;
float tex2DBiLinear( sampler2D textureSampler_i, vec2 texCoord_i )
{
float fHeight = 1024.0;
float fWidth = 512.0;
float texelSizeX = 1.0/fWidth;
float texelSizeY = 1.0/fHeight;
float p0q0 = texture2D(textureSampler_i, texCoord_i)[0];
float p1q0 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX, 0))[0];
float p0q1 = texture2D(textureSampler_i, texCoord_i + vec2(0, texelSizeY))[0];
float p1q1 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX , texelSizeY))[0];
float a = fract( texCoord_i.x * fWidth ); // Get Interpolation factor for X direction.
// Fraction near to valid data.
float pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction.
float pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction.
float b = fract( texCoord_i.y * fHeight );// Get Interpolation factor for Y direction.
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
}
void main() {
gl_FragColor = vec4(tex2DBiLinear(tex, v_texcoord), 0, 0, 1);
}
`;
const vs = `
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main() {
gl_Position = position;
v_texcoord = texcoord;
}
`;
const gl = document.querySelector('canvas').getContext('webgl');
// compile shaders, link programs, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// calls gl.createBuffer, gl.bindBuffer, gl.bufferData for each array
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-1, -1,
1, -1,
-1, 1,
1, 1,
],
},
texcoord: [
0, 0,
1, 0,
0, 1,
1, 1,
],
indices: [
0, 1, 2,
2, 1, 3,
],
});
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 512;
ctx.canvas.height = 1024;
const gradient = ctx.createRadialGradient(256, 512, 0, 256, 512, 700);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'cyan');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 512, 1024);
const tex = twgl.createTexture(gl, {
src: ctx.canvas,
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
auto: false,
});
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas width="471" height="488"></canvas>
如果您认为问题与浮点纹理有关,我也无法在那里进行 repo
const fs = `
precision highp float;
uniform sampler2D tex;
varying vec2 v_texcoord;
float tex2DBiLinear( sampler2D textureSampler_i, vec2 texCoord_i )
{
float fHeight = 1024.0;
float fWidth = 512.0;
float texelSizeX = 1.0/fWidth;
float texelSizeY = 1.0/fHeight;
float p0q0 = texture2D(textureSampler_i, texCoord_i)[0];
float p1q0 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX, 0))[0];
float p0q1 = texture2D(textureSampler_i, texCoord_i + vec2(0, texelSizeY))[0];
float p1q1 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX , texelSizeY))[0];
float a = fract( texCoord_i.x * fWidth ); // Get Interpolation factor for X direction.
// Fraction near to valid data.
float pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction.
float pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction.
float b = fract( texCoord_i.y * fHeight );// Get Interpolation factor for Y direction.
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
}
void main() {
gl_FragColor = vec4(tex2DBiLinear(tex, v_texcoord), 0, 0, 1);
}
`;
const vs = `
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main() {
gl_Position = position;
v_texcoord = texcoord;
}
`;
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('OES_texture_float');
if (!ext) { alert('need OES_texture_float'); }
// compile shaders, link programs, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// calls gl.createBuffer, gl.bindBuffer, gl.bufferData for each array
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-1, -1,
1, -1,
-1, 1,
1, 1,
],
},
texcoord: [
0, 0,
1, 0,
0, 1,
1, 1,
],
indices: [
0, 1, 2,
2, 1, 3,
],
});
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 512;
ctx.canvas.height = 1024;
const gradient = ctx.createRadialGradient(256, 512, 0, 256, 512, 700);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'cyan');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 512, 1024);
const tex = twgl.createTexture(gl, {
src: ctx.canvas,
type: gl.FLOAT,
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
auto: false,
});
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
const e = gl.getExtension('WEBGL_debug_renderer_info');
if (e) {
console.log(gl.getParameter(e.UNMASKED_VENDOR_WEBGL));
console.log(gl.getParameter(e.UNMASKED_RENDERER_WEBGL));
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas width="471" height="488"></canvas>
如果有任何值关闭。如果您的源纹理大小不匹配
fWidth
和 fHeigth
或者如果您的纹理坐标不同或以某种方式进行了调整,那么当然也许我可以 repo 。如果其中任何一个不同,那么我可以想象问题。在 Intel Iris Pro 和 Intel HD Graphics 630 中测试。也在 iPhone6+ 上测试。请注意,您需要确保片段着色器在
precision highp float
中运行但该设置可能只会影响移动 GPU。
关于opengl-es - 片段着色器中线性过滤浮点纹理的伪影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35196469/