opengl-es - 片段着色器中线性过滤浮点纹理的伪影

标签 opengl-es glsl webgl fragment-shader

我正在使用以下来自 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 的计算机上,它看起来像这样:

enter image description here

enter image description here

enter image description here

enter image description here

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

内置的线性过滤适用于两个 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 * .5tex2DBiLinear正在看像素 someTexcoordsomeTexcoord + 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>


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

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

关于opengl-es - 片段着色器中线性过滤浮点纹理的伪影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35196469/

相关文章:

qt 4.8.2 qpa QGraphicsView(QGLWidget)渲染产生黑屏

android - Android Phone Emulator 对性能的反射(reflect)如何?

opengl - 顶点着色器中从摄像机到对象的 X-Y 距离

opengl - 确定相邻像素的纹理位置

javascript - WebGL 从缓冲区中删除对象

c++ - 在OpenGL中绑定(bind)点的目的?

java - 就位比例矩阵

c++ - GLSL和c有什么区别?

javascript - WebGL 不绘制线条

javascript - 如何释放和垃圾收集 WebGL 上下文?