正如标题所示,我正在将一个场景渲染到一个帧缓冲区,并尝试在计算着色器中从该帧缓冲区提取颜色直方图。我对使用计算着色器完全是个新手,缺乏教程/示例/关键字让我不知所措。
特别是,我很难正确设置计算着色器的输入和输出图像。
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”)
我如何正确配置我的计算着色器?我的过程正确吗(至少在理论上),如果不正确,为什么?
1条答案
按热度按时间n8ghc7c11#
关于你的问题:
无法将布局(r16ui)应用到图像类型“image2D”
r16ui
只能应用于无符号图像类型,因此您应该使用uimage2D
。无法找到兼容的重载函数...
规范明确指出原子操作只能应用于32位类型(
r32i
、r32ui
或r32f
),因此必须使用32位纹理。您的代码中也存在其他问题。
你不能绑定一个FBO到一个纹理。你应该绑定支持FBO的纹理(
renderTexture
)。此外,您希望将纹理绑定到图像均匀而不是采样器,因此必须使用
glBindImageTexture
或glBindImageTextures
而不是glBindTexture
。使用后者,您可以在一次调用中绑定两个图像:您的
img_output
制服被标记为writeonly
。但是原子图像函数期望一个不合格的制服。因此删除writeonly
。您可以在OpenGL和GLSL规范中找到上述所有信息,这些规范可从the OpenGL registry免费访问。