c++ - 无法在 OpenGL 上加载多个纹理
问题描述
我正在尝试在 openGL 中加载多个纹理。为了验证这一点,我想加载 2 个纹理并将它们与以下片段着色器混合:
#version 330 core
out vec4 color;
in vec2 v_TexCoord;
uniform sampler2D u_Texture0;
uniform sampler2D u_Texture1;
void main()
{
color = mix(texture(u_Texture0, v_TexCoord), texture(u_Texture1, v_TexCoord), 0.5);
}
我将 OpenGL 的一些功能抽象到诸如等之类的类Shader
中Texture
UniformXX
。
这是尝试将 2 个纹理加载到片段的采样器单元中:
Shader shader;
shader.Attach(GL_VERTEX_SHADER, "res/shaders/vs1.shader");
shader.Attach(GL_FRAGMENT_SHADER, "res/shaders/fs1.shader");
shader.Link();
shader.Bind();
Texture texture0("res/textures/container.jpg", GL_RGB, GL_RGB);
texture0.Bind(0);
Uniform1i textureUnit0Uniform("u_Texture0");
textureUnit0Uniform.SetValues({ 0 });
shader.SetUniform(textureUnit0Uniform);
Texture texture1("res/textures/awesomeface.png", GL_RGBA, GL_RGBA);
texture1.Bind(1);
Uniform1i textureUnit1Uniform("u_Texture1");
textureUnit1Uniform.SetValues({ 1 });
shader.SetUniform(textureUnit1Uniform);
下面是Texture
实现的样子:
#include "Texture.h"
#include "Renderer.h"
#include "stb_image/stb_image.h"
Texture::Texture(const std::string& path, unsigned int destinationFormat, unsigned int sourceFormat)
: m_Path(path)
{
stbi_set_flip_vertically_on_load(1);
m_Buffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_BPP, 0);
GLCALL(glGenTextures(1, &m_RendererID));
GLCALL(glBindTexture(GL_TEXTURE_2D, m_RendererID));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, destinationFormat, m_Width, m_Height, 0, sourceFormat, GL_UNSIGNED_BYTE, m_Buffer));
glGenerateMipmap(GL_TEXTURE_2D);
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
if (m_Buffer)
stbi_image_free(m_Buffer);
}
Texture::~Texture()
{
GLCALL(glDeleteTextures(1, &m_RendererID));
}
void Texture::Bind(unsigned int unit) const
{
GLCALL(glActiveTexture(GL_TEXTURE0 + unit));
GLCALL(glBindTexture(GL_TEXTURE_2D, m_RendererID));
}
void Texture::Unbind() const
{
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
}
现在,我实际上并没有从两个纹理中获得均匀的颜色混合,而是只得到第二个纹理出现并与背景混合:
我已经确定了实现的问题constructor
,Texture
如果我注释掉第二个纹理的初始化,例如它constructor
永远不会被调用,那么我可以让第一个纹理显示出来。
谁能建议我做错了什么?
解决方案
花了我一段时间才发现,但是在调用第二个纹理的构造函数时,你的活动纹理单元仍然是 0,所以构造函数很高兴地重新指向你的纹理单元,你剩下两个纹理单元绑定到同一个纹理.
解决方案应该足够简单:不要交错创建纹理和纹理单元分配,首先创建纹理,然后显式绑定它们。
更好的是,考虑使用直接状态访问来避免所有这些绑定。
为了突出这个问题的未来观众的问题,这是有问题的调用序列:
// constructor of texture 1
glGenTextures(1, &container)
glBindTexture(GL_TEXTURE_2D, container) // Texture Unit 0 is now bound to container
// explicit texture0.Bind call
glActiveTexture(GL_TEXTURE0) // noop
glBindTexture(GL_TEXTURE_2D, container) // Texture Unit 0 is now bound to container
// constructor of texture 2
glGenTextures(1, &awesomeface)
glBindTexture(GL_TEXTURE_2D, awesomeface) // Texture Unit 0 is now bound to awesomeface instead of container.
// explicit texture1.Bind call
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, awesomeface) // Texture Unit 0 and 1 are now bound to awesomeface.
推荐阅读
- css - 如何使用css制作颜色渐变
- visual-studio - 删除以前的版本不会替换 DLL 的
- html - 将一个形状用作另一个形状的孔
- stream - microsoft stream api 发布了吗?
- angular - 如何修复“你似乎不依赖于“@angular/core”和/或“rxjs”。在离子
- buffer - 在 c 中使用 FreeRTOS 的简单输入和输出缓冲区示例
- javascript - 如何制作具有多个端点的 php API
- autodesk-forge - 如何在 Autodesk Forge 查看器中本地化对象的标高或楼层
- performance - 每条指令分析的 x86 程序
- docker - 删除 docker 镜像会影响缓存吗