如何在opengl中正确升级纹理?

Kan*_*jiu 1 c++ opengl textures glsl

让我们说,为了简化这个问题,我想创建一个包含从黑色到红色的颜色渐变的纹理.我知道有更简单的方法来实现这一点,但它是我的问题的一个很好的例子.

我想,我可以简单地从浮点数组创建一个纹理,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

并绘制它:

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);
Run Code Online (Sandbox Code Playgroud)

绑定顶点着色器的位置如下所示:

#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;
}
Run Code Online (Sandbox Code Playgroud)

片段着色器如下:

#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);
}
Run Code Online (Sandbox Code Playgroud)

在此之后,我希望在整个窗口中从左到右(黑色到红色)获得颜色渐变.然而,我得到的是从x和y方向的窗口的约1/4到3/4的梯度(见下图).我也注意到重复的包装在这里似乎不适用,因为我看起来像镜像重复.

结果:

我已经使用固定值而不是texCoords来使用片段着色器,并且认为x轴上的.25到.75的范围表示整个渐变(.25映射为0表示红色,.75表示为1).

将作为值传递的"步骤"数量更改为纹理(例如,4x4阵列)不会更改结果.

我也尝试使用图像作为纹理(加载了stb_image,分辨率为1920x1080),它可以很好地工作并在整个屏幕上传播.

为了澄清:为什么渐变的texCoords范围从.25到.75而不是从0到1以及如何修复它(除了调整texCoords本身)?

Rab*_*d76 6

让我们假设您有2x2纹理

2x2纹理

如果此纹理包裹在6x6片段的网格上,则纹素的中心恰好位于6x6正方形的3x3平铺的middel中的纹素上:

6x6四核

其他碎片的颜色取决于纹理参数 - 请参阅glTexParameter.

由于纹理被放大,因此GL_TEXTURE_MAG_FILTER是重要的.

如果是GL_NEAREST,那么片段的颜色是片段的纹理坐标中最接近的纹素之一:

如果是GL_LINEAR,则通过最接近纹理坐标的4个像素的加权平均来内插颜色.

6x6四边形边界处的插值取决于包裹参数GL_TEXTURE_WRAP_SGL_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);
Run Code Online (Sandbox Code Playgroud)

获得以下渐变:

  • 现在你的回答并不清楚,所以我想你应该补充一些说明,即纹素网格中每个"单元格"的中心定义纹素值,而坐标0和1不在纹素中心.也许还会对OP原始代码添加修改以正确地处理texel中心并显示结果. (2认同)