Created
July 28, 2020 09:19
-
-
Save NotAPenguin0/d792a560653216fb53b3eb07f21cce6e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| void calculate_depth_range() { | |
| // Coordinate of the pixel on screen | |
| ivec2 screen_pixel = ivec2(gl_GlobalInvocationID.xy); | |
| vec2 UV = vec2(screen_pixel) / pc.screen_size; | |
| ivec2 tex_size = ivec2(textureSize(depth_map)); | |
| ivec2 texels = ivec2(UV * tex_size); | |
| float depth = texelFetch(depth_map, texels, 0).r; | |
| // Depth values must be linearized because we stored them after applying projection | |
| depth = (0.5 * camera.projection[3][2]) / (depth + 0.5 * camera.projection[2][2] - 0.5); | |
| // Convert depth to uint so we can do atomic comparisons between threads | |
| uint depth_int = floatBitsToUint(depth); | |
| atomicMin(tile_data.min_depth_int, depth_int); | |
| atomicMax(tile_data.min_depth_int, depth_int); | |
| } | |
| void create_frustum() { | |
| if (gl_LocalInvocationIndex == 0) { | |
| // ID of this tile. | |
| ivec2 tile_id = ivec2(gl_WorkGroupID.xy); | |
| // Total amount of tiles, specified in vkCmdDispatch. Same as the workgroup count. | |
| ivec2 tile_count = ivec2(gl_NumWorkGroups.xy); | |
| // Get back floating point values for the depth | |
| float min_depth = uintBitsToFloat(tile_data.min_depth_int); | |
| float max_depth = uintBitsToFloat(tile_data.max_depth_int); | |
| // Scale step with tile size | |
| vec2 negative_step = (2.0 * vec2(tile_id)) / vec2(tile_count); | |
| vec2 positive_step = (2.0 * vec2(tile_id + ivec2(1, 1))) / vec2(tile_count); | |
| // Create basic planes, these still need to be transformed (multiply by view_projection and apply perspective division). | |
| tile_data.frustum.planes[0] = vec4(1.0, 0.0, 0.0, 1.0 - negative_step.x); // Left | |
| tile_data.frustum.planes[1] = vec4(-1.0, 0.0, 0.0, -1.0 + positive_step.x); // Right | |
| tile_data.frustum.planes[2] = vec4(0.0, 1.0, 0.0, 1.0 - negative_step.y); // Bottom | |
| tile_data.frustum.planes[3] = vec4(0.0, -1.0, 0.0, -1.0 + positive_step.y); // Top | |
| tile_data.frustum.planes[4] = vec4(0.0, 0.0, -1.0, -min_depth); // Near | |
| tile_data.frustum.planes[5] = vec4(0.0, 0.0, 1.0, max_depth); // Far | |
| // Transform the first four planes (left, right, bottom, top) | |
| for (uint i = 0; i < 4; i++) { | |
| tile_data.frustum.planes[i] *= camera.projection_view; | |
| tile_data.frustum.planes[i] /= length(tile_data.frustum.planes[i].xyz); | |
| } | |
| // Transform the depth planes. We do these separately because we don't want to apply the projection matrix here (since we're working | |
| // with linearized depth values). | |
| tile_data.frustum.planes[4] *= camera.view; | |
| tile_data.frustum.planes[4] /= length(tile_data.frustum.planes[4].xyz); | |
| tile_data.frustum.planes[5] *= camera.view; | |
| tile_data.frustum.planes[5] /= length(tile_data.frustum.planes[5].xyz); | |
| } | |
| } | |
| void cull_lights() { | |
| const uint thread_count = TILE_SIZE * TILE_SIZE; | |
| const uint thread_index = gl_LocalInvocationIndex; | |
| // Since we can process 256 lights simultaneously, we need additional passes of 256 lights if we exceed this limit. | |
| const uint light_count = lights.data.length(); | |
| const uint pass_count = (light_count + thread_count - 1) / thread_count; | |
| // Each thread processes one light per pass | |
| for (uint pass = 0; pass < pass_count; ++pass) { | |
| // Get the light index for this thread in this pass. If this index is out of bounds, we can stop testing lights on this thread. | |
| const uint light_index = pass * thread_count + thread_index; | |
| if (light_index >= light_count) { break; } | |
| // Read relevant light data from buffer | |
| const vec4 position = vec4(lights.data[light_index].transform.xyz, 1); | |
| const float radius = lights.data[light_index].transform.w; | |
| // Check if the light is inside the tile frustum | |
| float dist = 0; | |
| for (uint plane = 0; plane < 6; ++plane) { | |
| dist = dot(position, tile_data.frustum.planes[plane]) + radius; | |
| // If one of the distance tests fails, the light is not inside the tile frustum and we don't need to check the other planes | |
| if (dist < 0.0) { | |
| break; | |
| } | |
| } | |
| // If all distance tests succeeded, dist is now positive and the light is visible in the current tile. | |
| if (dist > 0.0) { | |
| // Add one to the amount of visible lights in this tile, and retrieve old amount. This old amount of the index at which we | |
| // have to store the light's index. | |
| const uint write_index = atomicAdd(tile_data.visible_light_count, 1); | |
| tile_data.visible_lights[write_index] = int(light_index); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment