c++ - 在计算着色器中计算帧缓冲区的颜色直方图

标签 c++ opengl glsl compute-shader

正如标题所示,我正在将场景渲染到帧缓冲区上,并尝试从计算着色器内的帧缓冲区中提取颜色直方图。我对使用计算着色器完全陌生,缺乏教程/示例/关键字让我不知所措。

特别是,我正在努力正确设置计算着色器的输入和输出图像。这是我拥有的:

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 的二维纹理图像,其中 N 是 bin 的数量,3 占个别颜色成分。在着色器中,我从输入图像中获取一个像素值,将其缩放到 0-255 范围内并增加直方图中的适当位置。

我无法验证这是否按预期工作,因为计算着色器会产生编译错误,即:

  • 无法将布局 (r16ui) 应用于图像类型 "image2D"
  • 无法找到兼容的重载函数“imageAtomicAdd(struct image2D1x16_bindless, ivec2, int)”
  • 编辑:更改为 r32ui 后,先前的错误现在变为:合格的实际参数 #1 无法转换为不太合格的参数(“im”)

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

最佳答案

关于您的问题:

can't apply layout(r16ui) to image type "image2D"

r16ui 只能应用于无符号图像类型,因此您应该使用 uimage2D

unable to find compatible overloaded function ...

规范明确指出原子操作只能应用于 32 位类型(r32ir32uir32f)。因此,您必须改用 32 位纹理。


您的代码中还有其他问题。

glBindTexture(GL_TEXTURE_2D, renderFBO);

您不能将 FBO 绑定(bind)到纹理。您应该改为绑定(bind)支持 FBO 的纹理 (renderTexture)。

此外,您打算将纹理绑定(bind)到图像制服而不是采样器,因此您必须使用 glBindImageTextureglBindImageTextures 而不是 glBindTexture。使用后者,您可以在一个调用中绑定(bind)两个图像:

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

您的 img_output uniform 被标记为 writeonly。然而,原子图像函数需要一个不合格的制服。所以删除writeonly


您可以在 OpenGL 和 GLSL 规范中找到上述所有信息,可从 the OpenGL registry 免费访问.

关于c++ - 在计算着色器中计算帧缓冲区的颜色直方图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70161571/

相关文章:

glsl - OpenFL - 为着色器提供时间

ios - GL_HALF_FLOAT_OES 和 glReadPixels

javascript - 三.JS | GLSL 通过场景纹理设置粒子颜色

C++/错误 : expression must have integral or unscoped enum type

c++ - std::shared_ptr 中的错误?

c++ - 控制如何将参数从子类构造函数声明发送到父类(super class)构造函数 (C++)

c++ - 了解 OpenGL

c++ - 当我在调用追加后立即实例化一个节点时,链表被破坏

c++ - 如何更改 OpenGL 形状的线宽?

c++ - c++中基于点的重力示例