#version 450 layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; #include #include layout(set = 0, binding = 0) uniform sampler2D in_depth; layout(set = 0, binding = 1) uniform sampler2D in_norm_rough; layout(set = 0, binding = 2) writeonly uniform image2D out_diffuse; layout(set = 0, binding = 3) writeonly uniform image2D out_specular; layout(std430, set = 0, binding = 4) buffer DirectionalLightData { int n; DirectionalLight directional_lights[10]; }directional_light_data; layout(std430, set = 0, binding = 5) buffer PointLightData { PointLight point_lights[10]; }point_light_data; layout(std430, set = 0, binding = 6) buffer SpotLightData { SpotLight spot_lights[10]; }spot_light_data; layout(std430, set = 0, binding = 7) buffer AreaLightData { AreaLight area_lights[10]; }area_light_data; layout(std430, set = 0, binding = 8) buffer ReflectionProbeData { ReflectionProbe probes[10]; }reflection_probe_data; /*layout(constant_id = 0) const int tiles_count_x = 64; layout(constant_id = 1) const int tiles_count_y = 64;*/ const int ntiles_x = 120, ntiles_y = 68; layout(set = 0, binding = 9) buffer TileData { Tile tiles[ntiles_x][ntiles_y]; Item items[81600]; }tile_data; layout(set = 0, binding = 10) buffer Res { uvec2 res; }res; layout(set = 0, binding = 11) uniform sampler2DShadow shadow_atlas; layout(set = 0, binding = 12) uniform sampler2D shadow_atlas_raw; layout(set = 0, binding = 13) buffer ShadowData { mat4 shadow_transforms[16]; vec4 shadow_maps[16]; } shadow_data; layout(push_constant) uniform ProjectionData { mat4 mv; mat4 p; //vec3 view_pos; } projection_data; #include #include void pbr_light(out vec3 specular, out vec3 diffuse, vec3 point_to_light, vec3 color, float attenuation, vec3 norm, vec3 point, float roughness) { //diffuse = vec3(sin(3.1415*point.yyy));return; vec3 vdir = normalize(get_view_pos() - point); vec3 halfway = normalize(point_to_light + vdir); float cos_theta = max(dot(norm, point_to_light), 0.0); vec3 radiance = color.xyz * attenuation; float F0 = 0.04; float fresnel = fresnel_schlick(max(dot(halfway, vdir), 0.0), F0); float ndf = normal_distribution_ggx(norm, halfway, roughness); float g = geometry_smith(norm, vdir, point_to_light, k_direct(roughness)); //cook-torrance float specular_factor = ndf * g * fresnel / max(4.0 * max(dot(norm, vdir) * dot(norm, point_to_light), 0.0), 0.001); float ks = fresnel, kd = 1.0-ks; diffuse = (kd / PI) * radiance * cos_theta; specular = specular_factor * radiance * cos_theta; } /*****************************************light processing functions***************************************************/ #define CUTOFF_MARGIN 5 float cutoff_function(float dist, float influence_radius) { return square(clamp((CUTOFF_MARGIN-CUTOFF_MARGIN*dist/influence_radius), 0.0, 1.0)); } void process_directional(out vec3 specular, out vec3 diffuse, DirectionalLight light, vec3 norm, vec3 point, float roughness) { vec3 point_to_light = normalize(-light.direction.xyz); vec3 vdir = normalize(get_view_pos() - point); vec3 halfway = normalize(vdir+norm); point_to_light = normalize(point_to_light); pbr_light(specular, diffuse, point_to_light, light.color.xyz, 1.0, norm, point, roughness); } void process_point(out vec3 specular, out vec3 diffuse, PointLight light, vec3 norm, vec3 point, float roughness) { vec3 point_to_light = light.position.xyz-point; float dist = length(point_to_light); vec3 vdir = normalize(get_view_pos() - point); vec3 halfway = normalize(vdir+norm); point_to_light = normalize(point_to_light); float attenuation = cutoff_function(dist, light.influence_radius) / square(dist); pbr_light(specular, diffuse, point_to_light, light.color.xyz, attenuation, norm, point, roughness); } void process_spot(out vec3 specular, out vec3 diffuse, SpotLight light, vec3 norm, vec3 point, float roughness) { vec3 point_to_light = light.position.xyz-point; float dist = length(point_to_light); float attenuation = light.size*light.size/square(tan(light.cone_angle)*dist); vec3 vdir = normalize(get_view_pos() - point); vec3 halfway = normalize(vdir+norm); point_to_light = normalize(point_to_light); attenuation *= clamp((dot(-light.direction, normalize(point_to_light))-cos(light.cone_angle))/cos(light.cone_angle*0.1), 0.0, 1.0); pbr_light(specular, diffuse, point_to_light, light.color.xyz, attenuation, norm, point, roughness); } void process_area(out vec3 specular, out vec3 diffuse, AreaLight light, vec3 norm, vec3 point, float roughness) { specular = vec3(1.0); diffuse = vec3(1.0); } void process_probe(out vec3 specular, out vec3 diffuse, ReflectionProbe light, vec3 norm, vec3 point, float roughness) { specular = vec3(1.0); diffuse = vec3(1.0); } /*****************************************light processing functions***************************************************/ /**********************************************shadow mapping**********************************************************/ #define CASCADE_MARGIN 0.01 #define PCF_SAMPLES 32 vec3 get_shadow_coords(vec4 wp_coord, mat4 mat, vec4 shadow_map, vec3 norm, vec3 ldir) { //vec3 bias = ldir * max(0.005 * (1 - dot(norm, ldir)), shadow_map.w); //vec4 r = mat * (wp_coord + vec4(bias, 0.0)); vec4 r = mat * wp_coord; r.xyz /= r.w; r.xy = (r.xy+1)/2.0; r.z -= max(0.005 * (1 - dot(norm, ldir)), shadow_map.w); r.xy *= shadow_map.z; r.xy += shadow_map.xy; return clamp(r.xyz, vec3(0.0), vec3(1.0)); } vec3 get_shadow_uv(vec4 wp_coord, uint shadow_index) { mat4 mat = shadow_data.shadow_transforms[shadow_index]; vec4 shadow_map = shadow_data.shadow_maps[shadow_index]; vec4 r = mat * wp_coord; r.xyz /= r.w; r.xy = (r.xy + 1) / 2.0; r.z -= shadow_map.w; return r.xyz; } vec2 get_atlas_coord(vec2 uv, uint shadow_index) { vec4 shadow_map = shadow_data.shadow_maps[shadow_index]; uv *= shadow_map.z; uv += shadow_map.xy; return uv; } bool check_shadow_range(vec4 wp_coord, mat4 mat) { vec4 r = mat * wp_coord; r.xyz /= r.w; return r.x < (1.0-CASCADE_MARGIN) && r.x > -(1.0-CASCADE_MARGIN) && r.y < (1.0-CASCADE_MARGIN) && r.y > -(1.0-CASCADE_MARGIN) && r.z < (1.0-CASCADE_MARGIN) && r.z > -(1.0-CASCADE_MARGIN); } uint find_shadow_cascade(vec3 point, uint shadow_index, uint n_cascade) { for (int cascade = 1; cascade <= n_cascade && !check_shadow_range(vec4(point, 1.0), shadow_data.shadow_transforms[shadow_index]); cascade++, shadow_index++ ); return shadow_index; } void find_blocker(vec3 uv, float light_angle, out float avg_depth, out uint n_blockers, uint shadow_index) { float search_width = light_angle * 0.2; float blocker_sum = 0.0; n_blockers = 0; for(int i = 0; i < 16; i++) { vec2 coords = uv.xy + poisson_disk_border[i] * search_width; vec2 atlas_coords = get_atlas_coord(coords, shadow_index); float shadow_map_depth = texture(shadow_atlas_raw, atlas_coords).r; if(shadow_map_depth < uv.z) { blocker_sum += shadow_map_depth; n_blockers++; } } avg_depth = blocker_sum / n_blockers; } float pcf(vec3 uv, float radius, uint shadow_index) { float shadow_fact = 0.0; for(int i = 0;i < PCF_SAMPLES; i++) { vec3 atlas_coords = vec3(get_atlas_coord(uv.xy + radius * poisson_disk[i], shadow_index), uv.z); shadow_fact += texture(shadow_atlas, atlas_coords); } return shadow_fact / PCF_SAMPLES; } float directional_shadows(vec3 point, uint light_index) { float light_angle = directional_light_data.directional_lights[light_index].angle; uint shadow_index = directional_light_data.directional_lights[light_index].shadows; if(shadow_index == 0xffffffff) { return 1.0; } uint n_cascades = directional_light_data.directional_lights[light_index].n_cascades; shadow_index = find_shadow_cascade(point, shadow_index, n_cascades); vec3 uv = get_shadow_uv(vec4(point, 1.0), shadow_index); float avg_depth = 0; uint n_blockers = 0; find_blocker(uv, light_angle, avg_depth, n_blockers, shadow_index); if(n_blockers < 1) return 1.0; float radius = (uv.z - avg_depth) * light_angle; return pcf(uv, radius, shadow_index); } /**********************************************shadow mapping**********************************************************/ void main() { if(gl_GlobalInvocationID.x > res.res.x || gl_GlobalInvocationID.y > res.res.y) return; vec2 uv = vec2(gl_GlobalInvocationID.xy) / vec2(res.res); ivec2 ntiles = ivec2(ceil(res.res.x/16), ceil(res.res.y/16)); Tile tile = tile_data.tiles[int(uv.x*ntiles.x)][int(uv.y*ntiles.y)]; int point_count, spot_count, area_count, probe_count; point_count = tile.point_spot_area_probe_count & 0xff; spot_count = tile.point_spot_area_probe_count >> 8 & 0xff; area_count = tile.point_spot_area_probe_count >> 16 & 0xff; probe_count = tile.point_spot_area_probe_count >> 24 & 0xff; vec3 norm = texelFetch(in_norm_rough, ivec2(gl_GlobalInvocationID.xy), 0).xyz*2.0-1.0; float roughness = texture(in_norm_rough, uv).w/4.0; float depth = texelFetch(in_depth, ivec2(gl_GlobalInvocationID.xy), 0).x; vec3 point = world_space_location(uv, depth); if(depth >= 1.0) return; /****************light processing****************/ vec3 specular = vec3(0.0), diffuse = vec3(0.0); //processes directional lights for(int i = 0; i < directional_light_data.n; i++) { float shadow_fact = directional_shadows(point, i); vec3 tspec, tdiff; process_directional(tspec, tdiff, directional_light_data.directional_lights[i], norm, point, roughness); specular += tspec * shadow_fact; diffuse += tdiff * shadow_fact; } //processes point lights for(int i = 0;i < point_count;i++) { int idx = tile_data.items[i+tile.offset].point_spot_offset >> 16 & 0xffff; vec3 tspec, tdiff; process_point(tspec, tdiff, point_light_data.point_lights[idx], norm, point, roughness); specular += tspec; diffuse += tdiff; } //processes spot lights for(int i = 0;i < spot_count;i++) { int idx = tile_data.items[i+tile.offset].point_spot_offset & 0xffff; float shadow_fact = 0.0; uint shadows_index = spot_light_data.spot_lights[idx].shadows; if(shadows_index != 0xffffffff) { for(int i = 0;i < 32; i++) { shadow_fact += texture(shadow_atlas, get_shadow_coords(vec4(point, 1.0), shadow_data.shadow_transforms[shadows_index], shadow_data.shadow_maps[shadows_index] , norm, normalize(spot_light_data.spot_lights[idx].position-point)) + vec3(poisson_disk[i]/3000.0, 0.0) ); } shadow_fact /= 32; } else { shadow_fact = 1.0; } vec3 tspec, tdiff; process_spot(tspec, tdiff, spot_light_data.spot_lights[idx], norm, point, roughness); specular += tspec * shadow_fact; diffuse += tdiff * shadow_fact; } //processes area lights for(int i = 0;i < area_count;i++) { int idx = i+tile.offset; vec3 tspec, tdiff; process_area(tspec, tdiff, area_light_data.area_lights[idx], norm, point, roughness); specular += tspec; diffuse += tdiff; } //processes probes for(int i = 0;i < probe_count;i++) { int idx = i+tile.offset; vec3 tspec, tdiff; //process_probe(tspec, tdiff, reflection_probe_data.probes[idx], norm, point, roughness); specular += tspec; diffuse += tdiff; } imageStore(out_diffuse, ivec2(gl_GlobalInvocationID.xy), diffuse.xyzz); imageStore(out_specular, ivec2(gl_GlobalInvocationID.xy), specular.xyzz); }