OpenGL3 отображает неправильную текстуру

Я пытаюсь добавить в свою программу вторую текстуру 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);
}

Я предполагаю, что я где-то здесь неправильно отключаю какое-то состояние текстуры, но, как я уже сказал, ничто из того, что я пытаюсь, не решает проблему. При необходимости могу разместить код для других частей программы.

Изменить: определенно существует некорректное использование API в этом коде C ++, а также в коде для первой текстуры, потому что, когда я удаляю функции инициализации и рендеринга для первой текстуры, отображается вторая. просто хорошо. Может ли кто-нибудь помочь мне определить мое неправильное использование OpenGL (вероятно, в конструкторе).

Другое редактирование: При дальнейшем исследовании я обнаружил, что какой из конструкторов двух объектов запускается первым, это тот, текстура которого отображается во время обеих процедур отображения.

3-е изменение: кое-что, что может иметь отношение: отвязка первой текстуры с glBindTexture (GL_TEXTURE_RECTANGLE, 0) после вызова glTexImage2D () в конструкторе приводит к тому, что она вообще не отображается во время любой из двух процедур отображения . Мне это кажется проблемой, и это может быть связано с другой моей проблемой.


person Defcronyke    schedule 29.08.2012    source источник


Ответы (4)


Ваша проблема прямо здесь:

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

Первый оператор создает объект текстуры и сохраняет его в _pm_tex_id[0]. Следующая инструкция перезаписывает объект текстуры с неизменным местоположением. Таким образом, вы теряете объект текстуры. Это ничем не отличается от вызова new для получения указателя с последующей перезаписью этого указателя; ты не можешь вернуть это.

Причина, по которой ваш код "работает" с вашим измененным решением, заключается в том, что вы сохранили его привязку к контексту (в другом слоте). Вы связали его, чтобы заполнить данными, но никогда не отвязываете. Таким образом, в контексте все еще есть объект текстуры, который вы потеряли.

Вам необходимо сохранить имя текстуры и единое расположение сэмплера отдельно. Вам следует использовать лучшие соглашения об именах, чем "id"; единообразные местоположения не должны иметь тех же соглашений об именах, что и имена объектов OpenGL. Так вы их не запутаете. Я бы посоветовал для униформы использовать «unif» вместо «id».


Другие вещи, которые не являются неправильными, но не обязательно полезными.

Вы часто звоните:

glEnableVertexAttribArray(0);

Без причины. Вы не можете сделать атрибут 0 более включенным, чем в первый раз;)

Вы также выделяете много массивов по 1 элементу. В этом действительно нет необходимости. Если вам нужен только один VAO, просто создайте переменную GLuint. Когда вам нужно его сгенерировать, просто возьмите его адрес.

Кроме того, перестаньте выделять так много памяти. Если вам нужен массив, используйте std::vector (вы можете получить указатель на массив точно так же, как сейчас: &vec[0]). Таким образом, вам не придется забывать стирать память; C ++ сделает это за вас, когда объект будет уничтожен. Вы уже используете C ++, так что можете фактически использовать этот язык.

person Nicol Bolas    schedule 29.08.2012
comment
Спасибо, что поправили меня! Вы абсолютно правы насчет моей проблемы, и теперь я называю их _mvp_loc _tex_loc и т. Д. Теперь, когда я привязываюсь к GL_TEXTURE_RECTANGLE во время функции draw (), она больше не выдает ошибку 502, и я могу отвязать текстуру, не пропуская ее. К вашему сведению, все эти динамические распределения находятся в C ++ 11 std :: unique_ptr ‹GLuint []›, поэтому мне никогда не нужно их освобождать, и я использую массивы, потому что мне очень скоро может понадобиться более одного из всего. - person Defcronyke; 29.08.2012

Я вижу одну привязку к GL_TEXTURE_RECTANGLE, а более позднюю привязку к GL_TEXTURE_2D. Должны ли они быть такими же?

person Tim    schedule 29.08.2012
comment
Когда я привязываюсь к GL_TEXTURE_RECTANGLE во время функции display (), он дает мне GL_INVALID_OPERATION, но когда я использую цель, которую использую, она, кажется, работает. За исключением ошибки 502, поведение кажется идентичным для любой цели. - person Defcronyke; 29.08.2012
comment
Звучит странно. Почему это работает в одном месте, а не в другом? Можете ли вы дважды проверить, что он исходит от glBindTexture? У меня нет точного представления о том, что делают эти объекты текстуры, но что-то здесь не так. - person Tim; 29.08.2012
comment
Единственная разница между использованием 2D и ПРЯМОУГОЛЬНИКА, кажется, заключается в том, что ПРЯМОУГОЛЬНИК дает мне ошибку 502. Первая текстура отображается в обоих случаях в любом случае. - person Defcronyke; 29.08.2012
comment
То же самое и в коде для первой текстуры. - person Defcronyke; 29.08.2012
comment
Хм, извините, тогда я не знаю. - person Tim; 29.08.2012
comment
В любом случае спасибо, что посмотрели на него, я буду пробовать разные вещи и отправлю ответ, если найду решение - person Defcronyke; 29.08.2012
comment
В заключение, какой конструктор запускается первым, это тот конструктор, текстура которого отображается во время обеих процедур отображения ... - person Defcronyke; 29.08.2012

Во-первых, у меня недостаточно репутации, чтобы публиковать комментарии, и мне не хотелось редактировать ваш вопрос по поводу того, что я собираюсь сказать, поэтому заранее извиняюсь, если это не сработает.

Ваше решение (или обходной путь) дает каждой текстуре свой собственный слот текстуры, в котором нет необходимости, если вы не хотите передавать несколько текстур одному и тому же шейдеру, поэтому определенно происходит конфликт.

Вы можете удалить glUniform1i(_pm_tex_id[0], x); из процедуры рендеринга и поместить его в конструктор, так как он должен быть установлен только один раз после (повторного) создания вашей шейдерной программы.

Вы изменили это после того, как Тим заметил различные вызовы привязки? Сформируйте документы OpenGl:

После создания именованная текстура может быть повторно привязана к той же исходной цели так часто, как это необходимо.

Я бы определенно поменял их, чтобы они оба были идентичными (я бы выбрал GL_TEXTURE_2D).

Вы делаете какие-либо другие вызовы GL_ *, связанные с текстурами где-то еще? Потому что это пахнет устаревшим параметром, который все еще висит после отрисовки первого объекта. Надеюсь, это поможет.

person pauluss86    schedule 29.08.2012

Я решил проблему, хотя я не уверен, почему мое решение сработало или на самом деле, что оно делает, но вот оно:

Для первой текстуры я добавил glActiveTexture (GL_TEXTURE0) над вызовом glGenTextures ().

Для второй текстуры я использовал glActiveTexture (GL_TEXTURE1) как над вызовом glGenTextures (), так и в функции display (), и я использовал glUniform1i (_pm_tex_id [0], 1) вместо glUniform1i (_pm_tex_id [0], 0 ).

Может ли кто-нибудь сказать мне, почему это сработало, и если это будет ограничивать количество текстур sampler2DRect? Я почти уверен, что доступно очень ограниченное количество GL_TEXTUREn для активации.

person Defcronyke    schedule 29.08.2012
comment
Это решает проблему в том смысле, что проблема больше не возникает. Но проблема не в этом. - person Nicol Bolas; 29.08.2012
comment
Вы правы, и я бы не стал считать это решением. Ваш ответ - это реальное решение, так что еще раз спасибо! - person Defcronyke; 29.08.2012