// bounding boxes of the light clusters in view space, see gl/cluster_grid.h // one invocation per cluster, run when the projection or the depth range of the pass changes #include layout(local_size_x = CLUSTER_BUILD_GROUP_SIZE) in; // clip space w at the lower boundary of slice k: the inverse of the slice formula used when shading float slice_depth(uint k) { return exp((float(k) - cluster_slice_bias) / cluster_slice_scale); } void main() { uint index = gl_GlobalInvocationID.x; if (index >= uint(CLUSTER_COUNT)) return; uvec3 cell = uvec3( index % uint(CLUSTER_GRID_X), (index / uint(CLUSTER_GRID_X)) % uint(CLUSTER_GRID_Y), index / uint(CLUSTER_GRID_X * CLUSTER_GRID_Y)); // clip x, y and w are affine functions of the view space position, while clip z is constant (reverse z with // the far plane at infinity), which makes the projection matrix singular. the position is recovered from // those three alone, so off-axis and rotated screens of custom viewports and vr eyes work too mat3 linear = mat3( vec3(cluster_projection[0][0], cluster_projection[0][1], cluster_projection[0][3]), vec3(cluster_projection[1][0], cluster_projection[1][1], cluster_projection[1][3]), vec3(cluster_projection[2][0], cluster_projection[2][1], cluster_projection[2][3])); vec3 translation = vec3(cluster_projection[3][0], cluster_projection[3][1], cluster_projection[3][3]); mat3 unproject = inverse(linear); // the tile in clip space xy, the slice in clip space w vec2 tiles = vec2(CLUSTER_GRID_X, CLUSTER_GRID_Y); vec2 ndc_min = vec2(cell.xy) / tiles * 2.0 - 1.0; vec2 ndc_max = vec2(cell.xy + 1U) / tiles * 2.0 - 1.0; float w_near = slice_depth(cell.z); float w_far = slice_depth(cell.z + 1U); vec3 lower = vec3(3.402823e38); vec3 upper = vec3(-3.402823e38); for (int corner = 0; corner < 8; ++corner) { vec2 ndc = vec2( (corner & 1) != 0 ? ndc_max.x : ndc_min.x, (corner & 2) != 0 ? ndc_max.y : ndc_min.y); float w = (corner & 4) != 0 ? w_far : w_near; vec3 position = unproject * (vec3(ndc * w, w) - translation); lower = min(lower, position); upper = max(upper, position); } cluster_aabbs[index].lower = vec4(lower, 0.0); cluster_aabbs[index].upper = vec4(upper, 0.0); }