shadowsFragmentFunctions.fx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. #ifdef SHADOWS
  2. #ifndef SHADOWFLOAT
  3. float unpack(vec4 color)
  4. {
  5. const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
  6. return dot(color, bit_shift);
  7. }
  8. #endif
  9. float computeFallOff(float value, vec2 clipSpace, float frustumEdgeFalloff)
  10. {
  11. float mask = smoothstep(1.0 - frustumEdgeFalloff, 1.0, clamp(dot(clipSpace, clipSpace), 0., 1.));
  12. return mix(value, 1.0, mask);
  13. }
  14. float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, vec2 depthValues)
  15. {
  16. vec3 directionToLight = vPositionW - lightPosition;
  17. float depth = length(directionToLight);
  18. depth = (depth + depthValues.x) / (depthValues.y);
  19. depth = clamp(depth, 0., 1.0);
  20. directionToLight = normalize(directionToLight);
  21. directionToLight.y = -directionToLight.y;
  22. #ifndef SHADOWFLOAT
  23. float shadow = unpack(textureCube(shadowSampler, directionToLight));
  24. #else
  25. float shadow = textureCube(shadowSampler, directionToLight).x;
  26. #endif
  27. if (depth > shadow)
  28. {
  29. return darkness;
  30. }
  31. return 1.0;
  32. }
  33. float computeShadowWithPoissonSamplingCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float darkness, vec2 depthValues)
  34. {
  35. vec3 directionToLight = vPositionW - lightPosition;
  36. float depth = length(directionToLight);
  37. depth = (depth + depthValues.x) / (depthValues.y);
  38. depth = clamp(depth, 0., 1.0);
  39. directionToLight = normalize(directionToLight);
  40. directionToLight.y = -directionToLight.y;
  41. float visibility = 1.;
  42. vec3 poissonDisk[4];
  43. poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
  44. poissonDisk[1] = vec3(1.0, -1.0, -1.0);
  45. poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
  46. poissonDisk[3] = vec3(1.0, -1.0, 1.0);
  47. // Poisson Sampling
  48. #ifndef SHADOWFLOAT
  49. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < depth) visibility -= 0.25;
  50. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < depth) visibility -= 0.25;
  51. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < depth) visibility -= 0.25;
  52. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < depth) visibility -= 0.25;
  53. #else
  54. if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < depth) visibility -= 0.25;
  55. if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < depth) visibility -= 0.25;
  56. if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < depth) visibility -= 0.25;
  57. if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < depth) visibility -= 0.25;
  58. #endif
  59. return min(1.0, visibility + darkness);
  60. }
  61. float computeShadowWithESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
  62. {
  63. vec3 directionToLight = vPositionW - lightPosition;
  64. float depth = length(directionToLight);
  65. depth = (depth + depthValues.x) / (depthValues.y);
  66. float shadowPixelDepth = clamp(depth, 0., 1.0);
  67. directionToLight = normalize(directionToLight);
  68. directionToLight.y = -directionToLight.y;
  69. #ifndef SHADOWFLOAT
  70. float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
  71. #else
  72. float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
  73. #endif
  74. float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
  75. return esm;
  76. }
  77. float computeShadowWithCloseESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
  78. {
  79. vec3 directionToLight = vPositionW - lightPosition;
  80. float depth = length(directionToLight);
  81. depth = (depth + depthValues.x) / (depthValues.y);
  82. float shadowPixelDepth = clamp(depth, 0., 1.0);
  83. directionToLight = normalize(directionToLight);
  84. directionToLight.y = -directionToLight.y;
  85. #ifndef SHADOWFLOAT
  86. float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
  87. #else
  88. float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
  89. #endif
  90. float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
  91. return esm;
  92. }
  93. float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
  94. {
  95. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  96. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  97. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  98. {
  99. return 1.0;
  100. }
  101. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  102. #ifndef SHADOWFLOAT
  103. float shadow = unpack(texture2D(shadowSampler, uv));
  104. #else
  105. float shadow = texture2D(shadowSampler, uv).x;
  106. #endif
  107. if (shadowPixelDepth > shadow)
  108. {
  109. return computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff);
  110. }
  111. return 1.;
  112. }
  113. float computeShadowWithPoissonSampling(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float mapSize, float darkness, float frustumEdgeFalloff)
  114. {
  115. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  116. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  117. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  118. {
  119. return 1.0;
  120. }
  121. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  122. float visibility = 1.;
  123. vec2 poissonDisk[4];
  124. poissonDisk[0] = vec2(-0.94201624, -0.39906216);
  125. poissonDisk[1] = vec2(0.94558609, -0.76890725);
  126. poissonDisk[2] = vec2(-0.094184101, -0.92938870);
  127. poissonDisk[3] = vec2(0.34495938, 0.29387760);
  128. // Poisson Sampling
  129. #ifndef SHADOWFLOAT
  130. if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  131. if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  132. if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  133. if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  134. #else
  135. if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  136. if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  137. if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  138. if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  139. #endif
  140. return computeFallOff(min(1.0, visibility + darkness), clipSpace.xy, frustumEdgeFalloff);
  141. }
  142. float computeShadowWithESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
  143. {
  144. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  145. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  146. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  147. {
  148. return 1.0;
  149. }
  150. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  151. #ifndef SHADOWFLOAT
  152. float shadowMapSample = unpack(texture2D(shadowSampler, uv));
  153. #else
  154. float shadowMapSample = texture2D(shadowSampler, uv).x;
  155. #endif
  156. float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
  157. return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
  158. }
  159. float computeShadowWithCloseESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
  160. {
  161. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  162. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  163. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  164. {
  165. return 1.0;
  166. }
  167. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  168. #ifndef SHADOWFLOAT
  169. float shadowMapSample = unpack(texture2D(shadowSampler, uv));
  170. #else
  171. float shadowMapSample = texture2D(shadowSampler, uv).x;
  172. #endif
  173. float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
  174. return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
  175. }
  176. #ifdef WEBGL2
  177. // Shadow PCF kernel size 1 with a single tap (lowest quality)
  178. float computeShadowWithPCF1(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
  179. {
  180. if (depthMetric > 1.0 || depthMetric < 0.0) {
  181. return 1.0;
  182. }
  183. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  184. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  185. float shadow = texture2D(shadowSampler, uvDepth);
  186. shadow = mix(darkness, 1., shadow);
  187. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  188. }
  189. // Shadow PCF kernel 3*3 in only 4 taps (medium quality)
  190. // This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
  191. // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
  192. float computeShadowWithPCF3(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
  193. {
  194. if (depthMetric > 1.0 || depthMetric < 0.0) {
  195. return 1.0;
  196. }
  197. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  198. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  199. vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
  200. uv += 0.5; // offset of half to be in the center of the texel
  201. vec2 st = fract(uv); // how far from the center
  202. vec2 base_uv = floor(uv) - 0.5; // texel coord
  203. base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
  204. // Equation resolved to fit in a 3*3 distribution like
  205. // 1 2 1
  206. // 2 4 2
  207. // 1 2 1
  208. vec2 uvw0 = 3. - 2. * st;
  209. vec2 uvw1 = 1. + 2. * st;
  210. vec2 u = vec2((2. - st.x) / uvw0.x - 1., st.x / uvw1.x + 1.) * shadowMapSizeAndInverse.y;
  211. vec2 v = vec2((2. - st.y) / uvw0.y - 1., st.y / uvw1.y + 1.) * shadowMapSizeAndInverse.y;
  212. float shadow = 0.;
  213. shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
  214. shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
  215. shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
  216. shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
  217. shadow = shadow / 16.;
  218. shadow = mix(darkness, 1., shadow);
  219. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  220. }
  221. // Shadow PCF kernel 5*5 in only 9 taps (high quality)
  222. // This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
  223. // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
  224. float computeShadowWithPCF5(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
  225. {
  226. if (depthMetric > 1.0 || depthMetric < 0.0) {
  227. return 1.0;
  228. }
  229. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  230. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  231. vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
  232. uv += 0.5; // offset of half to be in the center of the texel
  233. vec2 st = fract(uv); // how far from the center
  234. vec2 base_uv = floor(uv) - 0.5; // texel coord
  235. base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
  236. // Equation resolved to fit in a 5*5 distribution like
  237. // 1 2 4 2 1
  238. vec2 uvw0 = 4. - 3. * st;
  239. vec2 uvw1 = vec2(7.);
  240. vec2 uvw2 = 1. + 3. * st;
  241. vec3 u = vec3((3. - 2. * st.x) / uvw0.x - 2., (3. + st.x) / uvw1.x, st.x / uvw2.x + 2.) * shadowMapSizeAndInverse.y;
  242. vec3 v = vec3((3. - 2. * st.y) / uvw0.y - 2., (3. + st.y) / uvw1.y, st.y / uvw2.y + 2.) * shadowMapSizeAndInverse.y;
  243. float shadow = 0.;
  244. shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
  245. shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
  246. shadow += uvw2.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[0]), uvDepth.z));
  247. shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
  248. shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
  249. shadow += uvw2.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[1]), uvDepth.z));
  250. shadow += uvw0.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[2]), uvDepth.z));
  251. shadow += uvw1.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[2]), uvDepth.z));
  252. shadow += uvw2.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[2]), uvDepth.z));
  253. shadow = shadow / 144.;
  254. shadow = mix(darkness, 1., shadow);
  255. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  256. }
  257. const vec3 PoissonSamplers32[64] = vec3[64](
  258. vec3(0.06407013, 0.05409927, 0.),
  259. vec3(0.7366577, 0.5789394, 0.),
  260. vec3(-0.6270542, -0.5320278, 0.),
  261. vec3(-0.4096107, 0.8411095, 0.),
  262. vec3(0.6849564, -0.4990818, 0.),
  263. vec3(-0.874181, -0.04579735, 0.),
  264. vec3(0.9989998, 0.0009880066, 0.),
  265. vec3(-0.004920578, -0.9151649, 0.),
  266. vec3(0.1805763, 0.9747483, 0.),
  267. vec3(-0.2138451, 0.2635818, 0.),
  268. vec3(0.109845, 0.3884785, 0.),
  269. vec3(0.06876755, -0.3581074, 0.),
  270. vec3(0.374073, -0.7661266, 0.),
  271. vec3(0.3079132, -0.1216763, 0.),
  272. vec3(-0.3794335, -0.8271583, 0.),
  273. vec3(-0.203878, -0.07715034, 0.),
  274. vec3(0.5912697, 0.1469799, 0.),
  275. vec3(-0.88069, 0.3031784, 0.),
  276. vec3(0.5040108, 0.8283722, 0.),
  277. vec3(-0.5844124, 0.5494877, 0.),
  278. vec3(0.6017799, -0.1726654, 0.),
  279. vec3(-0.5554981, 0.1559997, 0.),
  280. vec3(-0.3016369, -0.3900928, 0.),
  281. vec3(-0.5550632, -0.1723762, 0.),
  282. vec3(0.925029, 0.2995041, 0.),
  283. vec3(-0.2473137, 0.5538505, 0.),
  284. vec3(0.9183037, -0.2862392, 0.),
  285. vec3(0.2469421, 0.6718712, 0.),
  286. vec3(0.3916397, -0.4328209, 0.),
  287. vec3(-0.03576927, -0.6220032, 0.),
  288. vec3(-0.04661255, 0.7995201, 0.),
  289. vec3(0.4402924, 0.3640312, 0.),
  290. vec3(0., 0., 0.),
  291. vec3(0., 0., 0.),
  292. vec3(0., 0., 0.),
  293. vec3(0., 0., 0.),
  294. vec3(0., 0., 0.),
  295. vec3(0., 0., 0.),
  296. vec3(0., 0., 0.),
  297. vec3(0., 0., 0.),
  298. vec3(0., 0., 0.),
  299. vec3(0., 0., 0.),
  300. vec3(0., 0., 0.),
  301. vec3(0., 0., 0.),
  302. vec3(0., 0., 0.),
  303. vec3(0., 0., 0.),
  304. vec3(0., 0., 0.),
  305. vec3(0., 0., 0.),
  306. vec3(0., 0., 0.),
  307. vec3(0., 0., 0.),
  308. vec3(0., 0., 0.),
  309. vec3(0., 0., 0.),
  310. vec3(0., 0., 0.),
  311. vec3(0., 0., 0.),
  312. vec3(0., 0., 0.),
  313. vec3(0., 0., 0.),
  314. vec3(0., 0., 0.),
  315. vec3(0., 0., 0.),
  316. vec3(0., 0., 0.),
  317. vec3(0., 0., 0.),
  318. vec3(0., 0., 0.),
  319. vec3(0., 0., 0.),
  320. vec3(0., 0., 0.),
  321. vec3(0., 0., 0.)
  322. );
  323. const vec3 PoissonSamplers64[64] = vec3[64](
  324. vec3(-0.613392, 0.617481, 0.),
  325. vec3(0.170019, -0.040254, 0.),
  326. vec3(-0.299417, 0.791925, 0.),
  327. vec3(0.645680, 0.493210, 0.),
  328. vec3(-0.651784, 0.717887, 0.),
  329. vec3(0.421003, 0.027070, 0.),
  330. vec3(-0.817194, -0.271096, 0.),
  331. vec3(-0.705374, -0.668203, 0.),
  332. vec3(0.977050, -0.108615, 0.),
  333. vec3(0.063326, 0.142369, 0.),
  334. vec3(0.203528, 0.214331, 0.),
  335. vec3(-0.667531, 0.326090, 0.),
  336. vec3(-0.098422, -0.295755, 0.),
  337. vec3(-0.885922, 0.215369, 0.),
  338. vec3(0.566637, 0.605213, 0.),
  339. vec3(0.039766, -0.396100, 0.),
  340. vec3(0.751946, 0.453352, 0.),
  341. vec3(0.078707, -0.715323, 0.),
  342. vec3(-0.075838, -0.529344, 0.),
  343. vec3(0.724479, -0.580798, 0.),
  344. vec3(0.222999, -0.215125, 0.),
  345. vec3(-0.467574, -0.405438, 0.),
  346. vec3(-0.248268, -0.814753, 0.),
  347. vec3(0.354411, -0.887570, 0.),
  348. vec3(0.175817, 0.382366, 0.),
  349. vec3(0.487472, -0.063082, 0.),
  350. vec3(-0.084078, 0.898312, 0.),
  351. vec3(0.488876, -0.783441, 0.),
  352. vec3(0.470016, 0.217933, 0.),
  353. vec3(-0.696890, -0.549791, 0.),
  354. vec3(-0.149693, 0.605762, 0.),
  355. vec3(0.034211, 0.979980, 0.),
  356. vec3(0.503098, -0.308878, 0.),
  357. vec3(-0.016205, -0.872921, 0.),
  358. vec3(0.385784, -0.393902, 0.),
  359. vec3(-0.146886, -0.859249, 0.),
  360. vec3(0.643361, 0.164098, 0.),
  361. vec3(0.634388, -0.049471, 0.),
  362. vec3(-0.688894, 0.007843, 0.),
  363. vec3(0.464034, -0.188818, 0.),
  364. vec3(-0.440840, 0.137486, 0.),
  365. vec3(0.364483, 0.511704, 0.),
  366. vec3(0.034028, 0.325968, 0.),
  367. vec3(0.099094, -0.308023, 0.),
  368. vec3(0.693960, -0.366253, 0.),
  369. vec3(0.678884, -0.204688, 0.),
  370. vec3(0.001801, 0.780328, 0.),
  371. vec3(0.145177, -0.898984, 0.),
  372. vec3(0.062655, -0.611866, 0.),
  373. vec3(0.315226, -0.604297, 0.),
  374. vec3(-0.780145, 0.486251, 0.),
  375. vec3(-0.371868, 0.882138, 0.),
  376. vec3(0.200476, 0.494430, 0.),
  377. vec3(-0.494552, -0.711051, 0.),
  378. vec3(0.612476, 0.705252, 0.),
  379. vec3(-0.578845, -0.768792, 0.),
  380. vec3(-0.772454, -0.090976, 0.),
  381. vec3(0.504440, 0.372295, 0.),
  382. vec3(0.155736, 0.065157, 0.),
  383. vec3(0.391522, 0.849605, 0.),
  384. vec3(-0.620106, -0.328104, 0.),
  385. vec3(0.789239, -0.419965, 0.),
  386. vec3(-0.545396, 0.538133, 0.),
  387. vec3(-0.178564, -0.596057, 0.)
  388. );
  389. // PCSS
  390. // This helps to achieve a contact hardening effect on the shadow
  391. // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
  392. // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
  393. // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
  394. float computeShadowWithPCSS(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers)
  395. {
  396. if (depthMetric > 1.0 || depthMetric < 0.0) {
  397. return 1.0;
  398. }
  399. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  400. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  401. float blockerDepth = 0.0;
  402. float sumBlockerDepth = 0.0;
  403. float numBlocker = 0.0;
  404. for (int i = 0; i < searchTapCount; i ++) {
  405. blockerDepth = texture(depthSampler, uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PoissonSamplers32[i].xy)).r;
  406. if (blockerDepth < depthMetric) {
  407. sumBlockerDepth += blockerDepth;
  408. numBlocker++;
  409. }
  410. }
  411. if (numBlocker < 1.0) {
  412. return 1.0;
  413. }
  414. float avgBlockerDepth = sumBlockerDepth / numBlocker;
  415. // Offset preventing aliasing on contact.
  416. float AAOffset = shadowMapSizeInverse * 10.;
  417. // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
  418. // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
  419. float penumbraRatio = ((depthMetric - avgBlockerDepth) + AAOffset);
  420. float filterRadius = penumbraRatio * lightSizeUV * shadowMapSizeInverse;
  421. float random = getRand(vPositionFromLight.xy);
  422. float rotationAngle = random * 3.1415926;
  423. vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
  424. float shadow = 0.;
  425. for (int i = 0; i < pcfTapCount; i++) {
  426. vec3 offset = poissonSamplers[i];
  427. // Rotated offset.
  428. offset = vec3(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0.);
  429. shadow += texture2D(shadowSampler, uvDepth + offset * filterRadius);
  430. }
  431. shadow /= float(pcfTapCount);
  432. // Blocker distance falloff
  433. shadow = mix(shadow, 1., depthMetric - avgBlockerDepth);
  434. // Apply darkness
  435. shadow = mix(darkness, 1., shadow);
  436. // Apply light frustrum fallof
  437. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  438. }
  439. float computeShadowWithPCSS16(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
  440. {
  441. return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32);
  442. }
  443. float computeShadowWithPCSS32(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
  444. {
  445. return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32);
  446. }
  447. float computeShadowWithPCSS64(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
  448. {
  449. return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
  450. }
  451. #endif
  452. #endif