【问题标题】:Can't load multiple texture on OpenGL无法在 OpenGL 上加载多个纹理
【发布时间】:2020-02-21 16:07:53
【问题描述】:

我正在尝试在 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 的一些功能抽象为 ShaderTexture 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));
}

现在,我没有从两个纹理中获得均匀的颜色混合,而是只让第二个纹理出现并与背景混合:

我已经将问题定位到Texture 实现的constructor,如果我注释掉第二个纹理的初始化,例如它的constructor 永远不会被调用,那么我可以获得第一个纹理出现。

谁能建议我做错了什么?

【问题讨论】:

    标签: c++ opengl textures


    【解决方案1】:

    我花了一段时间才发现,但是在您调用第二个纹理的构造函数时,您的 活动纹理单元 仍然为 0,因此构造函数很高兴地重新指向您的纹理单元,而您是剩下两个纹理单元绑定到同一个纹理。

    解决方案应该足够简单:不要将纹理创建和纹理单元分配交错,首先创建纹理,然后然后显式绑定它们。

    更好的是,考虑使用direct state access 来避免所有这些绑定。

    为了突出这个问题的未来观众的问题,这是有问题的调用顺序:

    // 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.
    

    【讨论】:

    • 那么规范中的缓冲区和纹理之间存在不一致?因为绑定缓冲区是我编辑的内容,如果纹理单元处于活动状态,那么最初使用该单元激活的纹理对象被编辑?因为在我的constructor 中我毕竟绑定了一个新纹理
    • 您的构造函数调用glBindTexture 将当前纹理单元 (0) 的当前目标 (GL_TEXTURE_2D) 重新绑定到新创建的纹理。
    • @Rabbid76 你确定吗?因为我在绑定纹理之前将GLCALL(glActiveTexture(GL_TEXTURE0 + unit)); 移动到constructor,现在它工作正常
    猜你喜欢
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多