180 lines
5.4 KiB
GLSL
180 lines
5.4 KiB
GLSL
#version 450
|
|
#extension GL_EXT_nonuniform_qualifier : require
|
|
|
|
struct DirectionalLightStruct
|
|
{
|
|
vec4 directionWorld;
|
|
vec3 direction;
|
|
uint isActive;
|
|
uint cullingMask;
|
|
vec4 diffuseColor;
|
|
mat4 pvMatrix;
|
|
uint shadowData;
|
|
};
|
|
|
|
struct AmbientLightStruct
|
|
{
|
|
vec4 ambientColor;
|
|
float strength;
|
|
uint isActive;
|
|
uint cullingMask;
|
|
};
|
|
|
|
layout(local_size_x = 16, local_size_y = 16) in;
|
|
layout(set = 3, binding = 0, rgba32f) uniform image2D positions;
|
|
layout(set = 3, binding = 1, rgba32f) uniform image2D normals;
|
|
layout(set = 3, binding = 2, rgba8) uniform image2D albedo;
|
|
layout(set = 3, binding = 3, rgba32ui) uniform uimage2D lightLayerData;
|
|
layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage;
|
|
layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace;
|
|
layout(set = 3, binding = 6, rgba8) uniform image2D targetImage;
|
|
layout(set = 3, binding = 7, rgba8) uniform image2D objectVFXImage;
|
|
|
|
layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global)
|
|
|
|
layout(set = 1, binding = 0) uniform LightCounts
|
|
{
|
|
uint directionalLights;
|
|
uint pointLights;
|
|
uint spotLights;
|
|
uint ambientLights;
|
|
|
|
} lightCounts;
|
|
|
|
layout(std430, set = 1, binding = 1) buffer DirectionalLightData
|
|
{
|
|
DirectionalLightStruct dLightData[];
|
|
} DirLightData;
|
|
|
|
layout(std430, set = 1, binding = 4) buffer AmbientLightData
|
|
{
|
|
AmbientLightStruct aLightData[];
|
|
} AmbLightData;
|
|
|
|
float LinStep (float val, float low, float high)
|
|
{
|
|
return clamp ((val - low)/(high - low), 0.0f, 1.0f);
|
|
}
|
|
|
|
float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV, vec3 worldNormal, vec3 lightDir)
|
|
{
|
|
// clip space for fragment from light view space
|
|
vec4 fragPosLightPOV = lightPV * worldSpaceFragPos;
|
|
|
|
// Perform perspective division and convert to 0 to 1 range
|
|
vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f);
|
|
|
|
vec2 moments = texture(shadowMap, converted.xy).xy;
|
|
|
|
if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f)
|
|
return 1.0f;
|
|
|
|
float returnVal = 0.0f;
|
|
|
|
float worldNormalDotLight = dot (normalize (worldNormal), normalize(lightDir));
|
|
|
|
if (worldNormalDotLight <= 0.0f)
|
|
return 0.7f;
|
|
|
|
// if (worldNormalDotLight <= 0.01f)
|
|
// return 0.7f;
|
|
|
|
if (fragPosLightPOV.z > moments.x && fragPosLightPOV.w > 0.0f)
|
|
{
|
|
float p = step (fragPosLightPOV.z, moments.x);
|
|
float variance = max (moments.y - (moments.x * moments.x), 0.00002f);
|
|
|
|
float d = fragPosLightPOV.z - moments.x;
|
|
float pMax = LinStep (variance / (variance + (d * d)), 0.9f, 1.0f);
|
|
|
|
returnVal = min (max (p, pMax) + 0.7f, 1.0f);
|
|
|
|
return returnVal;
|
|
|
|
}
|
|
else if (fragPosLightPOV.z > 1.0f)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
// return min (worldNormalDotLight + 0.7f, 1.0f);
|
|
return 1.0f;
|
|
|
|
}
|
|
|
|
void main()
|
|
{
|
|
// convenient variables
|
|
ivec2 globalThread = ivec2(gl_GlobalInvocationID);
|
|
|
|
// Get the diffuse color of the pixel
|
|
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
|
|
|
|
// Get position of fragment in world space
|
|
vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f);
|
|
|
|
// Get position of fragment in view spacee
|
|
vec3 positionView = imageLoad (positions, globalThread).rgb;
|
|
|
|
// normal of fragment
|
|
vec3 normalView = imageLoad(normals, globalThread).rgb;
|
|
|
|
uvec4 lightLayerAndNormal = imageLoad (lightLayerData, globalThread);
|
|
|
|
// light layer index
|
|
uint lightLayer = lightLayerAndNormal.x;
|
|
|
|
// Normals are stored in 2 32-bit uints (only first 48 bits are used) where they can be unpacked in 3 floats so we unpack them here.
|
|
vec3 worldNormal = vec3 (unpackHalf2x16 (lightLayerAndNormal.y).xy, unpackHalf2x16 (lightLayerAndNormal.z).x);
|
|
|
|
vec3 fragColor = vec3 (0.0f);
|
|
|
|
vec4 shadowMapColor = vec4 (1.0f);
|
|
|
|
// Shadow multiplier
|
|
float shadowValue = 1.0f;
|
|
|
|
for (int i = 0; i < lightCounts.ambientLights; ++i)
|
|
{
|
|
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
|
|
{
|
|
// Just do some add
|
|
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < lightCounts.directionalLights; ++i)
|
|
{
|
|
if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
|
|
{
|
|
// get normalized direction of light
|
|
vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction);
|
|
|
|
// Get diffuse strength
|
|
float diffuseStrength = max (0, dot (-dLightNormalized, normalView));
|
|
|
|
// Calculate the fragment color
|
|
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
|
|
|
|
// If the shadow map is enabled (test the bit)
|
|
if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1)
|
|
{
|
|
uint shadowMapIndex = (DirLightData.dLightData[i].shadowData >> 8);
|
|
shadowValue = min (shadowValue, CalcShadowValue (shadowMaps[nonuniformEXT(shadowMapIndex)], positionWorld, DirLightData.dLightData[i].pvMatrix, worldNormal, DirLightData.dLightData[i].directionWorld.xyz));
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate shadow map here
|
|
if (shadowValue != 0.0f)
|
|
fragColor.rgb *= shadowValue;
|
|
|
|
float ssaoVal = imageLoad (ssaoBlurredImage, globalThread).r;
|
|
fragColor *= ssaoVal;
|
|
|
|
vec4 objectVFXColor = imageLoad (objectVFXImage, globalThread);
|
|
fragColor += objectVFXColor.rgb * objectVFXColor.a;
|
|
|
|
// store result into result image
|
|
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f));
|
|
} |