计算着色器 - gl_GlobalInspirationID 和 local_size

Now*_*-01 4 opengl compute-shader

在尝试实现一个将影响灯光分配给集群的简单计算着色器时,我遇到了意外的行为(对于像我这样的菜鸟来说):

我使用 glDispatchCompute(32, 32, 32); 调用此着色器 它应该为每次调用写入一个[轻计数器+8个索引]到“索引”缓冲区。但是在调试时,我发现即使我使用唯一的 clusterId,我对缓冲区的写入也会在调用之间重叠。我通过索引[outIndexStart] 的值超过 8 和视觉闪烁来检测它。

根据文档,gl_GlobalInitationID是gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInitationID。但如果将所有本地大小设置为 1,写入问题就会消失。为什么 local_size 会以这种方式影响这段代码?我该如何推理在这里选择它的价值?

#version 430
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;

uniform int lightCount;

const unsigned int clusterSize = 32;
const unsigned int clusterSquared = clusterSize * clusterSize;

struct LightInfo {
    vec4 color;
    vec3 position;
    float radius;
};

layout(std430, binding = 0) buffer occupancyGrid {
    int exists[];
};

layout(std430, binding = 2) buffer lightInfos
{
  LightInfo lights [];
};

layout(std430, binding = 1) buffer outputList {
    int indices[];
};

void main(){
    unsigned int clusterId = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * clusterSize + gl_GlobalInvocationID.z * clusterSquared;

    if(exists[clusterId] == 0)
        return;

    //... not so relevant calculations

    unsigned int outIndexStart = clusterId * 9;
    unsigned int outOffset = 1;

    for(int i = 0; i < lightCount && outOffset < 9; i++){
        if(distance(lights[i].position, wordSpace.xyz) < lights[i].radius) {
            indices[outIndexStart + outOffset] = i;
            indices[outIndexStart]++;
            outOffset++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 5

我们来看两个声明:

layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
Run Code Online (Sandbox Code Playgroud)

const unsigned int clusterSize = 32;
Run Code Online (Sandbox Code Playgroud)

这些说的是不同的事情。声明local_size中说每个工作组将有 4x4x4 次调用,即 64 次。相比之下,您clusterSize说每个工作组只有 32 次调用。

如果要解决此问题,请使用系统提供的实际本地大小常量

const unsigned int clusterSize = gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z;
Run Code Online (Sandbox Code Playgroud)

你甚至可以这样做:

const uvec3 linearizeInvocation = uvec3{1, clusterSize, clusterSize * clusterSize};

...

unsigned int clusterId = dot(gl_GlobalInvocationID, linearizeInvocation);
Run Code Online (Sandbox Code Playgroud)