OpenGL中纹素和屏幕像素之间的一对一映射

4
我正在使用OpenGL进行以下操作。 我的屏幕大小为512 * 512。 我有一个与屏幕大小相同的纹理。 我想绘制一个覆盖整个屏幕的四边形,并建立像素和纹素之间的一对一映射,以便我可以在着色器中使用屏幕坐标做 texelFetch 。
首先,如果我像下面这样设置四边形的角落:
(-1, 1)+-----------+(1,1)
       |           |
       |           |
       |           |
       |           |
       |           |
(-1,-1)+-----------+(1,-1)

并将它们对应的纹理坐标设置为:

(0,511)+-----------+(511,511)
       |           |
       |           |
       |           |
       |           |
       |           |
(0,  0)+-----------+(511,0)

我刚使用了以下片段着色器,尝试为其四个边界分配不同的颜色,却只显示了白屏:

#version 330

in vec2 fUV;                              // sent from vertex shader

out vec4 color;

void main() {
    if (fUV.x == 0)                       // leftmost
        color = vec4(1.0, 0.0, 0.0, 1.0);
    else if (fUV.y == 0)                  // bottom
        color = vec4(0.0, 1.0, 0.0, 1.0);
    else if (fUV.x == 511)                // rightmost
        color = vec4(0.0, 0.0, 1.0, 1.0);
    else if (fUV.y == 511)                // top
        color = vec4(1.0, 0.0, 1.0, 1.0);
    else                                  // otherwise
        color = vec4(1.0, 1.0, 1.0, 1.0);

    // check if uv equals an integer
    if (fUV.y == 100)
        color = vec4(0.0, 0.0, 0.0, 1.0);
}

这意味着所有的相等性测试都失败了。

其次,如果我对所有的 -1 坐标添加半像素宽度偏移量 d= 1.0 / 512

(-1+d, 1 )+-----------+(1,1)
          |           |
          |           |
          |           |
          |           |
          |           |
(-1+d,-1+d)+-----------+(1,-1+d)

在保持其他内容不变的情况下,我在屏幕上画出了最左边的红线。

我得到的结果真的很令人困惑。为什么只有最左边的列被绘制,而底部行没有呢?

我想知道如何绘制四边形并设置它们的坐标,以便我可以在像素和纹理元素之间建立一对一的映射。


不应该使用“==”运算符进行浮点数比较。请使用“abs(fUV.x - 511) < 0.001”。 - James Poag
1个回答

3
你将像素错误地解释为点。默认情况下,OpenGL将它们视为以中心为半整数坐标的正方形。这意味着如果您提交以下纹理坐标:
(0,511)+-----------+(511,511)
       |           |
       |           |
       |           |
       |           |
       |           |
(0,  0)+-----------+(511,0)

接着,在屏幕坐标(511, 0)的右下角片段将被采样,其采样坐标为(511.5,0.5),并且将插值纹理坐标,得到(510.501, 0.499023)

有几种方法可以实现您的目标。

  1. Use the following texture coordinates and truncate:

    (0,512)+-----------+(512,512)
           |           |
           |           |
           |           |
           |           |
           |           |
    (0,  0)+-----------+(512,0)
    

    Now interpolating the coordinates at (511.5, 0.5) gives (511.5, 0.5), and truncating to integers gives (511, 0), which is the coordinates of the pixel for texelFetch.

  2. Use gl_FragCoord.xy instead of texture coordinates. It contains the same numbers as the interpolated texture coordinates in the previous item.

  3. Use normalized [0,1] texture coordinates and texture instead of texelFetch for lookup:

    (0,1)+-----------+(1,1)
         |           |
         |           |
         |           |
         |           |
         |           |
    (0,0)+-----------+(1,0)
    

    If your viewport is exactly of the same size as the texture then this will establish an exact mapping between pixels and texels.

    This approach is the most flexible and I highly recommend it to the others.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接