OpenGL3显示错误的纹理

时间:2012-08-29 00:13:31

标签: c++ opengl sfml opengl-3

我正在尝试向我的程序添加第二个sampler2DRect纹理。我正在为第二个纹理使用单独的着色器文件,否则我使用的是用于显示第一个纹理的相同代码。但是,当我尝试显示第二个纹理时,它会显示第一个纹理,而我似乎无法找出原因。我可能做错了一个API调用,或者可能省略了一些重要的东西,但我没有尝试解决这个问题。

没有报告GL错误,gDEBugger没有显示任何可疑信息。

我想问题可能在我的代码中的其他地方,但是这里是我用来尝试绘制第二个纹理的部分(这几乎与用于绘制第一个纹理的代码相同):

Test_World_Pause_Menu::Test_World_Pause_Menu(int resolution_width, int resolution_height)
    : _shaders("shaders/pause_menu.vert", "shaders/pause_menu.frag"),
      _vao_id( new GLuint[1] ),
      _mvp_id( new GLint[1] ),
      _pm_tex_id( new GLuint[1] ),
      _mvp( glm::ortho(0.0f, (GLfloat)resolution_width, 0.0f, (GLfloat)resolution_height, -1.0f, 1.0f) ),
      _pm_vertices_buffer( new GLuint[1] ),
      _pm_vertices( new GLfloat[12] ),
      _pm_colors_buffer( new GLuint[1] ),
      _pm_colors( new GLfloat[16] ),
      _pm_tex_coords_buffer( new GLuint[1] ),
      _pm_tex_coords( new GLfloat[8] ),
      _pm_normals_buffer( new GLuint[1] ),
      _pm_normals( new GLfloat[12] )
{
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  // set alpha blending mode

    // begin pause menu initialization
    _pm_image.loadFromFile("resources/levels/test_00/pause_menu/pause_menu.png");
    _pm_image.flipVertically();

    unsigned int pm_location_x = 0;
    unsigned int pm_location_y = _pm_image.getSize().y;
    unsigned int pm_width = _pm_image.getSize().x;
    unsigned int pm_height = _pm_image.getSize().y;

    _pm_vertices[0] = pm_location_x; _pm_vertices[1] = pm_location_y; _pm_vertices[2] = 0.0f;
    _pm_vertices[3] = pm_location_x; _pm_vertices[4] = pm_location_y - pm_height; _pm_vertices[5] = 0.0f;
    _pm_vertices[6] = pm_location_x + pm_width; _pm_vertices[7] = pm_location_y - pm_height; _pm_vertices[8] = 0.0f;
    _pm_vertices[9] = pm_location_x + pm_width; _pm_vertices[10] = pm_location_y; _pm_vertices[11] = 0.0f;

    _pm_colors[0] = 1.0f; _pm_colors[1] = 1.0f; _pm_colors[2] = 1.0f; _pm_colors[3] = 0.0f;
    _pm_colors[4] = 1.0f; _pm_colors[5] = 1.0f; _pm_colors[6] = 1.0f; _pm_colors[7] = 0.0f;
    _pm_colors[8] = 1.0f; _pm_colors[9] = 1.0f; _pm_colors[10] = 1.0f; _pm_colors[11] = 0.0f;
    _pm_colors[12] = 1.0f; _pm_colors[13] = 1.0f; _pm_colors[14] = 1.0f; _pm_colors[15] = 0.0f;

    _pm_tex_coords[0] = 0.0f; _pm_tex_coords[1] = pm_height;
    _pm_tex_coords[2] = 0.0f; _pm_tex_coords[3] = 0.0f;
    _pm_tex_coords[4] = pm_width; _pm_tex_coords[5] = 0.0f;
    _pm_tex_coords[6] = pm_width; _pm_tex_coords[7] = pm_height;

    _pm_normals[0] = 0.0f; _pm_normals[1] = 0.0f; _pm_normals[2] = 0.0f;
    _pm_normals[3] = 0.0f; _pm_normals[4] = 0.0f; _pm_normals[5] = 0.0f;
    _pm_normals[6] = 0.0f; _pm_normals[7] = 0.0f; _pm_normals[8] = 0.0f;
    _pm_normals[9] = 0.0f; _pm_normals[10] = 0.0f; _pm_normals[11] = 0.0f;

    glGenVertexArrays(1, &_vao_id[0]); // generate VAO
    glBindVertexArray(_vao_id[0]);     // bind VAO

    // vertices
    glEnableVertexAttribArray((GLuint)0);
    glGenBuffers(1, &_pm_vertices_buffer[0]);
    glBindBuffer(GL_ARRAY_BUFFER, _pm_vertices_buffer[0]);
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), _pm_vertices.get(), GL_STATIC_DRAW);
    glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glEnableVertexAttribArray(0);

    // normals (inexplicably needed even though it won't be used in the shaders)
    glEnableVertexAttribArray((GLuint)1);
    glGenBuffers(1, &_pm_normals_buffer[0]);
    glBindBuffer(GL_ARRAY_BUFFER, _pm_normals_buffer[0]);
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), _pm_normals.get(), GL_STATIC_DRAW);
    glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glEnableVertexAttribArray(0);

    // texture
    glEnableVertexAttribArray((GLuint)2);
    glGenBuffers(1, &_pm_tex_coords_buffer[0]);
    glBindBuffer(GL_ARRAY_BUFFER, _pm_tex_coords_buffer[0]);
    glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _pm_tex_coords.get(), GL_STATIC_DRAW);
    glVertexAttribPointer((GLuint)2, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenTextures(1, &_pm_tex_id[0]);
    glBindTexture(GL_TEXTURE_RECTANGLE, _pm_tex_id[0]);

    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, pm_width, pm_height,
            0, GL_RGBA, GL_UNSIGNED_BYTE, _pm_image.getPixelsPtr());

    glEnableVertexAttribArray(0);

    // colors
    glEnableVertexAttribArray((GLuint)3);
    glGenBuffers(1, &_pm_colors_buffer[0]);
    glBindBuffer(GL_ARRAY_BUFFER, _pm_colors_buffer[0]);
    glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(GLfloat), _pm_colors.get(), GL_STATIC_DRAW);
    glVertexAttribPointer((GLuint)3, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glEnableVertexAttribArray(0);

    // unbind buffers
    glBindVertexArray(0);

    _mvp_id[0] = glGetUniformLocation(_shaders.id(), "mvpMatrix");
    _pm_tex_id[0] = glGetUniformLocation(_shaders.id(), "pauseMenuTex");
// end pause menu initialization
}

void Test_World_Pause_Menu::display()
{
    glEnable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);

    _shaders.bind();

        glUniformMatrix4fv(_mvp_id[0], 1, GL_FALSE, &_mvp[0][0]);

// begin pause menu rendering
        glUniform1i(_pm_tex_id[0], 0);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, _pm_tex_id[0]);

        glBindVertexArray(_vao_id[0]);     // bind the VAO

        // draw the contents of the bound VAO
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glBindVertexArray(0); // unbind the VAO
// end pause menu rendering

    _shaders.unbind();

    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);

    return;
}

以下是我正在使用的着色器:

顶点着色器

#version 150

in vec4 in_Position;
in vec3 in_Normal;
in vec2 in_UV;
in vec4 in_Color;

uniform mat4 mvpMatrix;

smooth out vec3 vVaryingNormal;
smooth out vec2 vVaryingTexCoord;
smooth out vec4 vVaryingColor;

void main(void) 
{
    vVaryingNormal = in_Normal;
    vVaryingTexCoord = in_UV;
    vVaryingColor = in_Color;

    gl_Position = mvpMatrix * in_Position;
}

片段着色器

#version 150

smooth in vec3 vVaryingNormal;
smooth in vec2 vVaryingTexCoord;
smooth in vec4 vVaryingColor;

uniform sampler2DRect pauseMenuTex;

out vec4 out_Color;

void main(void)
{ 
    out_Color.a = vVaryingColor.a;
    out_Color += texture(pauseMenuTex, vVaryingTexCoord);
}

我的猜测是我在某处没有正确地关闭某些纹理状态,但就像我说的那样,我没有尝试解决问题。如有必要,我可以为程序的其他部分发布代码。

编辑:在这个C ++代码中肯定有一些错误的API使用,以及第一个纹理的代码,因为当我删除第一个纹理的初始化和渲染函数时,第二个显示就好了。有人可以帮助我查明我的错误OpenGL用法(它可能在构造函数中)。

另一个编辑:经过进一步调查,我发现两个对象的构造函数中最先运行的是在两个显示例程中都显示纹理的构造函数。

3rd Edit:可能相关的东西:在构造函数中调用glTexImage2D()之后,将第一个纹理与glBindTexture(GL_TEXTURE_RECTANGLE,0)取消绑定,导致它在任何一个期间都不显示两个显示例程。对我来说这似乎是一个问题,它可能与我的另一个问题有关。

4 个答案:

答案 0 :(得分:6)

你的问题就在这里:

glGenTextures(1, &_pm_tex_id[0]);
...
_pm_tex_id[0] = glGetUniformLocation(_shaders.id(), "pauseMenuTex");

第一个语句创建一个纹理对象并将其存储到_pm_tex_id[0]中。下一个语句使用统一位置覆盖纹理对象。因此,您丢失纹理对象。它与调用new获取指针,然后稍后覆盖该指针没有什么不同;你无法取回它。

您的代码"工作的原因"在your revised solution中使用是因为保持它绑定到上下文(在不同的插槽中)。你绑定它用数据填充它,但你永远不会解除它。因此,上下文仍然具有您丢失的纹理对象。

您需要存储纹理名称和采样器统一位置单独。您应该使用比" id"更好的命名约定;统一位置不应具有与OpenGL对象名称相同的命名约定。这样,你就不会混淆他们。我建议" unif"制服而不是" id"。


其他不错的事情,只是不一定有用。

您经常致电:

glEnableVertexAttribArray(0);

无缘无故。与第一次启用属性相比,您无法启用属性0 更多;)

你还分配了很多1项的数组。那个真的是不必要的。如果您只想要一个VAO,只需创建一个GLuint变量。当你需要生成它时,只需要它的地址。

此外,停止分配如此多的内存周期。如果需要数组,请使用std::vector(您可以使用与当前完全相同的方式获取指向数组的指针:&vec[0])。这样,您就不必记得删除内存;当对象被销毁时,C ++会为你做。您已经在使用C ++了,所以您也可以使用该语言。

答案 1 :(得分:2)

我看到一个绑定到GL_TEXTURE_RECTANGLE,然后绑定到GL_TEXTURE_2D。这些应该是一样的吗?

答案 2 :(得分:2)

首先,我没有足够的声誉来发表评论,我不想编辑你的问题,因为如果这不起作用,请提前道歉。

您的解决方案(或解决方法)为每个纹理提供了自己的纹理槽,除非您想将多个纹理传递到同一个着色器,否则这些纹理槽不应该是必需的,因此肯定会发生冲突。

您可以从渲染过程中删除glUniform1i(_pm_tex_id[0], x);并将其放在构造函数中,因为在(重新)创建着色器程序后只需设置一次。

蒂姆发现不同的绑定电话后,你改变了吗?形成OpenGl文档:

  

创建后,可以根据需要将命名纹理重新绑定到同一原始目标

我肯定会改变它们,所以它们都是相同的(我会选择GL_TEXTURE_2D)。

您在其他地方进行与纹理相关的任何其他GL_ *调用吗?因为在第一个对象被绘制之后,它仍然像一个陈旧的参数。希望这有点帮助。

答案 3 :(得分:0)

我解决了这个问题,虽然我不确定为什么我的解决方案有效或者它正在做什么,但这里是:

对于第一个纹理,我在glGenTextures()的调用之上添加了glActiveTexture(GL_TEXTURE0)。

对于第二个纹理,我在glGenTextures()和display()函数的调用之上都使用了glActiveTexture(GL_TEXTURE1),并且我使用了glUniform1i(_pm_tex_id [0],1)而不是glUniform1i(_pm_tex_id [0 ],0)。

任何人都可以告诉我为什么这样做,如果这样做会限制sampler2DRect纹理的数量?我很确定GL_TEXTUREn的数量非常有限,无法激活。