shadowsFragmentFunctions.fx 24 KB

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