如何在OpenGL中适当地放大纹理?

时间:2018-12-30 00:15:40

标签: c++ opengl glsl textures

让我们说,为了简单起见,我想创建一个包含从黑色到红色的颜色渐变的纹理。我知道实现这一目标的方法要简单得多,但这是解决我的问题的一个很好的例子。

我想,我可以像这样简单地从float数组创建纹理:

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轴上从.25到.75的范围代表整个渐变(.25映射到0代表红色,0.75代表1 )。

更改作为值传递给纹理(例如4x4数组)的“步数”并不会改变结果。

我还尝试过使用图像作为纹理(加载了stb_image,分辨率为1920x1080),其效果非常好,并且可以在整个屏幕上散布。

为澄清起见:为什么渐变的texCoords范围从.25到.75而不是从0到1,我该如何解决(除了调整texCoords本身)?

1 个答案:

答案 0 :(得分:6)

假设您具有2x2纹理

2x2纹理

如果此纹理包裹在6x6片段的网格上,则纹理像素的中心正好位于6x6正方形3x3瓷砖中间的纹理像素上:

6x6 quad

其他片段的颜色取决于纹理参数-请参见glTexParameter

由于纹理被放大,因此mouseleave很重要。

如果它是GL_TEXTURE_MAG_FILTER,则片段的颜色是最接近片段纹理坐标的texel之一:

如果它是GL_NEAREST,则通过最接近纹理坐标的4个像素的加权平均值对颜色进行插值。

6x6四边形边界处的插值取决于换行参数GL_LINEARGL_TEXTURE_WRAP_S

如果参数为GL_TEXTURE_WRAP_T(默认设置),则将纹理视为无休止的纹理,并且在边界处对颜色插值进行插值时要考虑到其相对侧的纹素。质地。这用于无缝纹理和平铺:

如果它是GL_REPEAT,则边界处的插值颜色将被钳制为纹理边界处的纹素的颜色:


将纹理包裹参数GL_CLAMP_TO_EDGE应用于纹理对象

GL_CLAMP_TO_EDGE

获得以下渐变: