多个 OpenGL 纹理在某些情况下不起作用?
Posted
技术标签:
【中文标题】多个 OpenGL 纹理在某些情况下不起作用?【英文标题】:Multiple OpenGL Textures not working in some instances? 【发布时间】:2019-09-03 12:07:06 【问题描述】:我正在尝试加载 OBJ 文件以在 OpenGL 中使用它们。 OBJ 文件中的每个对象都有自己的纹理。在我的代码中,我将文件的每个对象拆分为一个结构,如下所示:
struct ObjModelComponent
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
Texture tex;
ArrayBuffer vertex, uv, normal;
GLuint VAO;
;
Texture
类是一个简单的类,可以更轻松地加载和处理纹理。
在模型类中,我的ObjModelComponent
有一个std::vector
。
我正在像这样渲染对象:
void ObjModel::render()
for(int i = 0; i < components.size(); i++)
components[i].vertex.activate();
components[i].uv.activate();
components[i].normal.activate();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, components[i].tex.getTextureID());
shader->sendInt(0, components[i].tex.getTextureName());
glBindVertexArray(components[i].VAO);
shader->sendMat4(*data->projection, "projection");
shader->sendMat4(data->viewMat, "view");
shader->sendMat4(model, "model");
glDrawArrays(GL_TRIANGLES, 0, int(components[i].vertices.size()));
glBindVertexArray(0);
Texture 类如下所示:
Texture::Texture(std::string fileName, TextureType type):
textureName("tex"), fileName(fileName), type(type)
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
unsigned char *image = SOIL_load_image(fileName.c_str(), &texWidth, &texHeight, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
switch (type)
case TEXTURE_GENERATE_MIPMAP:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
break;
case TEXTURE_NO_MIP_MAP:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
default:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
Texture::Texture()
Texture& Texture::operator=(const Texture &other)
this->fileName = other.fileName;
this->textureName = other.textureName;
this->type = other.type;
// glDeleteTextures(1, &tex);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
unsigned char *image = SOIL_load_image(fileName.c_str(), &texWidth, &texHeight, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
switch (type)
case TEXTURE_GENERATE_MIPMAP:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
break;
case TEXTURE_NO_MIP_MAP:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
default:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return *this;
Texture::~Texture()
glDeleteTextures(1, &tex);
GLuint Texture::getTextureID()
return tex;
void Texture::setTextureName(std::string name)
textureName = name;
std::string Texture::getTextureName()
return textureName;
glm::vec2 Texture::getTextureSize()
return glm::vec2(texWidth, texHeight);
这是组件的生成方式:
for(int i = 0; i < fileLines.size(); i++)
if(fileLines[i].substr(0, 2) == "o ")
if(!first)
tmpComp.tex = tmpTex;
components.emplace_back(tmpComp);
componentIndex++;
first = false;
tmpTex = Texture(hg::substr(path, 0, int(path.find_last_of("/"))) + "/" + hg::substr(fileLines[i], 2, int(fileLines[i].length())) + ".png");
这是生成 VAO 和数组缓冲区的方式:
for(int i = 0; i < components.size(); i++)
glGenVertexArrays(1, &components[i].VAO);
glBindVertexArray(components[i].VAO);
components[i].vertex.setData(components[i].vertices.data(), sizeof(glm::vec3) * components[i].vertices.size(), 0);
components[i].uv.setData(components[i].uvs.data(), sizeof(glm::vec2) * components[i].uvs.size(), 1);
components[i].normal.setData(components[i].normals.data(), sizeof(glm::vec3) * components[i].normals.size(), 2);
components[i].vertex.activate();
components[i].uv.activate();
components[i].normal.activate();
glBindVertexArray(0);
你可以在 GitHub 上找到我的完整代码:https://github.com/Kuechenzwiebel/SDL-OpenGL-Tests
问题是,我的对象上显示的纹理是由最后一个渲染的对象使用的。
更新:删除纹理析构函数中的glDeleteTextures
,结果是所有组件上显示的纹理都是用于最后一个组件的纹理。
我真的不明白为什么这不起作用,我从其他只使用一种纹理的图元中复制了它。一切正常。
【问题讨论】:
您是否为每个纹理 (glGenTextures
) 生成并使用单独的对象(名称)值?
@Rabbid76 是的,我愿意。此外,我还有几个基元,每个基元都使用一个纹理,效果很好。
您需要提供minimal, reproducible example。
但这不是本网站的运作方式。 问题本身应包含所有信息。这也是为什么您应该创建一个重现问题的 minimal 示例(无论如何这都是一个很好的调试策略)。
好吧,我猜你的components.emplace_back(tmpComp)
调用ObjModelComponent
的隐式复制构造函数,而后者又调用Texture
的隐式复制构造函数,这意味着components[i].tex
和@ 987654338@ 现在引用相同的 GL 纹理对象。稍后,当您为tmpComp.tex
分配其他内容时,Texture::operator=()
将删除这个非常 GL 纹理对象,并创建一个新对象(可能与刚刚删除的对象名称相同,因此所有之前的组件都引用相同的名称)纹理对象,最后一次加载)。
【参考方案1】:
我找到了一种解决方法,我没有使用单独的 ArrayBuffers 和 VAO,而是只使用其中一个,并且还存储了新对象开始的索引。在那里我改变了使用的纹理。
【讨论】:
以上是关于多个 OpenGL 纹理在某些情况下不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
UIImageView autoresizingmask 在某些情况下不起作用