1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
vec4 unProject(vec4 clipSpace)
{
vec4 homo = inv_camera_projection * clipSpace;
homo.xyz /= homo.w;
homo.w = 0.0f;
return homo;
}
vec4 createPlaneEquation(vec4 b, vec4 c)
{
vec4 n;
n.xyz = normalize(cross(b.xyz, c.xyz));
n.w = 0;
return n;
}
layout(local_size_x = CULL_TILE_COUNT, local_size_y = CULL_TILE_COUNT, local_size_z = 1) in;
void main()
{
ivec2 globalID = ivec2(gl_GlobalInvocationID.xy);
ivec2 localID = ivec2(gl_LocalInvocationID.xy);
ivec2 tileID = ivec2(gl_WorkGroupID.xy);
ivec2 tileNumber = ivec2(gl_NumWorkGroups.xy);
uint index = tileID.y * tileNumber.x + tileID.x;
// Initialize shared global values for depth and light count
if(gl_LocalInvocationIndex == 0)
{
screenSize = textureSize(depth_texture, 0);
visibleLightCount = 0;
}
barrier();
if(gl_LocalInvocationIndex == 0)
{
float minX = ((tileID.x / float(CULL_TILE_COUNT)) * 2.0f) - 1.0f;
float minY = ((tileID.y / float(CULL_TILE_COUNT)) * 2.0f) - 1.0f;
float maxX = (((tileID.x + 1) / float(CULL_TILE_COUNT)) * 2.0f) - 1.0f;
float maxY = (((tileID.y + 1) / float(CULL_TILE_COUNT)) * 2.0f) - 1.0f;
vec4 corners[4];
// 3-------2
// | |
// | |
// 0-------1
corners[0] = unProject(vec4(minX, minY, 1.0f, 1.0f));
corners[1] = unProject(vec4(maxX, minY, 1.0f, 1.0f));
corners[2] = unProject(vec4(maxX, maxY, 1.0f, 1.0f));
corners[3] = unProject(vec4(minX, maxY, 1.0f, 1.0f));
vec4 frustum[4];
frustum[0] = createPlaneEquation(corners[0], corners[1]); //Bottom
frustum[1] = createPlaneEquation(corners[2], corners[3]); //Up
frustum[2] = createPlaneEquation(corners[3], corners[1]); //Left
frustum[3] = createPlaneEquation(corners[1], corners[2]); //Right
for(uint i = 0; i < point_light_count; i++)
{
vec4 position = vec4(point_lights[i].position, 1.0f); //view space
float radius = point_lights[i].radius;
bool inside = true;
for(int f = 0; f < 4; f++)
{
if(dot(frustum[f].xyz, position.xyz) > radius)
{
inside = false;
break;
}
}
if(inside)
{
uint offset = atomicAdd(visibleLightCount, 1);
visibleLightIndices[offset] = int(i);
}
}
}
barrier();
if(gl_LocalInvocationIndex == 0)
{
uint offset = index * POINTLIGHT_CULL_MAX_NUMBER;
for(uint i = 0; i < visibleLightCount; i++)
{
point_lights_cull_indices[offset + i] = visibleLightIndices[i];
}
if(visibleLightCount != POINTLIGHT_CULL_MAX_NUMBER)
{
point_lights_cull_indices[offset + visibleLightCount] = -1;
}
}
} |
Partager