Данные текстуры не используются во фрагментном шейдере - OpenGL

Я практикую текстуры в OpenGL, применяя простую текстуру белого цвета к квадрату. Код компилируется и работает нормально, но цвет квадрата просто черный, а не белый, как я указал.

Я думаю, это потому, что мой фрагментный шейдер не выполняет правильную выборку, это похоже на то, что данные, которые он возвращает из функции texture, равны нулю, поэтому текстура четырехугольника становится черной. Причина, по которой я так подозреваю, заключается в том, что, когда я запускаю программу, я могу сделать чистый белый цвет и немного сдвинуть одну из вершин на четырехугольнике, чтобы увидеть фон (поскольку он обычно заполняет всю поверхность). Тогда я могу ясно видеть белый фон с черным квадратом сверху. Таким образом, некоторый выходной цвет создается из фрагментного шейдера, это просто неправильный цвет, поскольку предоставленный мной небольшой массив пикселей имеет только белый цвет. Проблема в том, что я точно не знаю, почему код, который у меня есть, дает неверные результаты. Я пытаюсь следовать за книгой, в которой используется или менее тот же код. Я также пробовал искать его в разных руководствах, но все они, похоже, используют один и тот же подход, поэтому я застрял.

[РЕДАКТИРОВАТЬ]

Я обнаружил некоторые проблемы. Выполнив отслеживание ошибок с помощью glGetError (), я понял, что эта строка моего кода:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

возвращает код ошибки 1282 (Недопустимая операция) из-за того, что второй параметр level равен 0. Если я установил для него значение 1, ошибка исчезнет. Тогда проблема становится такой:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);

Что возвращает ту же ошибку, но не исправляется изменением параметра level.

Это фрагментный и вершинный шейдер, который я использую:

Фрагментный шейдер

// FRAGMENT SHADER
#version 330

uniform sampler2D tex;

in vec2 vs_tex_coord;

layout (location = 0) out vec4 outputColor;

void main(void)
{
    outputColor = texture(tex, vs_tex_coord);
}

Вершинный шейдер

// VERTEX SHADER
#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 in_tex_coord;

uniform vec2 offset;

out vec2 vs_tex_coord;

void main(void)
{
    vec4 finalOffset = vec4(offset.x, offset.y, 0.0, 0.0);
    gl_Position = position + finalOffset;
    vs_tex_coord = in_tex_coord;
}

Код, который я использую для создания и хранения текстурных объектов, довольно прост:

glGenTextures(1, &textureHandle);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureHandle);

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

const GLubyte myTexture[] = {0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF};

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);

myTexture просто содержит текстуру 4x4 во внутреннем формате RGB, где каждый компонент имеет 4 бита. Я установил их все в белый цвет.

Затем я просто создаю сэмплер по умолчанию, например:

glGenSamplers(1, &mySampler);

glBindSampler(0, mySampler);

И наконец рендер:

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glUseProgram(theProgram);

GLuint samplerLoc = glGetUniformLocation(theProgram, "tex");

if (samplerLoc == -1)
    printf("Location name could not be found...\n");

glUniform1i(samplerLoc, 0);

glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(16 * sizeof(float)));

glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

Массив, который я загружаю в VBO:

const float vertexPositions[] =
{
    // Vertex position
    -0.8f, -1.0f, 0.0f, 1.0f,
     1.0f, -1.0f, 0.0f, 1.0f,
     1.0f,  1.0f, 0.0f, 1.0f,
    -1.0f,  1.0f, 0.0f, 1.0f,

    // Texture coordinates
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f
};

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

Для всех, кто интересуется, визуальный результат таков: введите здесь описание изображения

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


person CodingBeagle    schedule 09.08.2013    source источник
comment
glTexStorage2D +1 за использование неизменяемых текстур.   -  person Nicol Bolas    schedule 09.08.2013
comment
Я не вижу той части, где вы привязываете текстуру к контексту для использования шейдером. Я вижу, где вы инициализируете текстуру, но связываете ли вы ее при фактическом рендеринге? Или вы просто предполагаете, что ничто другое не развяжет текстуру между инициализацией и использованием?   -  person Nicol Bolas    schedule 09.08.2013
comment
Да, я просто предполагал, что ничто другое не отвяжет текстуру между инициализацией и использованием (с тех пор, как я в первый раз привязываю ее для ее изменения). Тем не менее, я просто попытался вызвать glBindTexture (GL_TEXTURE_2D, textureHandle); внутри реального игрового цикла перед вызовом glDrawArrays. К сожалению, похоже, не повлияло :(   -  person CodingBeagle    schedule 09.08.2013
comment
кстати, если вы являетесь автором arcsynthesis.org/gltut (что может быть указано в вашем профиле), просто хотел поблагодарить вас :) Это было очень необходимое введение для новичков в программирование графики и немного OpenGL, оно заполнило пустоту, которая означала, что я начал со всего этого в первую очередь. Я все еще слежу за мной :)   -  person CodingBeagle    schedule 09.08.2013
comment
ничто другое не отвяжет текстуру между инициализацией и использованием Не будет. Но когда вы пытаетесь найти ошибки, лучше быть конкретным; никогда не знаешь, когда может случиться заблудший glBindTexture, и не знаешь об этом.   -  person Nicol Bolas    schedule 09.08.2013
comment
Хороший момент :) В любом случае я переместил glBindTexture в процедуру рендеринга, и, к сожалению, это не решило ее, хотя, по крайней мере, теперь эта часть кажется более ясной.   -  person CodingBeagle    schedule 09.08.2013
comment
Итак, я нашел кое-что интересное. Я попытался проверить ошибки с помощью OpenGL (черт возьми, урок извлечен! Всегда проверяйте ошибки ...!). В любом случае, я обнаружил, что в строке glTexStorage2D (GL_TEXTURE_2D, 0, GL_RGB8, 4, 4); при использовании glGetError я получаю код ошибки 1282. Я обнаружил, что это GL_INVALID_OPERATION. Хотя я не мог понять, почему, кроме того, что это связано с параметром Levels, равным 0. Если я установил его на 1, я не получу от него никаких ошибок.   -  person CodingBeagle    schedule 09.08.2013
comment
Затем я вместо этого получаю тот же код ошибки в glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);, даже если я изменю этот параметр уровня на 1. Там происходит что-то странное ...   -  person CodingBeagle    schedule 09.08.2013


Ответы (1)


Хорошо, после некоторого отслеживания ошибок я наконец нашел проблему! :) Для тех, кто столкнется с этой проблемой в будущем, вот (очень простое ... уф!) Решение.

Прежде всего, вот эта строчка:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

Возвращена ошибка OpenGL 1281 (недопустимая операция), потому что второй параметр levels должен быть как минимум 1, чтобы хранить достаточно памяти для базового изображения, независимо от того, хотите ли вы использовать MIP-карты или нет (который, как я думал, должен быть 0). Поэтому изменение его с 0 на 1 исправило его.

Во-вторых, эта строка:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);

Возникла проблема с параметром format, где указано GL_R в приведенном выше фрагменте. Это было совершенно неправильно. Глядя на официальную документацию для функции, говорится об этом:

формат Определяет формат данных пикселей. Допускаются следующие символические значения: GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT и GL_STENCIL_INDEX.

Тип, который я ранее указывал в glTextStorage2D, использует GL_RGB8, который имеет базовый внутренний формат GL_RGB, правильная версия:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);

Исправление этих двух проблем привело к появлению текстурированного результата :)

person CodingBeagle    schedule 09.08.2013