| /* |
| The MIT License (MIT) |
| |
| Copyright (c) 2022 Sascha Willems |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in all |
| copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| SOFTWARE. |
| */ |
| |
| #version 450 |
| |
| layout (binding = 1) uniform sampler2D samplerposition; |
| layout (binding = 2) uniform sampler2D samplerNormal; |
| layout (binding = 3) uniform sampler2D samplerAlbedo; |
| layout (binding = 5) uniform sampler2DArray samplerShadowMap; |
| |
| layout (location = 0) in vec2 inUV; |
| |
| layout (location = 0) out vec4 outFragColor; |
| |
| #define LIGHT_COUNT 3 |
| #define SHADOW_FACTOR 0.25 |
| #define AMBIENT_LIGHT 0.1 |
| #define USE_PCF |
| |
| struct Light |
| { |
| vec4 position; |
| vec4 target; |
| vec4 color; |
| mat4 viewMatrix; |
| }; |
| |
| layout (binding = 4) uniform UBO |
| { |
| vec4 viewPos; |
| Light lights[LIGHT_COUNT]; |
| int useShadows; |
| int debugDisplayTarget; |
| } ubo; |
| |
| float textureProj(vec4 P, float layer, vec2 offset) |
| { |
| float shadow = 1.0; |
| vec4 shadowCoord = P / P.w; |
| shadowCoord.st = shadowCoord.st * 0.5 + 0.5; |
| |
| if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0) |
| { |
| float dist = texture(samplerShadowMap, vec3(shadowCoord.st + offset, layer)).r; |
| if (shadowCoord.w > 0.0 && dist < shadowCoord.z) |
| { |
| shadow = SHADOW_FACTOR; |
| } |
| } |
| return shadow; |
| } |
| |
| float filterPCF(vec4 sc, float layer) |
| { |
| ivec2 texDim = textureSize(samplerShadowMap, 0).xy; |
| float scale = 1.5; |
| float dx = scale * 1.0 / float(texDim.x); |
| float dy = scale * 1.0 / float(texDim.y); |
| |
| float shadowFactor = 0.0; |
| int count = 0; |
| int range = 1; |
| |
| for (int x = -range; x <= range; x++) |
| { |
| for (int y = -range; y <= range; y++) |
| { |
| shadowFactor += textureProj(sc, layer, vec2(dx*x, dy*y)); |
| count++; |
| } |
| |
| } |
| return shadowFactor / count; |
| } |
| |
| vec3 shadow(vec3 fragcolor, vec3 fragpos) { |
| for(int i = 0; i < LIGHT_COUNT; ++i) |
| { |
| vec4 shadowClip = ubo.lights[i].viewMatrix * vec4(fragpos, 1.0); |
| |
| float shadowFactor; |
| #ifdef USE_PCF |
| shadowFactor= filterPCF(shadowClip, i); |
| #else |
| shadowFactor = textureProj(shadowClip, i, vec2(0.0)); |
| #endif |
| |
| fragcolor *= shadowFactor; |
| } |
| return fragcolor; |
| } |
| |
| void main() |
| { |
| // Get G-Buffer values |
| vec3 fragPos = texture(samplerposition, inUV).rgb; |
| vec3 normal = texture(samplerNormal, inUV).rgb; |
| vec4 albedo = texture(samplerAlbedo, inUV); |
| |
| // Debug display |
| if (ubo.debugDisplayTarget > 0) { |
| switch (ubo.debugDisplayTarget) { |
| case 1: |
| outFragColor.rgb = shadow(vec3(1.0), fragPos).rgb; |
| break; |
| case 2: |
| outFragColor.rgb = fragPos; |
| break; |
| case 3: |
| outFragColor.rgb = normal; |
| break; |
| case 4: |
| outFragColor.rgb = albedo.rgb; |
| break; |
| case 5: |
| outFragColor.rgb = albedo.aaa; |
| break; |
| } |
| outFragColor.a = 1.0; |
| return; |
| } |
| |
| // Ambient part |
| vec3 fragcolor = albedo.rgb * AMBIENT_LIGHT; |
| |
| vec3 N = normalize(normal); |
| |
| for(int i = 0; i < LIGHT_COUNT; ++i) |
| { |
| // Vector to light |
| vec3 L = ubo.lights[i].position.xyz - fragPos; |
| // Distance from light to fragment position |
| float dist = length(L); |
| L = normalize(L); |
| |
| // Viewer to fragment |
| vec3 V = ubo.viewPos.xyz - fragPos; |
| V = normalize(V); |
| |
| float lightCosInnerAngle = cos(radians(15.0)); |
| float lightCosOuterAngle = cos(radians(25.0)); |
| float lightRange = 100.0; |
| |
| // Direction vector from source to target |
| vec3 dir = normalize(ubo.lights[i].position.xyz - ubo.lights[i].target.xyz); |
| |
| // Dual cone spot light with smooth transition between inner and outer angle |
| float cosDir = dot(L, dir); |
| float spotEffect = smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); |
| float heightAttenuation = smoothstep(lightRange, 0.0f, dist); |
| |
| // Diffuse lighting |
| float NdotL = max(0.0, dot(N, L)); |
| vec3 diff = vec3(NdotL); |
| |
| // Specular lighting |
| vec3 R = reflect(-L, N); |
| float NdotR = max(0.0, dot(R, V)); |
| vec3 spec = vec3(pow(NdotR, 16.0) * albedo.a * 2.5); |
| |
| fragcolor += vec3((diff + spec) * spotEffect * heightAttenuation) * ubo.lights[i].color.rgb * albedo.rgb; |
| } |
| |
| // Shadow calculations in a separate pass |
| if (ubo.useShadows > 0) |
| { |
| fragcolor = shadow(fragcolor, fragPos); |
| } |
| |
| outFragColor = vec4(fragcolor, 1.0); |
| } |