1/* 2The MIT License (MIT) 3 4Copyright (c) 2022 Sascha Willems 5 6Permission is hereby granted, free of charge, to any person obtaining a copy 7of this software and associated documentation files (the "Software"), to deal 8in the Software without restriction, including without limitation the rights 9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10copies of the Software, and to permit persons to whom the Software is 11furnished to do so, subject to the following conditions: 12 13The above copyright notice and this permission notice shall be included in all 14copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22SOFTWARE. 23*/ 24 25#version 450 26 27layout (binding = 1) uniform sampler2D samplerposition; 28layout (binding = 2) uniform sampler2D samplerNormal; 29layout (binding = 3) uniform sampler2D samplerAlbedo; 30layout (binding = 5) uniform sampler2DArray samplerShadowMap; 31 32layout (location = 0) in vec2 inUV; 33 34layout (location = 0) out vec4 outFragColor; 35 36#define LIGHT_COUNT 3 37#define SHADOW_FACTOR 0.25 38#define AMBIENT_LIGHT 0.1 39#define USE_PCF 40 41int global_var = 0; 42 43struct Light 44{ 45 vec4 position; 46 vec4 target; 47 vec4 color; 48 mat4 viewMatrix; 49}; 50 51layout (binding = 4) uniform UBO 52{ 53 vec4 viewPos; 54 Light lights[LIGHT_COUNT]; 55 int useShadows; 56 int debugDisplayTarget; 57} ubo; 58 59float textureProj(vec4 P, float layer, vec2 offset) 60{ 61 float shadow = 1.0; 62 vec4 shadowCoord = P / P.w; 63 shadowCoord.st = shadowCoord.st * 0.5 + 0.5; 64 65 if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0) 66 { 67 float dist = texture(samplerShadowMap, vec3(shadowCoord.st + offset, layer)).r; 68 if (shadowCoord.w > 0.0 && dist < shadowCoord.z) 69 { 70 shadow = SHADOW_FACTOR; 71 } 72 } 73 return shadow; 74} 75 76float filterPCF(vec4 sc, float layer) 77{ 78 ivec2 texDim = textureSize(samplerShadowMap, 0).xy; 79 float scale = 1.5; 80 float dx = scale * 1.0 / float(texDim.x); 81 float dy = scale * 1.0 / float(texDim.y); 82 83 float shadowFactor = 0.0; 84 int count = 0; 85 int range = 1; 86 87 for (int x = -range; x <= range; x++) 88 { 89 for (int y = -range; y <= range; y++) 90 { 91 shadowFactor += textureProj(sc, layer, vec2(dx*x, dy*y)); 92 count++; 93 } 94 95 } 96 return shadowFactor / count; 97} 98 99vec3 shadow(vec3 fragcolor, vec3 fragpos) { 100 for(int i = 0; i < LIGHT_COUNT; ++i) 101 { 102 vec4 shadowClip = ubo.lights[i].viewMatrix * vec4(fragpos, 1.0); 103 104 float shadowFactor; 105 #ifdef USE_PCF 106 shadowFactor= filterPCF(shadowClip, i); 107 #else 108 shadowFactor = textureProj(shadowClip, i, vec2(0.0)); 109 #endif 110 111 fragcolor *= shadowFactor; 112 } 113 return fragcolor; 114} 115 116void main() 117{ 118 // Get G-Buffer values 119 vec3 fragPos = texture(samplerposition, inUV).rgb; 120 vec3 normal = texture(samplerNormal, inUV).rgb; 121 vec4 albedo = texture(samplerAlbedo, inUV); 122 123 // Debug display 124 if (ubo.debugDisplayTarget > 0) { 125 switch (ubo.debugDisplayTarget) { 126 case 1: 127 outFragColor.rgb = shadow(vec3(1.0), fragPos).rgb; 128 break; 129 case 2: 130 outFragColor.rgb = fragPos; 131 break; 132 case 3: 133 outFragColor.rgb = normal; 134 break; 135 case 4: 136 outFragColor.rgb = albedo.rgb; 137 break; 138 case 5: 139 outFragColor.rgb = albedo.aaa; 140 break; 141 } 142 outFragColor.a = 1.0; 143 return; 144 } 145 146 // Ambient part 147 vec3 fragcolor = albedo.rgb * AMBIENT_LIGHT; 148 149 vec3 N = normalize(normal); 150 151 for(int i = 0; i < LIGHT_COUNT; ++i) 152 { 153 // Vector to light 154 vec3 L = ubo.lights[i].position.xyz - fragPos; 155 // Distance from light to fragment position 156 float dist = length(L); 157 L = normalize(L); 158 159 // Viewer to fragment 160 vec3 V = ubo.viewPos.xyz - fragPos; 161 V = normalize(V); 162 163 float lightCosInnerAngle = cos(radians(15.0)); 164 float lightCosOuterAngle = cos(radians(25.0)); 165 float lightRange = 100.0; 166 167 // Direction vector from source to target 168 vec3 dir = normalize(ubo.lights[i].position.xyz - ubo.lights[i].target.xyz); 169 170 // Dual cone spot light with smooth transition between inner and outer angle 171 float cosDir = dot(L, dir); 172 float spotEffect = smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); 173 float heightAttenuation = smoothstep(lightRange, 0.0f, dist); 174 175 // Diffuse lighting 176 float NdotL = max(0.0, dot(N, L)); 177 vec3 diff = vec3(NdotL); 178 179 // Specular lighting 180 vec3 R = reflect(-L, N); 181 float NdotR = max(0.0, dot(R, V)); 182 vec3 spec = vec3(pow(NdotR, 16.0) * albedo.a * 2.5); 183 184 fragcolor += vec3((diff + spec) * spotEffect * heightAttenuation) * ubo.lights[i].color.rgb * albedo.rgb; 185 } 186 187 // Shadow calculations in a separate pass 188 if (ubo.useShadows > 0) 189 { 190 fragcolor = shadow(fragcolor, fragPos); 191 } 192 193 outFragColor = vec4(fragcolor, 1.0); 194} 195