Проблема с imageStore() (OpenGL 4.3)
Я пытаюсь вывести некоторые данные из вычислительного шейдера в текстуру, но imageStore(), кажется, ничего не делает. Вот шейдер:
#version 430
layout(RGBA32F) uniform image2D image;
layout (local_size_x = 1, local_size_y = 1) in;
void main() {
imageStore(image, ivec2(gl_GlobalInvocationID.xy), vec4(0.0f, 1.0f, 1.0f, 1.0f));
}
и код приложения здесь:
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
glBindImageTexture(0, tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glUseProgram(program->GetName());
glUniform1i(program->GetUniformLocation("image"), 0);
glDispatchCompute(WIDTH, HEIGHT, 1);
затем с этой текстурой рендерится полноэкранный квад, но в данный момент он показывает только некоторые случайные старые данные из видеопамяти Есть идеи, что может быть не так?
РЕДАКТИРОВАТЬ:
Вот как я отображаю текстуру:
// This comes right after the previous block of code
glUseProgram(drawProgram->GetName());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(drawProgram->GetUniformLocation("sampler"), 0);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers();
и drawProgram состоит из:
#version 430
#extension GL_ARB_explicit_attrib_location : require
layout(location = 0) in vec2 position;
out vec2 uvCoord;
void main() {
gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);
uvCoord = position;
}
а также:
#version 430
in vec2 uvCoord;
out vec4 color;
uniform sampler2D sampler;
void main() {
vec2 uv = (uvCoord + vec2(1.0f)) / 2.0f;
uv.y = 1.0f - uv.y;
color = texture(sampler, uv);
//color = vec4(uv.x, uv.y, 0.0f, 1.0f);
}
Последняя закомментированная строка в фрагментном шейдере производит этот вывод: вывод Render
Объект массива вершин (vao) имеет один буфер с 6 2D вершинами:
-1,0, -1,0
1,0, -1,0
1,0, 1,0
1,0, 1,0
-1,0, 1,0
-1,0, -1,0
3 ответа
Вот как я отображаю текстуру:
Это не достаточно хорошо. Я не вижу звонкаglMemoryBarrier
, так что нет гарантии, что ваш код действительно работает.
Помните: записи в изображения через Image Load/Store не связаны с памятью. Они требуют явной пользовательской синхронизации, прежде чем они станут видимыми. Если вы хотите использовать изображение, которое вы сохранили в качестве текстуры позже, должно быть явное glMemoryBarrier
вызывать после команды рендеринга, которая записывает в него, но перед командой рендеринга, которая выбирает из нее текстуру.
Почему это проблема, я не знаю
Потому что рабочий стол OpenGL не является OpenGL ES.
Последние три параметра описывают только расположение данных пикселей, которые вы предоставляете OpenGL. Они ничего не меняют в том, как OpenGL хранит данные. В ES они делают, но это только потому, что ES не выполняет преобразование формата.
В настольном OpenGL совершенно законно загружать данные с плавающей точкой в нормализованную целочисленную текстуру; Ожидается, что OpenGL преобразует данные как можно лучше. ES не выполняет преобразования, поэтому он должен изменить внутренний формат (третий параметр), чтобы он соответствовал данным.
Рабочего стола GL нет. Если вы хотите определенный формат изображения, вы просите его. Desktop GL дает вам то, что вы просите, и только то, что вы просите.
Всегда используйте размерные внутренние форматы.
GL_RGBA - это не внутренний формат, поэтому вы не можете знать, что это такое. Чаще всего он преобразуется в GL_RGBA8 с помощью OpenGL.
В вашем случае параметр GL_FLOAT, который вы устанавливаете, описывает только пиксельные данные, которые вы можете загрузить в текстуру.
Прочитайте таблицу 2 здесь, чтобы узнать, что вы можете установить в качестве внутреннего формата текстуры.
Хорошо, я нашел решение. Проблема заключается здесь:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
эта строка не определяет размер внутреннего формата (GL_RGBA). Когда я поставил GL_RGBA32F, он начал работать. Почему это проблема, я не знаю (надеюсь, кто-нибудь сможет объяснить).