我已经在OpenGL 4+中编写了球形跟踪算法的实现。
作为一个实验/玩具项目,我正在使用OpenGL 4.3计算着色器重新实现它,但整个过程都遇到了麻烦本地/全局调用ID事物。
基本思想是使用计算着色器计算图像并将其输出为纹理,然后使用简单程序将其复制到帧缓冲区。

这是我正在使用的计算着色器:

#version 430 core

layout (binding = 0, rgba32f) writeonly uniform image2D output_image;
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;

void main()
{
    ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
    imageStore(output_image, coord, vec4(0.0, 0.0, 1.0, 1.0));
}


这是初始化纹理的方式:

GLuint offscreen_texture;
glGenTextures(1, &offscreen_texture);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, offscreen_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WINDOW_WIDTH, WINDOW_HEIGHT, 0, GL_RGBA, GL_FLOAT, nullptr);
glBindImageTexture(0, offscreen_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);


这些是我使用的普通顶点着色器:

#version 430 core

void main()
{
    const vec4 verts[4] = vec4[4](vec4(-1.0, -1.0, 0.5, 1.0),
                                  vec4( 1.0, -1.0, 0.5, 1.0),
                                  vec4(-1.0,  1.0, 0.5, 1.0),
                                  vec4( 1.0,  1.0, 0.5, 1.0));

    gl_Position = verts[gl_VertexID];
}


和片段:

#version 430 core

layout (location = 0) out vec4 color_out;
layout(binding = 0) uniform sampler2D source_image;

void main()
{
    color_out = texture(source_image, gl_FragCoord.xy);
}


这是渲染代码:

compute_program.use();
glDispatchCompute(WINDOW_WIDTH / 16, WINDOW_HEIGHT / 16, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

copy_program.use();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


至此,一切正常,我看到我的屏幕完全是蓝色,而不是通常的清晰颜色。 >
当我尝试使用调用ID生成实际数据(如来自相机的光线)时,事情开始崩溃。 br />我尝试切换到计算着色器,例如:

#version 430 core

layout (binding = 0, rgba32f) writeonly uniform image2D output_image;
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;

void main()
{
    ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
    imageStore(output_image, coord, vec4(0.0, 0.0, coord.x / 1280.0, 1.0));
}


,它使用全局ID生成像素的蓝色。
从OpenGL Suberbible书和OpenGL Wiki上了解,我应该能够将全局ID用作屏幕空间坐标(很容易使用本地ID和工作组ID进行数学运算并确认),就像gl_FragCoord一样,以前的琐碎计算着色器已证实了这一点,该着色器会绘制每个像素。

此计算着色器的输出是一种从黑色到蓝色的水平渐变,但一切都会变成黑色。
我尝试了基于线程的本地/全局ID的“绘画”的几种组合,但是无论如何我都没有运气。

我是否误解了整个过程线程ID是否起作用?
使用它们/将它们映射到屏幕空间坐标(例如gl_FragCoord)的正确方法是什么?

编辑:只是要补充一点,我已经使用集成的Intel HD 5100和离散的Nvidia 765M GPU进行了测试,结果是相同的,所以我这边显然有问题。

#1 楼

问题实际上出在您的片段着色器中:

color_out = texture(source_image, gl_FragCoord.xy);


texture()函数接受范围为0.0到1.0的归一化坐标。内置的gl_FragCoord包含范围从(0.0,0.0)到(窗口宽度,窗口高度)的窗口坐标。

要解决此问题,请将片段着色器更改为此:

color_out = texture(source_image, gl_FragCoord.xy / vec2(1280.0, 720.0));


假设您的窗口是1280x720,请根据需要进行更改。

评论


$ \ begingroup $
哇,我现在想死:(我什至说我希望gl_GlobalInvocationID的行为类似于gl_FragCoord,它使用窗口坐标。这是有史以来最愚蠢的错误之一。
$ \ endgroup $
–马特奥·贝特洛(Matteo Bertello)
2015年10月20日在21:56