OpenGL中纹素和屏幕像素之间的一对一映射 [英] One on one mapping between texels and screen pixels in OpenGL
问题描述
我正在使用 OpenGL 执行以下操作.我的屏幕尺寸为 512*512.我有一个与屏幕大小相同的纹理.我想绘制一个覆盖整个屏幕的四边形,并在像素和纹素之间建立一对一的映射,以便我可以在着色器中使用屏幕坐标执行 texelFetch
.
I am doing the following with OpenGL. My screen is of size 512*512. I have a texture of the same size as the screen. I want to draw a quad that covers the whole screen and establishes a one on one mapping between pixels and texels, so that I can do texelFetch
with screen coordinates in shaders.
首先,如果我像下面这样设置四边形的角:
First, if I setup the corners of the quad like the following:
(-1, 1)+-----------+(1,1)
| |
| |
| |
| |
| |
(-1,-1)+-----------+(1,-1)
并将它们对应的纹理坐标设置为:
and set their corresponding texture coordinates as:
(0,511)+-----------+(511,511)
| |
| |
| |
| |
| |
(0, 0)+-----------+(511,0)
我刚刚使用以下片段着色器获得了一个白色屏幕,该着色器尝试为其四个边界分配不同的颜色:
I just got a white screen using the following fragment shader which tries to assign different colors to its four boundaries:
#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);
}
这意味着所有相等性测试都失败了.
which means all equality test have failed.
其次,如果我将半像素宽度偏移 d= 1.0/512
添加到所有 -1 坐标:
Secondly, If I add a half pixel width offset d= 1.0 / 512
to all -1 coordinates:
(-1+d, 1 )+-----------+(1,1)
| |
| |
| |
| |
| |
(-1+d,-1+d)+-----------+(1,-1+d)
保持其他不变,我在屏幕上绘制了最左边的红线.
keeping other things unchanged, I got the leftmost red line drawn on the screen.
我得到的上述结果真的很令人困惑.为什么只画了最左边的一列,而没有画底行?
The above results I got are really confusing. Why was only the leftmost column drawn while the bottom row was not?
我想知道我应该如何绘制四边形并设置它们的坐标,以便我可以在像素和纹素之间建立一对一的映射.
I would like to know how should I draw a quad and set their coordinates so that I can establish a one on one mapping between pixels and texels.
推荐答案
您将像素误解为点.默认情况下,OpenGL 将它们视为中心为半整数坐标的正方形.这意味着如果您提交以下纹理坐标:
You misinterpret pixels as points. OpenGL, by default, treats them as squares with half-integer coordinates at the centers. That means that if you submit the following texture coordinates:
(0,511)+-----------+(511,511)
| |
| |
| |
| |
| |
(0, 0)+-----------+(511,0)
然后在屏幕坐标 (511, 0)
处的右下片段将在 (511.5, 0.5)
处被采样,并将得到内插的纹理坐标给出 (510.501, 0.499023)
.
then the bottom right fragment at screen coordinates (511, 0)
will be sampled at (511.5, 0.5)
, and will get the texture coordinates interpolated giving (510.501, 0.499023)
.
有几种方法可以实现您的目标.
There are a few ways to achieve your goal.
使用以下纹理坐标并截断:
Use the following texture coordinates and truncate:
(0,512)+-----------+(512,512)
| |
| |
| |
| |
| |
(0, 0)+-----------+(512,0)
现在在 (511.5, 0.5)
处插入坐标给出 (511.5, 0.5)
,截断为整数给出 (511, 0)
>,这是texelFetch
的像素坐标.
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
.
使用 gl_FragCoord.xy
而不是纹理坐标.它包含与前一项中插入的纹理坐标相同的数字.
Use gl_FragCoord.xy
instead of texture coordinates. It contains the same numbers as the interpolated texture coordinates in the previous item.
使用归一化的 [0,1] 纹理坐标和 texture
代替 texelFetch
进行查找:
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.
这篇关于OpenGL中纹素和屏幕像素之间的一对一映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!