如果现代 opengl 中有多个纹理,则没有纹理
No texture if multiple textures in modern opengl
我将 C++ 和 OpenGL 4.6 与 SDL2 和 glew 一起使用。
我有一个 class 纹理:
#include "stb_image/stb_image.h"
class Texture {
private:
unsigned int m_RendererID;
std::string m_FilePath;
unsigned char *m_LocalBuffer;
int m_Width, m_Height, m_BPP;
public:
Texture(const std::string &path);
~Texture();
void Bind(unsigned int slot = 0) const;
void Unbind() const;
inline int GetWidth() const { return m_Width; }
inline int GetHeight() const { return m_Height; }
inline int GetID() const { return m_RendererID; }
};
Texture::Texture(const std::string &path)
: m_RendererID(0), m_FilePath(path), m_LocalBuffer(nullptr), m_Width(0), m_Height(0), m_BPP(0)
{
stbi_set_flip_vertically_on_load(1); //Flip vertically because OpenGL renders texture in the opposite way
m_LocalBuffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_BPP, 4);
GLCall(glGenTextures(1, &m_RendererID));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer));
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
if (m_LocalBuffer) {
stbi_image_free(m_LocalBuffer);
}
}
Texture::~Texture() {
GLCall(glDeleteTextures(1, &m_RendererID));
}
void Texture::Bind(unsigned int slot) const {
GLCall(glActiveTexture(GL_TEXTURE0 + slot));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
}
void Texture::Unbind() const {
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
}
如果我创建一个纹理,纹理显示:
Texture texture("ship.png");
texture.Bind(0);
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 0);
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
但是如果我创建两个纹理,我只会得到黑屏:
Texture texture("ship.png");
texture.Bind(0);
Texture texture2("ship2.png");
texture2.Bind(1);
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 0);
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
这应该有效。我在互联网上搜索了 2 个小时,但我似乎无法找到这行不通的原因。你们能帮帮我吗?
在以下代码行的末尾
Texture texture("ship.png");
texture.Bind(0);
Texture texture2("ship2.png");
texture2.Bind(1);
第二个纹理对象 ("ship2.png") 绑定到纹理单元 1,但默认纹理对象 (0) 绑定到纹理单元 0。
注意,当调用 Texture texture("ship.png");
时,纹理对象被创建并绑定到当前纹理单元,之后默认纹理对象 (0) 被绑定到当前纹理单元:
Texture::Texture(const std::string &path) {
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
// [...]
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
}
请注意,您所说的 "unbind" 不会解除任何绑定。 glBindTexture(GL_TEXTURE_2D, 0)
将默认纹理对象 (0) 绑定到当前活动的纹理单元。没有必要这样做。
只需更改说明的顺序即可解决您的问题。首先创建并加载纹理对象。然后将纹理对象绑定到纹理单元:
Texture texture("ship.png");
Texture texture2("ship2.png");
texture.Bind(0);
texture2.Bind(1);
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 0);
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
作为替代方案,您可以避免使用纹理单元 0。使用纹理单元 0 仅用于创建纹理对象:
Texture::Texture(const std::string &path, unsigned int slot) {
GLCall(glActiveTexture(GL_TEXTURE0));
// [...]
}
Texture texture("ship.png");
texture.Bind(1); // <--- 1
Texture texture2("ship2.png");
texture2.Bind(2); // <--- 2
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 1); // <--- 1
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
或者在classTexture
的构造函数中添加纹理单元的参数:
Texture::Texture(const std::string &path, unsigned int slot) {
GLCall(glGenTextures(1, &m_RendererID));
GLCall(glActiveTexture(GL_TEXTURE0 + slot));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
// [...]
// GLCall(glBindTexture(GL_TEXTURE_2D, 0)); <--- delete
}
Texture texture("ship.png", 0);
Texture texture2("ship2.png", 1);
我将 C++ 和 OpenGL 4.6 与 SDL2 和 glew 一起使用。 我有一个 class 纹理:
#include "stb_image/stb_image.h"
class Texture {
private:
unsigned int m_RendererID;
std::string m_FilePath;
unsigned char *m_LocalBuffer;
int m_Width, m_Height, m_BPP;
public:
Texture(const std::string &path);
~Texture();
void Bind(unsigned int slot = 0) const;
void Unbind() const;
inline int GetWidth() const { return m_Width; }
inline int GetHeight() const { return m_Height; }
inline int GetID() const { return m_RendererID; }
};
Texture::Texture(const std::string &path)
: m_RendererID(0), m_FilePath(path), m_LocalBuffer(nullptr), m_Width(0), m_Height(0), m_BPP(0)
{
stbi_set_flip_vertically_on_load(1); //Flip vertically because OpenGL renders texture in the opposite way
m_LocalBuffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_BPP, 4);
GLCall(glGenTextures(1, &m_RendererID));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer));
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
if (m_LocalBuffer) {
stbi_image_free(m_LocalBuffer);
}
}
Texture::~Texture() {
GLCall(glDeleteTextures(1, &m_RendererID));
}
void Texture::Bind(unsigned int slot) const {
GLCall(glActiveTexture(GL_TEXTURE0 + slot));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
}
void Texture::Unbind() const {
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
}
如果我创建一个纹理,纹理显示:
Texture texture("ship.png");
texture.Bind(0);
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 0);
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
但是如果我创建两个纹理,我只会得到黑屏:
Texture texture("ship.png");
texture.Bind(0);
Texture texture2("ship2.png");
texture2.Bind(1);
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 0);
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
这应该有效。我在互联网上搜索了 2 个小时,但我似乎无法找到这行不通的原因。你们能帮帮我吗?
在以下代码行的末尾
Texture texture("ship.png"); texture.Bind(0); Texture texture2("ship2.png"); texture2.Bind(1);
第二个纹理对象 ("ship2.png") 绑定到纹理单元 1,但默认纹理对象 (0) 绑定到纹理单元 0。
注意,当调用 Texture texture("ship.png");
时,纹理对象被创建并绑定到当前纹理单元,之后默认纹理对象 (0) 被绑定到当前纹理单元:
Texture::Texture(const std::string &path) { GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID)); // [...] GLCall(glBindTexture(GL_TEXTURE_2D, 0)); }
请注意,您所说的 "unbind" 不会解除任何绑定。 glBindTexture(GL_TEXTURE_2D, 0)
将默认纹理对象 (0) 绑定到当前活动的纹理单元。没有必要这样做。
只需更改说明的顺序即可解决您的问题。首先创建并加载纹理对象。然后将纹理对象绑定到纹理单元:
Texture texture("ship.png");
Texture texture2("ship2.png");
texture.Bind(0);
texture2.Bind(1);
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 0);
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
作为替代方案,您可以避免使用纹理单元 0。使用纹理单元 0 仅用于创建纹理对象:
Texture::Texture(const std::string &path, unsigned int slot) {
GLCall(glActiveTexture(GL_TEXTURE0));
// [...]
}
Texture texture("ship.png");
texture.Bind(1); // <--- 1
Texture texture2("ship2.png");
texture2.Bind(2); // <--- 2
shader.Bind();
va.Bind();
ib.Bind();
shader.SetUniform1i("u_Texture", 1); // <--- 1
glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr);
或者在classTexture
的构造函数中添加纹理单元的参数:
Texture::Texture(const std::string &path, unsigned int slot) {
GLCall(glGenTextures(1, &m_RendererID));
GLCall(glActiveTexture(GL_TEXTURE0 + slot));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
// [...]
// GLCall(glBindTexture(GL_TEXTURE_2D, 0)); <--- delete
}
Texture texture("ship.png", 0);
Texture texture2("ship2.png", 1);