All checks were successful
Build (Arch Linux) / build (push) Successful in 3m10s
81 lines
3.1 KiB
Plaintext
81 lines
3.1 KiB
Plaintext
#version 460 core
|
|
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
|
|
|
const uint MAX_NUM_LIGHTS = 100u;
|
|
|
|
struct cluster {
|
|
vec4 min_point;
|
|
vec4 max_point;
|
|
uint count;
|
|
uint light_indices[MAX_NUM_LIGHTS];
|
|
};
|
|
|
|
layout(std430, binding = 1) restrict buffer cluster_buf {
|
|
cluster clusters[];
|
|
};
|
|
|
|
uniform float z_near;
|
|
uniform float z_far;
|
|
uniform mat4 inverse_proj_mat;
|
|
uniform uvec3 grid_size;
|
|
uniform uvec2 screen_dimensions;
|
|
|
|
vec3 screen_to_view(vec2 screen_coord);
|
|
vec3 line_intersection_with_z_plane(vec3 start_point, vec3 end_point, float z_distance);
|
|
|
|
/*
|
|
context: glViewport is referred to as the "screen"
|
|
clusters are built based on a 2d screen-space grid and depth slices.
|
|
Later when shading, it is easy to figure what cluster a fragment is in based on
|
|
gl_FragCoord.xy and the fragment's z depth from camera
|
|
*/
|
|
void main() {
|
|
uint tile_idx =
|
|
gl_WorkGroupID.x + (gl_WorkGroupID.y * grid_size.x) + (gl_WorkGroupID.z * grid_size.x * grid_size.y);
|
|
vec2 tile_size = screen_dimensions / grid_size.xy;
|
|
|
|
// tile in screen-space
|
|
vec2 min_tile_screen = gl_WorkGroupID.xy * tile_size;
|
|
vec2 max_tile_screen = (gl_WorkGroupID.xy + 1) * tile_size;
|
|
|
|
// convert tile to view space sitting on the near plane
|
|
vec3 min_tile = screen_to_view(min_tile_screen);
|
|
vec3 max_tile = screen_to_view(max_tile_screen);
|
|
|
|
float plane_near = z_near * pow(z_far / z_near, gl_WorkGroupID.z / float(grid_size.z));
|
|
float plane_far = z_near * pow(z_far / z_near, (gl_WorkGroupID.z + 1) / float(grid_size.z));
|
|
|
|
// the line goes from the eye position in view space (0, 0, 0)
|
|
// through the min/max points of a tile to intersect with a given cluster's near-far planes
|
|
vec3 min_point_near = line_intersection_with_z_plane(vec3(0, 0, 0), min_tile, plane_near);
|
|
vec3 min_point_far = line_intersection_with_z_plane(vec3(0, 0, 0), min_tile, plane_far);
|
|
vec3 max_point_near = line_intersection_with_z_plane(vec3(0, 0, 0), max_tile, plane_near);
|
|
vec3 max_point_far = line_intersection_with_z_plane(vec3(0, 0, 0), max_tile, plane_far);
|
|
|
|
clusters[tile_idx].min_point = vec4(min(min_point_near, min_point_far), 0.0);
|
|
clusters[tile_idx].max_point = vec4(max(max_point_near, max_point_far), 0.0);
|
|
}
|
|
|
|
// Returns the intersection point of an infinite line and a
|
|
// plane perpendicular to the Z-axis
|
|
vec3 line_intersection_with_z_plane(vec3 start_point, vec3 end_point, float z_distance) {
|
|
vec3 direction = end_point - start_point;
|
|
vec3 normal = vec3(0.0, 0.0, -1.0); // plane normal
|
|
|
|
// skip check if the line is parallel to the plane.
|
|
|
|
float t = (z_distance - dot(normal, start_point)) / dot(normal, direction);
|
|
return start_point + t * direction; // the parametric form of the line equation
|
|
}
|
|
|
|
vec3 screen_to_view(vec2 screen_coord) {
|
|
// normalize screen_coord to [-1, 1] and
|
|
// set the NDC depth of the coordinate to be on the near plane. This is -1 by
|
|
// default in OpenGL
|
|
vec4 ndc = vec4(screen_coord / screen_dimensions * 2.0 - 1.0, -1.0, 1.0);
|
|
|
|
vec4 view_coord = inverse_proj_mat * ndc;
|
|
view_coord /= view_coord.w;
|
|
return view_coord.xyz;
|
|
}
|