opengl 计算计算着色器内部帧缓冲区的颜色直方图

rpppsulh  于 2023-01-02  发布在  其他
关注(0)|答案(1)|浏览(157)

正如标题所示,我正在将一个场景渲染到一个帧缓冲区,并尝试在计算着色器中从该帧缓冲区提取颜色直方图。我对使用计算着色器完全是个新手,缺乏教程/示例/关键字让我不知所措。
特别是,我很难正确设置计算着色器的输入和输出图像。

computeShaderProgram = loadComputeShader("test.computeshader");

int bin_size = 1;
int num_bins = 256 / bin_size;
tex_w = 1024;
tex_h = 768;

GLuint renderFBO, renderTexture;
GLuint tex_output;

//defining output image that will contain the histogram
glGenTextures(1, &tex_output);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_output);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, num_bins, 3, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R16UI);

//defining the framebuffer the scene will be rendered on
glGenFramebuffers(1, &renderFBO);

glGenTextures(1, &renderTexture);
glBindTexture(GL_TEXTURE_2D, renderTexture);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W_WIDTH, W_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glBindFramebuffer(GL_FRAMEBUFFER, renderFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

在主循环中,我在帧缓冲区上绘制了一个简单的正方形,并尝试将帧缓冲区作为输入图像传递给计算着色器:

glBindFramebuffer(GL_FRAMEBUFFER, renderFBO);
glDrawArrays(GL_TRIANGLES, 0, 6);

glUseProgram(computeShaderProgram);
//use as input the drawn framebuffer
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderFBO);
//use as output a pre-defined texture image
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex_output);
//run compute shader
glDispatchCompute((GLuint)tex_w, (GLuint)tex_h, 1);

GLuint *outBuffer = new GLuint[num_bins * 3];
glGetTexImage(GL_TEXTURE_2D, 0, GL_R16, GL_UNSIGNED_INT, outBuffer);

最后,在计算着色器中,我有:

#version 450
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform readonly image2D img_input;
layout(r16ui, binding = 1) uniform writeonly image2D img_output;

void main() {

    // grabbing pixel value from input image  
    vec4 pixel_color = imageLoad(img_input, ivec2(gl_GlobalInvocationID.xy));

    vec3 rgb = round(pixel_color.rgb * 255);

    ivec2 r = ivec2(rgb.r, 0);
    ivec2 g = ivec2(rgb.g, 1);
    ivec2 b = ivec2(rgb.b, 2);

    imageAtomicAdd(img_output, r, 1);
    imageAtomicAdd(img_output, g, 1);
    imageAtomicAdd(img_output, b, 1);
}

我将输出定义为N x 3大小的2d纹理图像,其中N是bin的数量,3表示各个颜色分量。在着色器中,我从输入图像中获取像素值,将其缩放到0-255范围,并在直方图中增加适当的位置。
我无法验证这是否按预期工作,因为计算着色器会产生编译错误,即:

  • 不能应用布局(r16 ui)到图像类型"image2D"
  • 无法找到兼容的重载函数"imageAtomicAdd(struct image2D1x16_bindless, ivec2, int)"
  • 编辑:更改为r32ui后,之前的错误现在变为:限定的实际参数#1不能转换为限定较少的参数(“im”)

我如何正确配置我的计算着色器?我的过程正确吗(至少在理论上),如果不正确,为什么?

n8ghc7c1

n8ghc7c11#

关于你的问题:
无法将布局(r16ui)应用到图像类型“image2D”
r16ui只能应用于无符号图像类型,因此您应该使用uimage2D
无法找到兼容的重载函数...
规范明确指出原子操作只能应用于32位类型(r32ir32uir32f),因此必须使用32位纹理。
您的代码中也存在其他问题。

glBindTexture(GL_TEXTURE_2D, renderFBO);

你不能绑定一个FBO到一个纹理。你应该绑定支持FBO的纹理(renderTexture)。
此外,您希望将纹理绑定到图像均匀而不是采样器,因此必须使用glBindImageTextureglBindImageTextures而不是glBindTexture。使用后者,您可以在一次调用中绑定两个图像:

GLuint images[] = { renderTexture, tex_output };
glBindImageTextures(0, 2, images);

您的img_output制服被标记为writeonly。但是原子图像函数期望一个不合格的制服。因此删除writeonly
您可以在OpenGL和GLSL规范中找到上述所有信息,这些规范可从the OpenGL registry免费访问。

相关问题