1
0
Fork 0
fgdata/Shaders/clustered-include.frag

244 lines
8.9 KiB
GLSL
Raw Normal View History

#version 120
uniform sampler3D fg_Clusters;
uniform sampler2D fg_ClusteredPointLights;
uniform sampler2D fg_ClusteredSpotLights;
uniform int fg_ClusteredTileSize;
uniform float fg_ClusteredSliceScale;
uniform float fg_ClusteredSliceBias;
uniform int fg_ClusteredHorizontalTiles;
uniform int fg_ClusteredVerticalTiles;
const int MAX_POINTLIGHTS = 1024;
const int MAX_SPOTLIGHTS = 1024;
const int MAX_LIGHT_GROUPS_PER_CLUSTER = 255;
struct PointLight {
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 attenuation;
};
struct SpotLight {
vec4 position;
vec4 direction;
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 attenuation;
float cos_cutoff;
float exponent;
};
PointLight unpackPointLight(int index)
{
PointLight light;
float v = (float(index) + 0.5) / float(MAX_POINTLIGHTS);
light.position = texture2D(fg_ClusteredPointLights, vec2(0.1, v));
light.ambient = texture2D(fg_ClusteredPointLights, vec2(0.3, v));
light.diffuse = texture2D(fg_ClusteredPointLights, vec2(0.5, v));
light.specular = texture2D(fg_ClusteredPointLights, vec2(0.7, v));
light.attenuation = texture2D(fg_ClusteredPointLights, vec2(0.9, v));
return light;
}
SpotLight unpackSpotLight(int index)
{
SpotLight light;
float v = (float(index) + 0.5) / float(MAX_SPOTLIGHTS);
light.position = texture2D(fg_ClusteredSpotLights, vec2(0.0714, v));
light.direction = texture2D(fg_ClusteredSpotLights, vec2(0.2143, v));
light.ambient = texture2D(fg_ClusteredSpotLights, vec2(0.3571, v));
light.diffuse = texture2D(fg_ClusteredSpotLights, vec2(0.5, v));
light.specular = texture2D(fg_ClusteredSpotLights, vec2(0.6429, v));
light.attenuation = texture2D(fg_ClusteredSpotLights, vec2(0.7857, v));
vec2 reminder = texture2D(fg_ClusteredSpotLights, vec2(0.9286, v)).xy;
light.cos_cutoff = reminder.x;
light.exponent = reminder.y;
return light;
}
// @param p Fragment position in view space.
// @param n Fragment normal in view space.
vec3 getClusteredLightsContribution(vec3 p, vec3 n, vec3 texel)
{
int zSlice = int(max(log2(-p.z) * fg_ClusteredSliceScale
+ fg_ClusteredSliceBias, 0.0));
int ySlice = int(gl_FragCoord.y) / fg_ClusteredTileSize * zSlice;
int xSlice = int(gl_FragCoord.x) / fg_ClusteredTileSize;
vec2 clusterCoords = vec2(
(float(xSlice) + 0.5) / fg_ClusteredHorizontalTiles,
(float(ySlice) * float(zSlice) + 0.5) / fg_ClusteredVerticalTiles);
int pointCount = int(texture3D(fg_Clusters, vec3(clusterCoords, 0.0)).r);
int spotCount = int(texture3D(fg_Clusters, vec3(clusterCoords, 0.0)).g);
int lightGroupCount = int(ceil(float(pointCount + spotCount) / 4.0));
vec3 color = vec3(0.0);
for (int i = 0; i < lightGroupCount; ++i) {
float r = (float(i + 1) + 0.5) / float(MAX_LIGHT_GROUPS_PER_CLUSTER + 1);
vec4 packedIndices = texture3D(fg_Clusters, vec3(clusterCoords, r));
for (int j = 0; j < 4; ++j) {
int index;
if (j == 0) index = int(packedIndices.x);
else if (j == 1) index = int(packedIndices.y);
else if (j == 2) index = int(packedIndices.z);
else if (j == 3) index = int(packedIndices.w);
else break;
int currentLight = i * 4 + j;
if (currentLight < pointCount) {
// This is a point light
PointLight light = unpackPointLight(index);
float range = light.attenuation.w;
vec3 toLight = light.position.xyz - p;
// Ignore fragments outside the light volume
if (dot(toLight, toLight) > (range * range))
continue;
float d = length(toLight);
float att = 1.0 / (light.attenuation.x // constant
+ light.attenuation.y * d // linear
+ light.attenuation.z * d * d); // quadratic
vec3 lightDir = normalize(toLight);
float NdotL = max(dot(n, lightDir), 0.0);
vec3 Iamb = light.ambient.rgb;
vec3 Idiff = gl_FrontMaterial.diffuse.rgb * light.diffuse.rgb * NdotL;
vec3 Ispec = vec3(0.0);
if (NdotL > 0.0) {
vec3 halfVector = normalize(lightDir + normalize(-p));
float NdotHV = max(dot(n, halfVector), 0.0);
Ispec = gl_FrontMaterial.specular.rgb
* light.specular.rgb
* pow(NdotHV, gl_FrontMaterial.shininess);
}
color += ((Iamb + Idiff) * texel + Ispec) * att;
} else if (currentLight < (pointCount + spotCount)) {
// This is a spot light
SpotLight light = unpackSpotLight(index);
vec3 toLight = light.position.xyz - p;
float d = length(toLight);
float att = 1.0 / (light.attenuation.x // constant
+ light.attenuation.y * d // linear
+ light.attenuation.z * d * d); // quadratic
vec3 lightDir = normalize(toLight);
float spotDot = dot(-lightDir, light.direction.xyz);
if (spotDot < light.cos_cutoff)
continue;
att *= pow(spotDot, light.exponent);
float NdotL = max(dot(n, lightDir), 0.0);
vec3 Iamb = light.ambient.rgb;
vec3 Idiff = gl_FrontMaterial.diffuse.rgb * light.diffuse.rgb * NdotL;
vec3 Ispec = vec3(0.0);
if (NdotL > 0.0) {
vec3 halfVector = normalize(lightDir + normalize(-p));
float NdotHV = max(dot(n, halfVector), 0.0);
Ispec = gl_FrontMaterial.specular.rgb
* light.specular.rgb
* pow(NdotHV, gl_FrontMaterial.shininess);
}
color += ((Iamb + Idiff) * texel + Ispec) * att;
} else {
break;
}
}
}
return clamp(color, 0.0, 1.0);
// for (int i = 0; i < pointCount; ++i) {
// vec3 lightCoords = clusterCoords;
// int pointCount = int(texture2D(fg_Clusters, clusterCoords).r);
// PointLight light = pointLights[lightListIndex];
// float range = light.attenuation.w;
// vec3 toLight = light.position.xyz - p;
// // Ignore fragments outside the light volume
// if (dot(toLight, toLight) > (range * range))
// continue;
// ////////////////////////////////////////////////////////////////////////
// // Actual lighting
// float d = length(toLight);
// float att = 1.0 / (light.attenuation.x // constant
// + light.attenuation.y * d // linear
// + light.attenuation.z * d * d); // quadratic
// vec3 lightDir = normalize(toLight);
// float NdotL = max(dot(n, lightDir), 0.0);
// vec3 Iamb = light.ambient.rgb;
// vec3 Idiff = light.diffuse.rgb * NdotL;
// vec3 Ispec = vec3(0.0);
// if (NdotL > 0.0) {
// vec3 halfVector = normalize(lightDir + normalize(-p));
// float NdotHV = max(dot(n, halfVector), 0.0);
// Ispec = light.specular.rgb * att * pow(NdotHV, shininess);
// }
// color += addColors(color, (Iamb + Idiff + Ispec) * att);
// }
// for (uint i = uint(0); i < spotCount; ++i) {
// uint lightListIndex = texelFetch(fg_ClusteredLightIndices,
// int(startIndex + i)).r;
// SpotLight light = spotLights[lightListIndex];
// vec3 toLight = light.position.xyz - p;
// ////////////////////////////////////////////////////////////////////////
// // Actual lighting
// float d = length(toLight);
// float att = 1.0 / (light.attenuation.x // constant
// + light.attenuation.y * d // linear
// + light.attenuation.z * d * d); // quadratic
// vec3 lightDir = normalize(toLight);
// float spotDot = dot(-lightDir, light.direction.xyz);
// if (spotDot < light.cos_cutoff)
// continue;
// att *= pow(spotDot, light.exponent);
// float NdotL = max(dot(n, lightDir), 0.0);
// vec3 Iamb = light.ambient.rgb;
// vec3 Idiff = light.diffuse.rgb * NdotL;
// vec3 Ispec = vec3(0.0);
// if (NdotL > 0.0) {
// vec3 halfVector = normalize(lightDir + normalize(-p));
// float NdotHV = max(dot(n, halfVector), 0.0);
// Ispec = light.specular.rgb * att * pow(NdotHV, shininess);
// }
// color += (Iamb + Idiff + Ispec) * att;
// }
}