glActiveTexture超出GL_TEXTURE0时多纹理渲染失效问题求助
嘿,我一眼就瞅出问题所在了——你没有把着色器里的sampler2D textures[32]数组元素和对应的OpenGL纹理单元(GL_TEXTURE0、GL_TEXTURE1这类)绑定起来。OpenGL默认会把所有未显式赋值的sampler变量都关联到纹理单元0,所以不管你用数组索引1还是其他值,最终采样的都是GL_TEXTURE0上绑定的纹理,这就是为啥所有方块都显示第一张图的原因。
具体修复步骤
1. 关联sampler数组与纹理单元
你需要在CPU端告诉OpenGL:textures[0]对应纹理单元0,textures[1]对应纹理单元1,以此类推。在你的main.cxx里,shader->Enable()之后添加这段代码:
// 获取sampler数组的uniform位置 GLuint textureArrayLoc = glGetUniformLocation(shader->GetProgramID(), "textures"); // 准备数组:索引i对应纹理单元i(GL_TEXTUREi) GLint textureUnits[32]; for (int i = 0; i < 32; ++i) { textureUnits[i] = i; } // 将数组传递给着色器 glUniform1iv(textureArrayLoc, 32, textureUnits);
这里假设你的Shader类有GetProgramID()方法能返回着色器程序的ID,如果没有的话,你需要在Shader类里加一个这个方法,或者直接把程序ID存在一个变量里调用。
2. 修复Texture类的参数错误
在texture.cxx的Load方法里,你重复设置了GL_TEXTURE_MIN_FILTER两次:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
这明显是手滑了,第二个应该是GL_TEXTURE_MAG_FILTER(纹理放大过滤),不然放大纹理时的过滤参数没设置,可能会有显示问题:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3. 确认顶点属性设置(可选但稳妥)
你的vbotid顶点属性设置是正确的,但再确认下:
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(GLfloat), 0);
步长用sizeof(GLfloat)没问题,因为每个纹理ID都是单独的float,没有额外的填充数据。
为啥之前的调试没找到问题?
- 你切换GL_TEXTURE0和GL_TEXTURE1时能显示对应纹理,说明纹理加载、绑定到纹理单元的流程是正常的,但sampler数组没和单元关联,所以不管索引多少都取单元0的纹理。
- 硬编码索引没用,因为数组里的所有元素默认都指向单元0,所以不管你写
textures[1]还是textures[31],采样的都是GL_TEXTURE0的纹理。
修改后的main.cxx关键片段
while (!window.ShouldClose()) { window.Clear(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // ********************************************************************* shader->Enable(); // 新增:绑定sampler数组到对应纹理单元 GLuint textureArrayLoc = glGetUniformLocation(shader->GetProgramID(), "textures"); GLint textureUnits[32]; for (int i = 0; i < 32; ++i) { textureUnits[i] = i; } glUniform1iv(textureArrayLoc, 32, textureUnits); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex1->GetTID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex2->GetTID()); glBindVertexArray(vao); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, nullptr); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(0); // ********************************************************************* window.Update(); }
这样改完之后,textures[0]就对应GL_TEXTURE0的黄色方块,textures[1]对应GL_TEXTURE1的蓝色方块,你的两个图形就能正常显示不同纹理啦!
内容的提问来源于stack exchange,提问作者Jae D. Nam

