在片段着色器中线性过滤浮点纹理的伪像

Mad*_*ist 9 opengl-es glsl webgl fragment-shader

我正在使用本教程中的以下代码对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.
}
Run Code Online (Sandbox Code Playgroud)

在Nvidia GPU上看起来很不错,但在其他两台采用Intel集成GPU的计算机上,它看起来像这样:

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

出现较浅或较暗的线条,不应该出现在那里.如果放大,它们会变得可见,并且缩放得越多,它们就越频繁.当非常接近地放大时,它们出现在我正在过滤的纹理的每个纹素的边缘.我尝试更改片段着色器中的精度语句,但这并没有解决它.

内置线性过滤适用于两个GPU,但我仍然需要手动过滤作为不支持使用WebGL对浮点纹理进行线性过滤的GPU的后备.

英特尔GPU来自台式机Core i5-4460和配备Intel HD 5500 GPU的笔记本电脑.对于浮点值的所有精度,我得到一个rangeMin和rangeMax为127,精度为23 getShaderPrecisionFormat.

有什么原因导致这些文物以及我如何解决它?

编辑:

通过多尝试一下,我发现在片段着色器中减少纹素大小变量会删除这些伪像:

float texelSizeX = 1.0/fWidth*0.998;
float texelSizeY = 1.0/fHeight*0.998;
Run Code Online (Sandbox Code Playgroud)

乘以0.999是不够的,但将纹素大小乘以0.998会消除伪影.

这显然不是一个令人满意的解决方案,我仍然不知道是什么导致它,我现在可能在其他GPU或驱动程序上造成了伪影.所以我仍然有兴趣弄清楚实际问题在这里.

gma*_*man 1

我不清楚代码想要做什么。它不会再现 GPU 的双线性,因为这将使用以纹理坐标为中心的像素。

换句话说,按照实施

vec4 c = tex2DBiLinear(someSampler, someTexcoord);
Run Code Online (Sandbox Code Playgroud)

不等于LINEAR

vec4 c = texture2D(someSampler, someTexcoord);
Run Code Online (Sandbox Code Playgroud)

texture2D查看像素someTexcoord +/- texelSize * .5,而 as 则tex2DBiLinear查看像素someTexcoord,并且someTexcoord + texelSize

您没有提供足够的代码来重新发布您的问题。我猜测源纹理的大小是 512x1024,但由于您没有发布该代码,我不知道您的源纹理是否与定义的大小匹配。您也没有发布您的目标大小。您发布的最上面的图像是 471x488。这是您的目标尺寸吗?您也没有发布您正在使用的纹理坐标的代码以及操作它们的代码。

猜测您的源是 512x1024,您的目标是 471x488 我无法重现您的问题。

vec4 c = tex2DBiLinear(someSampler, someTexcoord);
Run Code Online (Sandbox Code Playgroud)
vec4 c = texture2D(someSampler, someTexcoord);
Run Code Online (Sandbox Code Playgroud)

如果您认为问题与浮点纹理有关,我也无法在那里回购

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);
Run Code Online (Sandbox Code Playgroud)
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas width="471" height="488"></canvas>
Run Code Online (Sandbox Code Playgroud)

如果任何值关闭。如果您的源纹理大小不匹配fWidthfHeigth或者您的纹理坐标不同或以某种方式进行调整,那么我当然可以回购。如果其中任何一个不同,那么我可以想象问题。

在 Intel Iris Pro 和 Intel HD Graphics 630 中进行了测试。还在 iPhone6+ 上进行了测试。请注意,您需要确保片段着色器正在运行precision highp float,但该设置可能只会影响移动 GPU。