Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
323 lines (258 sloc)
8.91 KB
This file contains 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
| #version 450 | |
| layout(local_size_x = 64) in; | |
| #define CLUSTERER_BINDLESS | |
| #include "clusterer_data.h" | |
| layout(push_constant) uniform Registers | |
| { | |
| mat4 view; | |
| uint num_lights; | |
| } registers; | |
| layout(std140, set = 1, binding = 0) uniform ClustererParameters | |
| { | |
| ClustererParametersBindless parameters; | |
| }; | |
| layout(std430, set = 0, binding = 0) readonly buffer ClustererData | |
| { | |
| ClustererBindlessTransforms cluster_transforms; | |
| }; | |
| const uint MAX_TRIANGLES = 8; | |
| struct CullSetup | |
| { | |
| vec4 data[4 * MAX_TRIANGLES]; | |
| }; | |
| struct TransformedSpot | |
| { | |
| vec4 clip[5]; | |
| vec4 z; | |
| }; | |
| layout(std430, set = 0, binding = 1) readonly buffer TransformedSpots | |
| { | |
| TransformedSpot spots[]; | |
| } transformed; | |
| layout(std430, set = 0, binding = 2) writeonly buffer CullingSetup | |
| { | |
| CullSetup data[]; | |
| } culling_setup; | |
| vec2 project_sphere_flat(float view_xy, float view_z, float radius) | |
| { | |
| float len = length(vec2(view_xy, view_z)); | |
| float sin_xy = radius / len; | |
| vec2 result; | |
| if (sin_xy < 0.999) | |
| { | |
| float cos_xy = sqrt(1.0 - sin_xy * sin_xy); | |
| vec2 rot_lo = mat2(cos_xy, sin_xy, -sin_xy, cos_xy) * vec2(view_xy, view_z); | |
| vec2 rot_hi = mat2(cos_xy, -sin_xy, +sin_xy, cos_xy) * vec2(view_xy, view_z); | |
| if (rot_lo.y <= 0.0) | |
| rot_lo = vec2(-1.0, 0.0); | |
| if (rot_hi.y <= 0.0) | |
| rot_hi = vec2(+1.0, 0.0); | |
| result = vec2(rot_lo.x / rot_lo.y, rot_hi.x / rot_hi.y); | |
| } | |
| else | |
| result = vec2(-1.0 / 0.0, +1.0 / 0.0); | |
| return result; | |
| } | |
| void clip_single_output(out mat3x2 clipped, vec3 c0, vec3 c1, vec3 c2, float target) | |
| { | |
| float la = (target - c0.z) / (c2.z - c0.z); | |
| float lb = (target - c1.z) / (c2.z - c1.z); | |
| c0 = mix(c0, c2, la); | |
| c1 = mix(c1, c2, lb); | |
| clipped = mat3x2(c0.xy, c1.xy, c2.xy); | |
| } | |
| void clip_dual_output(out mat3x2 clipped0, out mat3x2 clipped1, vec3 c0, vec3 c1, vec3 c2, float target) | |
| { | |
| float l_ab = (target - c0.z) / (c1.z - c0.z); | |
| float l_ac = (target - c0.z) / (c2.z - c0.z); | |
| vec3 ab = mix(c0, c1, l_ab); | |
| vec3 ac = mix(c0, c2, l_ac); | |
| clipped0 = mat3x2(ab.xy, c1.xy, ac.xy); | |
| clipped1 = mat3x2(ac.xy, c1.xy, c2.xy); | |
| } | |
| void clip_single_output(out mat3 clipped, vec4 c0, vec4 c1, vec4 c2, float target) | |
| { | |
| float la = (target - c0.w) / (c2.w - c0.w); | |
| float lb = (target - c1.w) / (c2.w - c1.w); | |
| c0 = mix(c0, c2, la); | |
| c1 = mix(c1, c2, lb); | |
| clipped = mat3(c0.xyz / target, c1.xyz / target, c2.xyz / c2.w); | |
| } | |
| void clip_dual_output(out mat3 clipped0, out mat3 clipped1, vec4 c0, vec4 c1, vec4 c2, float target) | |
| { | |
| float l_ab = (target - c0.w) / (c1.w - c0.w); | |
| float l_ac = (target - c0.w) / (c2.w - c0.w); | |
| vec4 ab = mix(c0, c1, l_ab); | |
| vec4 ac = mix(c0, c2, l_ac); | |
| clipped0 = mat3(ab.xyz / target, c1.xyz / c1.w, ac.xyz / target); | |
| clipped1 = mat3(ac.xyz / target, c1.xyz / c1.w, c2.xyz / c2.w); | |
| } | |
| float cross_2d(vec2 a, vec2 b) | |
| { | |
| return a.x * b.y - a.y * b.x; | |
| } | |
| void setup_triangle(inout uint num_triangles, mat3x2 triangle, float cull) | |
| { | |
| vec2 c0 = triangle[0]; | |
| vec2 c1 = triangle[1]; | |
| vec2 c2 = triangle[2]; | |
| vec2 ab = c1 - c0; | |
| vec2 bc = c2 - c1; | |
| vec2 ca = c0 - c2; | |
| float z = cross_2d(ab, -ca); | |
| if (abs(z) < 0.000001 || sign(cull) == sign(z)) | |
| return; | |
| float inv_z = 1.0 / z; | |
| vec3 base = inv_z * vec3(cross_2d(ab, -c0), cross_2d(bc, -c1), cross_2d(ca, -c2)); | |
| vec3 dx = inv_z * vec3(-ab.y, -bc.y, -ca.y); | |
| vec3 dy = inv_z * vec3(ab.x, bc.x, ca.x); | |
| if (num_triangles < MAX_TRIANGLES) | |
| { | |
| culling_setup.data[gl_GlobalInvocationID.x].data[4u * num_triangles] = vec4(base, 0.0); | |
| culling_setup.data[gl_GlobalInvocationID.x].data[4u * num_triangles + 1u] = vec4(dx, z); | |
| culling_setup.data[gl_GlobalInvocationID.x].data[4u * num_triangles + 2u] = vec4(dy, inv_z); | |
| culling_setup.data[gl_GlobalInvocationID.x].data[4u * num_triangles + 3u] = vec4(min(min(c0, c1), c2), max(max(c0, c1), c2)); | |
| } | |
| num_triangles++; | |
| } | |
| void setup_triangle(inout uint num_triangles, mat3 triangle, float cull) | |
| { | |
| vec3 c0 = triangle[0]; | |
| vec3 c1 = triangle[1]; | |
| vec3 c2 = triangle[2]; | |
| bvec3 clip_z = greaterThan(vec3(c0.z, c1.z, c2.z), vec3(1.0)); | |
| uint clip_code = uint(clip_z.x) + uint(clip_z.y) * 2u + uint(clip_z.z) * 4u; | |
| mat3x2 clipped0, clipped1; | |
| bool dual = false; | |
| switch (clip_code) | |
| { | |
| case 0: | |
| clipped0 = mat3x2(c0.xy, c1.xy, c2.xy); | |
| break; | |
| case 1: | |
| clip_dual_output(clipped0, clipped1, c0, c1, c2, 1.0); | |
| dual = true; | |
| break; | |
| case 2: | |
| clip_dual_output(clipped0, clipped1, c1, c2, c0, 1.0); | |
| dual = true; | |
| break; | |
| case 4: | |
| clip_dual_output(clipped0, clipped1, c2, c0, c1, 1.0); | |
| dual = true; | |
| break; | |
| case 3: | |
| clip_single_output(clipped0, c0, c1, c2, 1.0); | |
| break; | |
| case 5: | |
| clip_single_output(clipped0, c2, c0, c1, 1.0); | |
| break; | |
| case 6: | |
| clip_single_output(clipped0, c1, c2, c0, 1.0); | |
| break; | |
| case 7: | |
| return; | |
| } | |
| setup_triangle(num_triangles, clipped0, cull); | |
| if (dual) | |
| setup_triangle(num_triangles, clipped1, cull); | |
| } | |
| void setup_triangle(inout uint num_triangles, vec4 c0, vec4 c1, vec4 c2, float cull) | |
| { | |
| const float MIN_W = 1.0 / 1024.0; | |
| bvec3 clip_w = lessThan(vec3(c0.w, c1.w, c2.w), vec3(MIN_W)); | |
| uint clip_code = uint(clip_w.x) + uint(clip_w.y) * 2u + uint(clip_w.z) * 4u; | |
| mat3 clipped0; | |
| mat3 clipped1; | |
| bool dual = false; | |
| switch (clip_code) | |
| { | |
| case 0: | |
| clipped0 = mat3(c0.xyz / c0.w, c1.xyz / c1.w, c2.xyz / c2.w); | |
| break; | |
| case 1: | |
| clip_dual_output(clipped0, clipped1, c0, c1, c2, MIN_W); | |
| dual = true; | |
| break; | |
| case 2: | |
| clip_dual_output(clipped0, clipped1, c1, c2, c0, MIN_W); | |
| dual = true; | |
| break; | |
| case 4: | |
| clip_dual_output(clipped0, clipped1, c2, c0, c1, MIN_W); | |
| dual = true; | |
| break; | |
| case 3: | |
| clip_single_output(clipped0, c0, c1, c2, MIN_W); | |
| break; | |
| case 5: | |
| clip_single_output(clipped0, c2, c0, c1, MIN_W); | |
| break; | |
| case 6: | |
| clip_single_output(clipped0, c1, c2, c0, MIN_W); | |
| break; | |
| case 7: | |
| return; | |
| } | |
| setup_triangle(num_triangles, clipped0, cull); | |
| if (dual) | |
| setup_triangle(num_triangles, clipped1, cull); | |
| } | |
| void main() | |
| { | |
| uint index = gl_GlobalInvocationID.x; | |
| if (index >= registers.num_lights) | |
| return; | |
| bool point = (cluster_transforms.type_mask[index >> 5u] & (1u << (index & 31u))) != 0u; | |
| if (point) | |
| { | |
| vec3 pos = cluster_transforms.lights[index].position; | |
| float radius = 1.0 / cluster_transforms.lights[index].inv_radius; | |
| vec3 view = (registers.view * vec4(pos, 1.0)).xyz; | |
| view.yz = -view.yz; | |
| vec4 ranges = vec4(project_sphere_flat(view.x, view.z, radius), | |
| project_sphere_flat(view.y, view.z, radius)); | |
| float xy_length = length(vec2(view.x, view.y)); | |
| mat2 clip_transform; | |
| if (xy_length < 0.00001) | |
| clip_transform = mat2(1.0); | |
| else | |
| { | |
| float inv_xy_length = 1.0 / xy_length; | |
| clip_transform = mat2(view.x, -view.y, view.y, view.x) * inv_xy_length; | |
| } | |
| vec2 transformed_xy = clip_transform * view.xy; | |
| vec4 transformed_ranges = vec4(project_sphere_flat(transformed_xy.x, view.z, radius), | |
| project_sphere_flat(transformed_xy.y, view.z, radius)); | |
| bool ellipsis = all(not(isinf(transformed_ranges))); | |
| vec2 center = (transformed_ranges.xz + transformed_ranges.yw) * 0.5; | |
| vec2 ellipse_radius = transformed_ranges.yw - center; | |
| ranges = ranges * parameters.clip_scale.xxyy; | |
| culling_setup.data[index].data[0] = ranges.xzyw; | |
| culling_setup.data[index].data[1] = transformed_ranges; | |
| culling_setup.data[index].data[2] = vec4(clip_transform[0], clip_transform[1]); | |
| culling_setup.data[index].data[3] = vec4(float(ellipsis), 1.0 / ellipse_radius.xy, 0.0); | |
| } | |
| else | |
| { | |
| vec4 z = transformed.spots[index].z; | |
| if (z.x != 0.0) | |
| { | |
| uint num_triangles = 0u; | |
| vec4 c0 = transformed.spots[index].clip[0]; | |
| vec4 c1 = transformed.spots[index].clip[1]; | |
| vec4 c2 = transformed.spots[index].clip[2]; | |
| vec4 c3 = transformed.spots[index].clip[3]; | |
| vec4 c4 = transformed.spots[index].clip[4]; | |
| setup_triangle(num_triangles, c0, c1, c2, z.x); | |
| setup_triangle(num_triangles, c0, c2, c3, z.x); | |
| setup_triangle(num_triangles, c0, c3, c4, z.x); | |
| setup_triangle(num_triangles, c0, c4, c1, z.x); | |
| setup_triangle(num_triangles, c2, c1, c3, z.x); | |
| setup_triangle(num_triangles, c4, c3, c1, z.x); | |
| culling_setup.data[index].data[0].w = uintBitsToFloat(num_triangles); | |
| } | |
| else | |
| culling_setup.data[index].data[0].w = uintBitsToFloat(0xffffffffu); | |
| } | |
| } |