OpenGL中纹素和屏幕像素之间的一对一映射 [英] One on one mapping between texels and screen pixels in OpenGL

查看:140
本文介绍了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.

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

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆