我正在使用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)
保持其他内容不变,我在屏幕上绘制了最左边的红线。
我得到的上述结果实在令人困惑。为什么只有最左边的列被绘制而底行不是?
我想知道如何绘制四边形并设置它们的坐标,以便我可以在像素和纹素之间建立一对一的映射。
答案 0 :(得分:2)
您将像素误解为点。默认情况下,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)
如果您的视口与纹理的大小完全相同,那么将在像素和纹素之间建立精确的映射。
这种方法最灵活,我强烈推荐给其他人。