如何向我的 openGL 程序添加多个纹理?

Posted

技术标签:

【中文标题】如何向我的 openGL 程序添加多个纹理?【英文标题】:How can I add multiple textures to my openGL program? 【发布时间】:2019-04-22 19:58:48 【问题描述】:

我正在编写一个 openGL 程序并将多个模型绘制到环境中,但我不知道如何将不同的纹理应用于每个模型,所以现在它们都具有相同的纹理。我读过我需要在程序中添加多个纹理单元或使用纹理图集。纹理图集似乎更复杂,所以我正在尝试添加纹理单元。

我认为这个过程的工作方式是:

    使用 glGenTextures 生成两个纹理单元。 使用 glBindTexture 和 glTexImage2D 将第一张图片的数据绑定到第一个纹理单元。 对第二张图片执行相同操作。

从这里,我想我可以使用 glActiveTexture 告诉 openGL 我想使用哪个纹理单元。这似乎只适用于一种纹理(即跳过第 3 步),但适用于两种或更多纹理。

我确定我错过了什么,所以有人能指出我正确的方向吗?

//Generate textures
int texturec=2;
int w[texturec],h[texturec];
unsigned char *data[texturec];
data[0]=getImage(&w[0],&h[0],"resources/a.png");
data[1]=getImage(&w[1],&h[1],"resources/b.png");

//Apply textures
GLuint textures[texturec];
glGenTextures(texturec, textures);

//Bind a.png to the first texture unit
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);

//Bind b.png to the second texture unit
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);

glActiveTexture(GL_TEXTURE0);

//Not super clear on what this does, but it needs to be here.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

这是我的着色器:

片段:

#version 330 core

in vec2 UV;
out vec3 color;

uniform sampler2D textureSampler;

void main()
    color=texture(textureSampler,UV).rgb;

顶点:

#version 330 core

layout(location=0) in vec3 vertexPos;
layout(location=1) in vec2 vertexUV;

out vec2 UV;

uniform mat4 MVP;

void main()
    gl_Position=MVP*vec4(vertexPos,1);
    UV=vertexUV;

编辑:

这是我应用 Rabid76 建议后的新代码:

//Generate textures
int texturec=2;
int w[texturec],h[texturec];
unsigned char *data[texturec];
data[0]=getImage(&w[0],&h[0],"resources/a.png");
data[1]=getImage(&w[1],&h[1],"resources/b.png");

//Apply textures
GLuint textures[texturec];
glGenTextures(texturec, textures);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

//Shaders
programID=loadShaders("shaders/vertex.shader","shaders/fragment.shader");
glUseProgram(programID);

//Use texture unit 1
glActiveTexture(GL_TEXTURE1);
GLint texLoc=glGetUniformLocation(programID, "textureSampler");
glUniform1i(texLoc, 1);

【问题讨论】:

【参考方案1】:
    使用glGenTextures 生成两个纹理单元。

没有。 glGenTextures 不生成纹理单元。

glGenTextures 保留名称值,可用于纹理对象。

glBindTexture 将命名纹理绑定到纹理目标。调用此函数时,纹理对象将绑定到当前纹理单元。 当前纹理单元可以通过glActiveTexture设置:

例如

GLuint textures[texturec];
glGenTextures(texturec, textures);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
// [...]

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
// [...]

纹理对象名称值和纹理单元是完全不同的东西。 纹理单元是纹理对象和着色器程序之间的绑定点。 一方面,纹理对象必须绑定到纹理单元,另一方面,纹理单元必须设置为纹理采样器统一。所以纹理单元是两者之间的“链接”。

从 GLSL 4.2 版开始,纹理单元可以通过着色器中的Layout Qualifier (GLSL) 设置。 Binding point 对应于纹理单元。例如binding = 1 表示纹理单元 1:

layout(binding = 1) uniform sampler2D textureSampler;

或者,纹理单元索引可以通过glUniform1i分配给纹理采样器制服:

GLint texLoc = glGetUniformLocation(programID, "textureSampler");
glUniform1i(texLoc, 1);

如果着色器程序使用 1 个纹理采样器均匀

uniform sampler2D textureSampler;

那么在绘制调用之前绑定正确的纹理对象就足够了:

glActiveTexture(GL_TEXTURE0); // this is default 
glBindTexture(GL_TEXTURE_2D, textures[0]);

但是如果着色器程序使用多个纹理采样器制服(同一个目标),那么不同的纹理对象必须绑定到不同的纹理单元:

例如

layout(binding = 3) uniform sampler2D textureSampler1;
layout(binding = 4) uniform sampler2D textureSampler2;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, textures[0]);

glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, textures[1]);

分别

layout(location = 7) uniform sampler2D textureSampler1;
layout(location = 8) uniform sampler2D textureSampler2;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, textures[0]);

glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, textures[1]);

glUseProgram(programID);
glUniform1i(7, 3); // location = 7 <- texture unit 3
glUniform1i(8, 4); // location = 8 <- texture unit 4

【讨论】:

由于 OP 没有在他们提供的代码中显示它,因此可能值得扩展最后一句以显示对 glUniform() 的调用以设置片段着色器使用的纹理单元。跨度> 我已尽力根据您的回答更改我的代码。我已将更改后的代码粘贴到原始问题的末尾。这些更改允许我使用纹理单元 1,但我无法切换回纹理单元 0。如果我将 glUniform1i 的第二个参数更改为 0,则所有纹理默认为黑色。 @sam 正如问题中间部分提到的,在draw call之前绑定合适的纹理就足够了。由于在着色器程序中一次只使用一个纹理,因此使用纹理单元 0 就足够了。这意味着您不需要任何 glActiveTexture,但在 glDraw... 之前使用 glBindTexture @sam 在任何情况下glActiveTexture 只在glBindTexture 之前有用。活动纹理单元的任何其他更改都不会按照您的预期进行 - 不管是什么。 @sam 在您的程序中还有其他对glBindTexture 的调用吗?必须先安装程序 (glUseProgram(programID)),然后才能设置制服 (glUniform1i(texLoc, 1))。 glTexParameteri 不会改变一些神奇的全局参数。它设置当前绑定的纹理对象的参数。必须为每个对象调用它。

以上是关于如何向我的 openGL 程序添加多个纹理?的主要内容,如果未能解决你的问题,请参考以下文章

在OpenGL中计算按1d、2d、3d分组创建的纹理

C++ OpenGL 错误的 Collada 纹理坐标

将 CIFilter 应用于 OpenGL 渲染到纹理

将纹理添加到 QT OpenGL 场景图

OpenGL中多个纹理的问题

如何在多采样纹理上渲染帧缓冲区对象?