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

Posted

技术标签:

【中文标题】OpenGL中纹素和屏幕像素之间的一对一映射【英文标题】:One on one mapping between texels and screen pixels in OpenGL 【发布时间】:2017-06-03 08:42:27 【问题描述】:

我正在使用 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 【参考方案1】:

您将像素误解为点。默认情况下,OpenGL 将它们视为中心具有半整数坐标的正方形。这意味着如果您提交以下纹理坐标:

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

然后屏幕坐标(511, 0) 处的右下角片段将在(511.5, 0.5) 处采样,并将得到纹理坐标插值得到(510.501, 0.499023)

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

    使用以下纹理坐标并截断:

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

    现在对(511.5, 0.5) 处的坐标进行插值得到(511.5, 0.5),截断为整数得到(511, 0),这是texelFetch 的像素坐标。

    使用gl_FragCoord.xy 代替纹理坐标。它包含与前一项中的插值纹理坐标相同的数字。

    使用标准化的 [0,1] 纹理坐标和 texture 代替 texelFetch 进行查找:

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

    如果您的视口与纹理的大小完全相同,那么这将在像素和纹素之间建立精确的映射。

    这种方法最灵活,我强烈推荐给其他人。

【讨论】:

以上是关于OpenGL中纹素和屏幕像素之间的一对一映射的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate框架学习之注解配置关系映射

mybatis xml数据层框架应用--Mybatis关系映射之一对一关系映射

Hibernate多表关系配置——一对一关系映射

MyBatis之基于XML的表之间映射

OpenGL-坐标系

在OpenGL中加载图像以用于GIS应用程序