163 lines
4.9 KiB
Text
163 lines
4.9 KiB
Text
|
#version 330 core
|
||
|
|
||
|
uniform sampler3D fg_Clusters;
|
||
|
uniform sampler2D fg_ClusteredIndices;
|
||
|
uniform sampler2D fg_ClusteredPointLights;
|
||
|
uniform sampler2D fg_ClusteredSpotLights;
|
||
|
|
||
|
uniform int fg_ClusteredMaxPointLights;
|
||
|
uniform int fg_ClusteredMaxSpotLights;
|
||
|
uniform int fg_ClusteredMaxLightIndices;
|
||
|
uniform int fg_ClusteredTileSize;
|
||
|
uniform int fg_ClusteredDepthSlices;
|
||
|
uniform float fg_ClusteredSliceScale;
|
||
|
uniform float fg_ClusteredSliceBias;
|
||
|
uniform int fg_ClusteredHorizontalTiles;
|
||
|
uniform int fg_ClusteredVerticalTiles;
|
||
|
|
||
|
// surface.glsl
|
||
|
vec3 surface_eval_analytical(
|
||
|
vec3 base_color, float metallic, float roughness, vec3 f0,
|
||
|
vec3 light_intensity, float occlusion,
|
||
|
vec3 N, vec3 L, vec3 V);
|
||
|
|
||
|
struct PointLight {
|
||
|
vec3 position;
|
||
|
vec3 color;
|
||
|
float intensity;
|
||
|
float range;
|
||
|
};
|
||
|
|
||
|
struct SpotLight {
|
||
|
vec3 position;
|
||
|
vec3 direction;
|
||
|
vec3 color;
|
||
|
float intensity;
|
||
|
float range;
|
||
|
float cos_cutoff;
|
||
|
float exponent;
|
||
|
};
|
||
|
|
||
|
PointLight unpackPointLight(int index)
|
||
|
{
|
||
|
float v = (float(index) + 0.5) / float(fg_ClusteredMaxPointLights);
|
||
|
PointLight light;
|
||
|
vec4 block;
|
||
|
block = texture(fg_ClusteredPointLights, vec2(0.25, v));
|
||
|
light.position = block.xyz;
|
||
|
light.range = block.w;
|
||
|
block = texture(fg_ClusteredPointLights, vec2(0.75, v));
|
||
|
light.color = block.xyz;
|
||
|
light.intensity = block.w;
|
||
|
return light;
|
||
|
}
|
||
|
|
||
|
SpotLight unpackSpotLight(int index)
|
||
|
{
|
||
|
float v = (float(index) + 0.5) / float(fg_ClusteredMaxSpotLights);
|
||
|
SpotLight light;
|
||
|
vec4 block;
|
||
|
block = texture(fg_ClusteredSpotLights, vec2(0.125, v));
|
||
|
light.position = block.xyz;
|
||
|
light.range = block.w;
|
||
|
block = texture(fg_ClusteredSpotLights, vec2(0.375, v));
|
||
|
light.direction = block.xyz;
|
||
|
light.cos_cutoff = block.w;
|
||
|
block = texture(fg_ClusteredSpotLights, vec2(0.625, v));
|
||
|
light.color = block.xyz;
|
||
|
light.intensity = block.w;
|
||
|
block = texture(fg_ClusteredSpotLights, vec2(0.875, v));
|
||
|
light.exponent = block.x;
|
||
|
return light;
|
||
|
}
|
||
|
|
||
|
int getIndex(int counter)
|
||
|
{
|
||
|
vec2 coords = vec2(mod(float(counter), float(fg_ClusteredMaxLightIndices)) + 0.5,
|
||
|
float(counter / fg_ClusteredMaxLightIndices) + 0.5);
|
||
|
// Normalize
|
||
|
coords /= vec2(fg_ClusteredMaxLightIndices);
|
||
|
return int(texture(fg_ClusteredIndices, coords).r);
|
||
|
}
|
||
|
|
||
|
float get_square_falloff_attenuation(vec3 to_light, float inv_range)
|
||
|
{
|
||
|
float dd = dot(to_light, to_light);
|
||
|
float factor = dd * inv_range * inv_range;
|
||
|
float smooth_factor = max(1.0 - factor * factor, 0.0);
|
||
|
return (smooth_factor * smooth_factor) / max(dd, 0.0001);
|
||
|
}
|
||
|
|
||
|
float get_spot_angle_attenuation(vec3 l, vec3 light_dir,
|
||
|
float cos_cutoff, float exponent)
|
||
|
{
|
||
|
float cd = dot(-l, light_dir);
|
||
|
if (cd < cos_cutoff)
|
||
|
return 0.0;
|
||
|
return pow(cd, exponent);
|
||
|
}
|
||
|
|
||
|
vec3 eval_scene_lights(vec3 base_color, float metallic, float roughness, vec3 f0,
|
||
|
vec3 P, vec3 N, vec3 V)
|
||
|
{
|
||
|
int slice = int(max(log2(-P.z) * fg_ClusteredSliceScale
|
||
|
+ fg_ClusteredSliceBias, 0.0));
|
||
|
vec3 cluster_coords = vec3(floor(gl_FragCoord.xy / fg_ClusteredTileSize),
|
||
|
slice) + vec3(0.5); // Pixel center
|
||
|
// Normalize
|
||
|
cluster_coords /= vec3(fg_ClusteredHorizontalTiles,
|
||
|
fg_ClusteredVerticalTiles,
|
||
|
fg_ClusteredDepthSlices);
|
||
|
|
||
|
vec3 cluster = texture(fg_Clusters, cluster_coords).rgb;
|
||
|
int light_index = int(cluster.r);
|
||
|
int point_count = int(cluster.g);
|
||
|
int spot_count = int(cluster.b);
|
||
|
|
||
|
vec3 color = vec3(0.0);
|
||
|
|
||
|
for (int i = 0; i < point_count; ++i) {
|
||
|
int index = getIndex(light_index++);
|
||
|
PointLight light = unpackPointLight(index);
|
||
|
|
||
|
vec3 to_light = light.position - P;
|
||
|
vec3 L = normalize(to_light);
|
||
|
|
||
|
float attenuation = get_square_falloff_attenuation(
|
||
|
to_light, 1.0 / light.range);
|
||
|
if (attenuation <= 0.0)
|
||
|
continue;
|
||
|
|
||
|
vec3 intensity = light.color * light.intensity * attenuation;
|
||
|
|
||
|
color += surface_eval_analytical(
|
||
|
base_color, metallic, roughness, f0,
|
||
|
intensity, 1.0,
|
||
|
N, L, V);
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < spot_count; ++i) {
|
||
|
int index = getIndex(light_index++);
|
||
|
SpotLight light = unpackSpotLight(index);
|
||
|
|
||
|
vec3 to_light = light.position - P;
|
||
|
vec3 L = normalize(to_light);
|
||
|
|
||
|
float attenuation = get_square_falloff_attenuation(
|
||
|
to_light, 1.0 / light.range);
|
||
|
attenuation *= get_spot_angle_attenuation(
|
||
|
L, light.direction, light.cos_cutoff, light.exponent);
|
||
|
if (attenuation <= 0.0)
|
||
|
continue;
|
||
|
|
||
|
vec3 intensity = light.color * light.intensity * attenuation;
|
||
|
|
||
|
color += surface_eval_analytical(
|
||
|
base_color, metallic, roughness, f0,
|
||
|
intensity, 1.0,
|
||
|
N, L, V);
|
||
|
}
|
||
|
|
||
|
return color;
|
||
|
}
|