如何在opengl中正确升级纹理?
Posted
技术标签:
【中文标题】如何在opengl中正确升级纹理?【英文标题】:How to properly upscale a texture in opengl? 【发布时间】:2018-12-30 00:15:39 【问题描述】:假设,为了这个问题的简单性,我想创建一个包含从黑色到红色的颜色渐变的纹理。我知道有很多更简单的方法可以实现这一点,但这是解决我的问题的一个很好的例子。
我想,我可以像这样简单地从浮点数组创建纹理:
float values[4]
0.f, 1.f,
0.f, 1.f
// gen texture
unsigned int texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
// set filter and wrap
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// copy values
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 2, 2, 0, GL_RED, GL_FLOAT, values);
然后画出来:
float vertices[8]
-1.f, -1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, 0.f, 1.f
// generate vertex buffer, vertex buffer layout and vertex array
unsigned int[6] indices
0, 1, 2,
2, 3, 1
// generate index buffer
// bind everything
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
绑定的顶点着色器如下所示:
#version 330 core
layout(location=0) in vec2 in_position;
layout(location=1) in vec2 in_texCoords;
out vec2 texCoords;
void main()
gl_Position = vec4(in_position, 0.f, 1.f);
texCoords = in_texCoords;
片段着色器是这样的:
#version 330 core
layout(location = 0) out vec4 out_color;
in vec2 texCoords;
uniform sampler2D u_gradient;
void main()
float red = texture(u_gradient, texCoords).r;
out_color = vec4(red, 0.f, 0.f, 1.f);
在此之后,我希望在整个窗口中获得从左到右(从黑色到红色)的颜色渐变。 然而,我得到的是在 x 和 y 方向上从窗口的大约 1/4 到 3/4 的渐变(见下图)。我还注意到重复的包装在这里似乎并不适用,因为我得到的看起来像镜像重复。
结果:
我使用固定值而不是 texCoords 使用片段着色器,并发现 x 轴上从 0.25 到 0.75 的范围代表整个渐变(红色为 0.25 映射到 0,红色为 0.75 到 1 )。
更改作为值传递给纹理(例如 4x4 数组)的“步数”数量不会改变结果。
我也尝试过使用图像作为纹理(加载 stb_image,分辨率 1920x1080),效果非常好,并且遍布整个屏幕。
澄清一下:为什么渐变的 texCoords 范围从 0.25 到 .75 而不是从 0 到 1,我该如何修复它(除了调整 texCoords 本身)?
【问题讨论】:
请看Textures objects and parameters,特别是GL_REPEAT
的效果。请改用GL_CLAMP_TO_EDGE
。 (顺便说一句。你设置了两次GL_TEXTURE_WRAP_S
- 第二次可能是GL_TEXTURE_WRAP_T
。)
复制粘贴代码时出现换行错误。它在我的代码中是正确的,我也在这里修复了它。 @Scheff
【参考方案1】:
假设你有一个 2x2 的纹理
2x2 纹理
如果此纹理被包裹在 6x6 片段的网格上,则纹素的中心正好在 6x6 正方形的 3x3 平铺中间的纹素上:
6x6 四边形
其他片段的颜色取决于纹理参数 - 请参阅glTexParameter
。
由于纹理被放大,GL_TEXTURE_MAG_FILTER
很重要。
如果是GL_NEAREST
,那么片段的颜色是最接近片段纹理坐标的纹素之一:
如果是GL_LINEAR
,则颜色被插值,通过最接近纹理坐标的4个像素的加权平均值。
6x6 四边形边界处的插值取决于环绕参数GL_TEXTURE_WRAP_S
和GL_TEXTURE_WRAP_T
。
如果参数为GL_REPEAT
(默认),则纹理被视为无限纹理,边界颜色插值的插值考虑了纹理对面的纹素。这用于无缝纹理和平铺:
如果是GL_CLAMP_TO_EDGE
,那么边界处的插值颜色被钳制为纹理边界处纹素的颜色:
将纹理包裹参数GL_CLAMP_TO_EDGE
应用于纹理对象,
float values[4] 0.f, 1.f, 0.f, 1.f ;
unsigned int texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
// set filter and wrap
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// copy values
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 2, 2, 0, GL_RED, GL_FLOAT, values);
得到以下渐变:
【讨论】:
现在从您的回答中并不清楚,所以我认为您应该添加一些说明,即纹素值是为纹素网格中每个“单元格”的中心定义的,以及坐标0 和 1 不在纹素中心。也许还可以对 OP 的原始代码进行修改,以正确处理纹素中心并显示结果。以上是关于如何在opengl中正确升级纹理?的主要内容,如果未能解决你的问题,请参考以下文章