#version 450
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include<light_structs.h>
layout(set = 0, binding = 0) uniform sampler2D reduced_depth_sampler;
layout(std430, set = 0, binding = 1) buffer PointLightData
{
PointLight point_lights[10];
}point_light_data;
layout(std430, set = 0, binding = 2) buffer SpotLightData
{
SpotLight spot_lights[10];
}spot_light_data;
layout(std430, set = 0, binding = 3) buffer AreaLightData
{
AreaLight area_lights[10];
}area_light_data;
layout(std430, set = 0, binding = 4) buffer ReflectionProbeData
{
ReflectionProbe probes[10];
}reflection_probe_data;
const int ntiles_x = 120, ntiles_y = 68;
layout(set = 0, binding = 5) buffer TileData
{
Tile tiles[ntiles_x][ntiles_y];
Item items[81600];
}tile_data;
layout(set = 0, binding = 6) uniform NLightsBlock{ivec4 n_lights;} n_lights_block;
layout(set = 0, binding = 7) buffer TilingInfo
{
uvec2 tile_size;
uint max_items;
uint max_items_tile;
} tiling_info;
layout(push_constant) uniform ProjectionData
{
mat4 mv;
mat4 p;
//vec3 view_pos;
} projection_data;
vec2 depth_minmax(ivec2 ctile)
{
return texelFetch(reduced_depth_sampler, ctile, 0).xy;
}
vec3 world_space_location(ivec2 ctile, float depth, ivec2 ntiles)
{
ivec2 resolution = ntiles*ivec2(tiling_info.tile_size);
vec2 uv = vec2(ctile)/vec2(ntiles);
//moves the location at the center og the tile
uv += 0.5/vec2(ntiles);
//converts from normalized range to -1.0..1.0
vec4 clip_space = vec4(1.0);
clip_space.xy = uv*2.0-1.0;
clip_space.z = depth;
mat4 p = projection_data.p;
p[0][3] = 0.0;
p[1][3] = 0.0;
p[2][3] = -1.0;
vec4 homogenous = inverse(p)*clip_space;
homogenous /= homogenous.w;
vec4 world_space = inverse(projection_data.mv) * homogenous;
return world_space.xyz;
}
float sphere_ray_intersection(vec3 ray_origin, vec3 ray_dir, vec4 sphere, out bool intersected)
{
vec3 op = sphere.xyz - ray_origin;
float t, eps = 1e-3;
float b = dot(op, ray_dir);
float det = b * b - dot(op, op) + sphere.w * sphere.w;
intersected = det >= 0.0;
if(det < 0.0)
{
return 0.0;
}
else
{
det = sqrt(det);
return (t = b - det) > eps ?
t :
((t = b + det) > eps ? t : 0.0);
}
}
bool has_influence(PointLight light, vec3 a, vec3 b)
{
vec3 ray_dir = normalize(b - a);
vec3 ray_origin = a;
bool intersected;
float dist = sphere_ray_intersection(
ray_origin,
ray_dir,
vec4(light.position.xyz, light.influence_radius),
intersected
);
return intersected && (dist > 0 || dist < length(b - a)) && dist != 0.0;
return length(a-light.position.xyz) < light.influence_radius;
}
bool has_influence(SpotLight light, vec3 a, vec3 b)
{
return true;
}
bool has_influence(AreaLight light, vec3 a, vec3 b)
{
return false;
}
bool has_influence(ReflectionProbe light, vec3 a, vec3 b)
{
return false;
}
uint global_id(ivec2 ntiles)
{
/*return gl_GlobalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +
gl_GlobalInvocationID.y * gl_WorkGroupSize.x +
gl_GlobalInvocationID.x;*/
return gl_GlobalInvocationID.y*ntiles.x+gl_GlobalInvocationID.x;
}
void main(){
ivec2 ntiles = textureSize(reduced_depth_sampler, 0);
if(gl_GlobalInvocationID.x > ntiles.x || gl_GlobalInvocationID.y > ntiles.y) return;
//current til
ivec2 ctile = ivec2(gl_GlobalInvocationID.xy);
vec2 depth_minmax = depth_minmax(ctile);
vec3 world_space_location_a = world_space_location(ctile, depth_minmax.x, ntiles),
world_space_location_b = world_space_location(ctile, depth_minmax.y, ntiles);
//tiles have fixed length in buffer
tile_data.tiles[ctile.x][ctile.y].offset = int(global_id(ntiles)*tiling_info.max_items_tile);
//------------------------------iterate over point lights--------------------------------
int current_light = 0, start = int(global_id(ntiles)*tiling_info.max_items_tile);
for(int i = 0;i < n_lights_block.n_lights.x && current_light < tiling_info.max_items_tile;i++)
{
PointLight light = point_light_data.point_lights[i];
if(has_influence(light, world_space_location_a, world_space_location_b))
tile_data.items[start+current_light++].point_spot_offset = i << 16;
}
//writes count for this type of light
tile_data.tiles[ctile.x][ctile.y].point_spot_area_probe_count = current_light;
//------------------------------iterate over spot lights--------------------------------
current_light = 0;
for(int i = 0;i < n_lights_block.n_lights.y && current_light < tiling_info.max_items_tile;i++)
{
SpotLight light = spot_light_data.spot_lights[i];
if(has_influence(light, world_space_location_a, world_space_location_b))
tile_data.items[start+current_light++].point_spot_offset |= i & 0x0000ffff;
}
//writes count for this type of light
tile_data.tiles[ctile.x][ctile.y].point_spot_area_probe_count |= current_light << 8;
//------------------------------iterate over area lights--------------------------------
current_light = 0;
for(int i = 0;i < n_lights_block.n_lights.z && current_light < tiling_info.max_items_tile;i++)
{
AreaLight light = area_light_data.area_lights[i];
if(has_influence(light, world_space_location_a, world_space_location_b))
tile_data.items[start+current_light++].area_probe_offset = i << 16;
}
//writes count for this type of light
tile_data.tiles[ctile.x][ctile.y].point_spot_area_probe_count |= current_light << 16;
//------------------------------iterate over reflection probes--------------------------------
current_light = 0;
for(int i = 0;i < n_lights_block.n_lights.w && current_light < tiling_info.max_items_tile;i++)
{
ReflectionProbe light = reflection_probe_data.probes[i];
if(has_influence(light, world_space_location_a, world_space_location_b))
tile_data.items[start+current_light++].point_spot_offset |= i & 0x0000ffff;
}
//writes count for this type of light
tile_data.tiles[ctile.x][ctile.y].point_spot_area_probe_count |= current_light << 24;
}