shadowsFragmentFunctions.fx 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. #ifdef SHADOWS
  2. #ifndef SHADOWFLOAT
  3. // Dupplicate to prevent include in include issues
  4. float unpack(vec4 color)
  5. {
  6. 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);
  7. return dot(color, bit_shift);
  8. }
  9. #endif
  10. float computeFallOff(float value, vec2 clipSpace, float frustumEdgeFalloff)
  11. {
  12. float mask = smoothstep(1.0 - frustumEdgeFalloff, 1.00000012, clamp(dot(clipSpace, clipSpace), 0., 1.));
  13. return mix(value, 1.0, mask);
  14. }
  15. #define inline
  16. float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, vec2 depthValues)
  17. {
  18. vec3 directionToLight = vPositionW - lightPosition;
  19. float depth = length(directionToLight);
  20. depth = (depth + depthValues.x) / (depthValues.y);
  21. depth = clamp(depth, 0., 1.0);
  22. directionToLight = normalize(directionToLight);
  23. directionToLight.y = -directionToLight.y;
  24. #ifndef SHADOWFLOAT
  25. float shadow = unpack(textureCube(shadowSampler, directionToLight));
  26. #else
  27. float shadow = textureCube(shadowSampler, directionToLight).x;
  28. #endif
  29. return depth > shadow ? darkness : 1.0;
  30. }
  31. #define inline
  32. float computeShadowWithPoissonSamplingCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float darkness, vec2 depthValues)
  33. {
  34. vec3 directionToLight = vPositionW - lightPosition;
  35. float depth = length(directionToLight);
  36. depth = (depth + depthValues.x) / (depthValues.y);
  37. depth = clamp(depth, 0., 1.0);
  38. directionToLight = normalize(directionToLight);
  39. directionToLight.y = -directionToLight.y;
  40. float visibility = 1.;
  41. vec3 poissonDisk[4];
  42. poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
  43. poissonDisk[1] = vec3(1.0, -1.0, -1.0);
  44. poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
  45. poissonDisk[3] = vec3(1.0, -1.0, 1.0);
  46. // Poisson Sampling
  47. #ifndef SHADOWFLOAT
  48. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < depth) visibility -= 0.25;
  49. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < depth) visibility -= 0.25;
  50. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < depth) visibility -= 0.25;
  51. if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < depth) visibility -= 0.25;
  52. #else
  53. if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < depth) visibility -= 0.25;
  54. if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < depth) visibility -= 0.25;
  55. if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < depth) visibility -= 0.25;
  56. if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < depth) visibility -= 0.25;
  57. #endif
  58. return min(1.0, visibility + darkness);
  59. }
  60. #define inline
  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. #define inline
  78. float computeShadowWithCloseESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
  79. {
  80. vec3 directionToLight = vPositionW - lightPosition;
  81. float depth = length(directionToLight);
  82. depth = (depth + depthValues.x) / (depthValues.y);
  83. float shadowPixelDepth = clamp(depth, 0., 1.0);
  84. directionToLight = normalize(directionToLight);
  85. directionToLight.y = -directionToLight.y;
  86. #ifndef SHADOWFLOAT
  87. float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
  88. #else
  89. float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
  90. #endif
  91. float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
  92. return esm;
  93. }
  94. #ifdef WEBGL2
  95. #define inline
  96. float computeShadowCSM(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray shadowSampler, float darkness, float frustumEdgeFalloff)
  97. {
  98. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  99. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  100. vec3 uvLayer = vec3(uv.x, uv.y, layer);
  101. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  102. #ifndef SHADOWFLOAT
  103. float shadow = unpack(texture2D(shadowSampler, uvLayer));
  104. #else
  105. float shadow = texture2D(shadowSampler, uvLayer).x;
  106. #endif
  107. return shadowPixelDepth > shadow ? computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff) : 1.;
  108. }
  109. #endif
  110. #define inline
  111. float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
  112. {
  113. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  114. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  115. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  116. {
  117. return 1.0;
  118. }
  119. else
  120. {
  121. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  122. #ifndef SHADOWFLOAT
  123. float shadow = unpack(texture2D(shadowSampler, uv));
  124. #else
  125. float shadow = texture2D(shadowSampler, uv).x;
  126. #endif
  127. return shadowPixelDepth > shadow ? computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff) : 1.;
  128. }
  129. }
  130. #define inline
  131. float computeShadowWithPoissonSampling(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float mapSize, float darkness, float frustumEdgeFalloff)
  132. {
  133. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  134. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  135. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  136. {
  137. return 1.0;
  138. }
  139. else
  140. {
  141. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  142. float visibility = 1.;
  143. vec2 poissonDisk[4];
  144. poissonDisk[0] = vec2(-0.94201624, -0.39906216);
  145. poissonDisk[1] = vec2(0.94558609, -0.76890725);
  146. poissonDisk[2] = vec2(-0.094184101, -0.92938870);
  147. poissonDisk[3] = vec2(0.34495938, 0.29387760);
  148. // Poisson Sampling
  149. #ifndef SHADOWFLOAT
  150. if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  151. if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  152. if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  153. if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
  154. #else
  155. if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  156. if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  157. if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  158. if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
  159. #endif
  160. return computeFallOff(min(1.0, visibility + darkness), clipSpace.xy, frustumEdgeFalloff);
  161. }
  162. }
  163. #define inline
  164. float computeShadowWithESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
  165. {
  166. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  167. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  168. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  169. {
  170. return 1.0;
  171. }
  172. else
  173. {
  174. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  175. #ifndef SHADOWFLOAT
  176. float shadowMapSample = unpack(texture2D(shadowSampler, uv));
  177. #else
  178. float shadowMapSample = texture2D(shadowSampler, uv).x;
  179. #endif
  180. float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
  181. return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
  182. }
  183. }
  184. #define inline
  185. float computeShadowWithCloseESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
  186. {
  187. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  188. vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
  189. if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
  190. {
  191. return 1.0;
  192. }
  193. else
  194. {
  195. float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
  196. #ifndef SHADOWFLOAT
  197. float shadowMapSample = unpack(texture2D(shadowSampler, uv));
  198. #else
  199. float shadowMapSample = texture2D(shadowSampler, uv).x;
  200. #endif
  201. float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
  202. return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
  203. }
  204. }
  205. #ifdef WEBGL2
  206. #define GREATEST_LESS_THAN_ONE 0.99999994
  207. // Shadow PCF kernel size 1 with a single tap (lowest quality)
  208. #define inline
  209. float computeShadowWithCSMPCF1(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArrayShadow shadowSampler, float darkness, float frustumEdgeFalloff)
  210. {
  211. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  212. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  213. uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
  214. vec4 uvDepthLayer = vec4(uvDepth.x, uvDepth.y, layer, uvDepth.z);
  215. float shadow = texture(shadowSampler, uvDepthLayer);
  216. shadow = mix(darkness, 1., shadow);
  217. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  218. }
  219. // Shadow PCF kernel 3*3 in only 4 taps (medium quality)
  220. // This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
  221. // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
  222. #define inline
  223. float computeShadowWithCSMPCF3(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArrayShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
  224. {
  225. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  226. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  227. uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
  228. vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
  229. uv += 0.5; // offset of half to be in the center of the texel
  230. vec2 st = fract(uv); // how far from the center
  231. vec2 base_uv = floor(uv) - 0.5; // texel coord
  232. base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
  233. // Equation resolved to fit in a 3*3 distribution like
  234. // 1 2 1
  235. // 2 4 2
  236. // 1 2 1
  237. vec2 uvw0 = 3. - 2. * st;
  238. vec2 uvw1 = 1. + 2. * st;
  239. vec2 u = vec2((2. - st.x) / uvw0.x - 1., st.x / uvw1.x + 1.) * shadowMapSizeAndInverse.y;
  240. vec2 v = vec2((2. - st.y) / uvw0.y - 1., st.y / uvw1.y + 1.) * shadowMapSizeAndInverse.y;
  241. float shadow = 0.;
  242. shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[0]), layer, uvDepth.z));
  243. shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[0]), layer, uvDepth.z));
  244. shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[1]), layer, uvDepth.z));
  245. shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[1]), layer, uvDepth.z));
  246. shadow = shadow / 16.;
  247. shadow = mix(darkness, 1., shadow);
  248. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  249. }
  250. // Shadow PCF kernel 5*5 in only 9 taps (high quality)
  251. // This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
  252. // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
  253. #define inline
  254. float computeShadowWithCSMPCF5(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArrayShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
  255. {
  256. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  257. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  258. uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
  259. vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
  260. uv += 0.5; // offset of half to be in the center of the texel
  261. vec2 st = fract(uv); // how far from the center
  262. vec2 base_uv = floor(uv) - 0.5; // texel coord
  263. base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
  264. // Equation resolved to fit in a 5*5 distribution like
  265. // 1 2 4 2 1
  266. vec2 uvw0 = 4. - 3. * st;
  267. vec2 uvw1 = vec2(7.);
  268. vec2 uvw2 = 1. + 3. * st;
  269. vec3 u = vec3((3. - 2. * st.x) / uvw0.x - 2., (3. + st.x) / uvw1.x, st.x / uvw2.x + 2.) * shadowMapSizeAndInverse.y;
  270. vec3 v = vec3((3. - 2. * st.y) / uvw0.y - 2., (3. + st.y) / uvw1.y, st.y / uvw2.y + 2.) * shadowMapSizeAndInverse.y;
  271. float shadow = 0.;
  272. shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[0]), layer, uvDepth.z));
  273. shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[0]), layer, uvDepth.z));
  274. shadow += uvw2.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[2], v[0]), layer, uvDepth.z));
  275. shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[1]), layer, uvDepth.z));
  276. shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[1]), layer, uvDepth.z));
  277. shadow += uvw2.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[2], v[1]), layer, uvDepth.z));
  278. shadow += uvw0.x * uvw2.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[2]), layer, uvDepth.z));
  279. shadow += uvw1.x * uvw2.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[2]), layer, uvDepth.z));
  280. shadow += uvw2.x * uvw2.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[2], v[2]), layer, uvDepth.z));
  281. shadow = shadow / 144.;
  282. shadow = mix(darkness, 1., shadow);
  283. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  284. }
  285. // Shadow PCF kernel size 1 with a single tap (lowest quality)
  286. #define inline
  287. float computeShadowWithPCF1(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
  288. {
  289. if (depthMetric > 1.0 || depthMetric < 0.0) {
  290. return 1.0;
  291. }
  292. else
  293. {
  294. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  295. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  296. float shadow = texture2D(shadowSampler, uvDepth);
  297. shadow = mix(darkness, 1., shadow);
  298. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  299. }
  300. }
  301. // Shadow PCF kernel 3*3 in only 4 taps (medium quality)
  302. // This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
  303. // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
  304. #define inline
  305. float computeShadowWithPCF3(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
  306. {
  307. if (depthMetric > 1.0 || depthMetric < 0.0) {
  308. return 1.0;
  309. }
  310. else
  311. {
  312. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  313. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  314. vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
  315. uv += 0.5; // offset of half to be in the center of the texel
  316. vec2 st = fract(uv); // how far from the center
  317. vec2 base_uv = floor(uv) - 0.5; // texel coord
  318. base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
  319. // Equation resolved to fit in a 3*3 distribution like
  320. // 1 2 1
  321. // 2 4 2
  322. // 1 2 1
  323. vec2 uvw0 = 3. - 2. * st;
  324. vec2 uvw1 = 1. + 2. * st;
  325. vec2 u = vec2((2. - st.x) / uvw0.x - 1., st.x / uvw1.x + 1.) * shadowMapSizeAndInverse.y;
  326. vec2 v = vec2((2. - st.y) / uvw0.y - 1., st.y / uvw1.y + 1.) * shadowMapSizeAndInverse.y;
  327. float shadow = 0.;
  328. shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
  329. shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
  330. shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
  331. shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
  332. shadow = shadow / 16.;
  333. shadow = mix(darkness, 1., shadow);
  334. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  335. }
  336. }
  337. // Shadow PCF kernel 5*5 in only 9 taps (high quality)
  338. // This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
  339. // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
  340. #define inline
  341. float computeShadowWithPCF5(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
  342. {
  343. if (depthMetric > 1.0 || depthMetric < 0.0) {
  344. return 1.0;
  345. }
  346. else
  347. {
  348. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  349. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  350. vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
  351. uv += 0.5; // offset of half to be in the center of the texel
  352. vec2 st = fract(uv); // how far from the center
  353. vec2 base_uv = floor(uv) - 0.5; // texel coord
  354. base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
  355. // Equation resolved to fit in a 5*5 distribution like
  356. // 1 2 4 2 1
  357. vec2 uvw0 = 4. - 3. * st;
  358. vec2 uvw1 = vec2(7.);
  359. vec2 uvw2 = 1. + 3. * st;
  360. vec3 u = vec3((3. - 2. * st.x) / uvw0.x - 2., (3. + st.x) / uvw1.x, st.x / uvw2.x + 2.) * shadowMapSizeAndInverse.y;
  361. vec3 v = vec3((3. - 2. * st.y) / uvw0.y - 2., (3. + st.y) / uvw1.y, st.y / uvw2.y + 2.) * shadowMapSizeAndInverse.y;
  362. float shadow = 0.;
  363. shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
  364. shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
  365. shadow += uvw2.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[0]), uvDepth.z));
  366. shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
  367. shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
  368. shadow += uvw2.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[1]), uvDepth.z));
  369. shadow += uvw0.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[2]), uvDepth.z));
  370. shadow += uvw1.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[2]), uvDepth.z));
  371. shadow += uvw2.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[2]), uvDepth.z));
  372. shadow = shadow / 144.;
  373. shadow = mix(darkness, 1., shadow);
  374. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  375. }
  376. }
  377. const vec3 PoissonSamplers32[64] = vec3[64](
  378. vec3(0.06407013, 0.05409927, 0.),
  379. vec3(0.7366577, 0.5789394, 0.),
  380. vec3(-0.6270542, -0.5320278, 0.),
  381. vec3(-0.4096107, 0.8411095, 0.),
  382. vec3(0.6849564, -0.4990818, 0.),
  383. vec3(-0.874181, -0.04579735, 0.),
  384. vec3(0.9989998, 0.0009880066, 0.),
  385. vec3(-0.004920578, -0.9151649, 0.),
  386. vec3(0.1805763, 0.9747483, 0.),
  387. vec3(-0.2138451, 0.2635818, 0.),
  388. vec3(0.109845, 0.3884785, 0.),
  389. vec3(0.06876755, -0.3581074, 0.),
  390. vec3(0.374073, -0.7661266, 0.),
  391. vec3(0.3079132, -0.1216763, 0.),
  392. vec3(-0.3794335, -0.8271583, 0.),
  393. vec3(-0.203878, -0.07715034, 0.),
  394. vec3(0.5912697, 0.1469799, 0.),
  395. vec3(-0.88069, 0.3031784, 0.),
  396. vec3(0.5040108, 0.8283722, 0.),
  397. vec3(-0.5844124, 0.5494877, 0.),
  398. vec3(0.6017799, -0.1726654, 0.),
  399. vec3(-0.5554981, 0.1559997, 0.),
  400. vec3(-0.3016369, -0.3900928, 0.),
  401. vec3(-0.5550632, -0.1723762, 0.),
  402. vec3(0.925029, 0.2995041, 0.),
  403. vec3(-0.2473137, 0.5538505, 0.),
  404. vec3(0.9183037, -0.2862392, 0.),
  405. vec3(0.2469421, 0.6718712, 0.),
  406. vec3(0.3916397, -0.4328209, 0.),
  407. vec3(-0.03576927, -0.6220032, 0.),
  408. vec3(-0.04661255, 0.7995201, 0.),
  409. vec3(0.4402924, 0.3640312, 0.),
  410. vec3(0., 0., 0.),
  411. vec3(0., 0., 0.),
  412. vec3(0., 0., 0.),
  413. vec3(0., 0., 0.),
  414. vec3(0., 0., 0.),
  415. vec3(0., 0., 0.),
  416. vec3(0., 0., 0.),
  417. vec3(0., 0., 0.),
  418. vec3(0., 0., 0.),
  419. vec3(0., 0., 0.),
  420. vec3(0., 0., 0.),
  421. vec3(0., 0., 0.),
  422. vec3(0., 0., 0.),
  423. vec3(0., 0., 0.),
  424. vec3(0., 0., 0.),
  425. vec3(0., 0., 0.),
  426. vec3(0., 0., 0.),
  427. vec3(0., 0., 0.),
  428. vec3(0., 0., 0.),
  429. vec3(0., 0., 0.),
  430. vec3(0., 0., 0.),
  431. vec3(0., 0., 0.),
  432. vec3(0., 0., 0.),
  433. vec3(0., 0., 0.),
  434. vec3(0., 0., 0.),
  435. vec3(0., 0., 0.),
  436. vec3(0., 0., 0.),
  437. vec3(0., 0., 0.),
  438. vec3(0., 0., 0.),
  439. vec3(0., 0., 0.),
  440. vec3(0., 0., 0.),
  441. vec3(0., 0., 0.)
  442. );
  443. const vec3 PoissonSamplers64[64] = vec3[64](
  444. vec3(-0.613392, 0.617481, 0.),
  445. vec3(0.170019, -0.040254, 0.),
  446. vec3(-0.299417, 0.791925, 0.),
  447. vec3(0.645680, 0.493210, 0.),
  448. vec3(-0.651784, 0.717887, 0.),
  449. vec3(0.421003, 0.027070, 0.),
  450. vec3(-0.817194, -0.271096, 0.),
  451. vec3(-0.705374, -0.668203, 0.),
  452. vec3(0.977050, -0.108615, 0.),
  453. vec3(0.063326, 0.142369, 0.),
  454. vec3(0.203528, 0.214331, 0.),
  455. vec3(-0.667531, 0.326090, 0.),
  456. vec3(-0.098422, -0.295755, 0.),
  457. vec3(-0.885922, 0.215369, 0.),
  458. vec3(0.566637, 0.605213, 0.),
  459. vec3(0.039766, -0.396100, 0.),
  460. vec3(0.751946, 0.453352, 0.),
  461. vec3(0.078707, -0.715323, 0.),
  462. vec3(-0.075838, -0.529344, 0.),
  463. vec3(0.724479, -0.580798, 0.),
  464. vec3(0.222999, -0.215125, 0.),
  465. vec3(-0.467574, -0.405438, 0.),
  466. vec3(-0.248268, -0.814753, 0.),
  467. vec3(0.354411, -0.887570, 0.),
  468. vec3(0.175817, 0.382366, 0.),
  469. vec3(0.487472, -0.063082, 0.),
  470. vec3(-0.084078, 0.898312, 0.),
  471. vec3(0.488876, -0.783441, 0.),
  472. vec3(0.470016, 0.217933, 0.),
  473. vec3(-0.696890, -0.549791, 0.),
  474. vec3(-0.149693, 0.605762, 0.),
  475. vec3(0.034211, 0.979980, 0.),
  476. vec3(0.503098, -0.308878, 0.),
  477. vec3(-0.016205, -0.872921, 0.),
  478. vec3(0.385784, -0.393902, 0.),
  479. vec3(-0.146886, -0.859249, 0.),
  480. vec3(0.643361, 0.164098, 0.),
  481. vec3(0.634388, -0.049471, 0.),
  482. vec3(-0.688894, 0.007843, 0.),
  483. vec3(0.464034, -0.188818, 0.),
  484. vec3(-0.440840, 0.137486, 0.),
  485. vec3(0.364483, 0.511704, 0.),
  486. vec3(0.034028, 0.325968, 0.),
  487. vec3(0.099094, -0.308023, 0.),
  488. vec3(0.693960, -0.366253, 0.),
  489. vec3(0.678884, -0.204688, 0.),
  490. vec3(0.001801, 0.780328, 0.),
  491. vec3(0.145177, -0.898984, 0.),
  492. vec3(0.062655, -0.611866, 0.),
  493. vec3(0.315226, -0.604297, 0.),
  494. vec3(-0.780145, 0.486251, 0.),
  495. vec3(-0.371868, 0.882138, 0.),
  496. vec3(0.200476, 0.494430, 0.),
  497. vec3(-0.494552, -0.711051, 0.),
  498. vec3(0.612476, 0.705252, 0.),
  499. vec3(-0.578845, -0.768792, 0.),
  500. vec3(-0.772454, -0.090976, 0.),
  501. vec3(0.504440, 0.372295, 0.),
  502. vec3(0.155736, 0.065157, 0.),
  503. vec3(0.391522, 0.849605, 0.),
  504. vec3(-0.620106, -0.328104, 0.),
  505. vec3(0.789239, -0.419965, 0.),
  506. vec3(-0.545396, 0.538133, 0.),
  507. vec3(-0.178564, -0.596057, 0.)
  508. );
  509. // PCSS
  510. // This helps to achieve a contact hardening effect on the shadow
  511. // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
  512. // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
  513. // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
  514. #define inline
  515. float computeShadowWithCSMPCSS(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
  516. {
  517. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  518. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  519. uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
  520. vec4 uvDepthLayer = vec4(uvDepth.x, uvDepth.y, layer, uvDepth.z);
  521. float blockerDepth = 0.0;
  522. float sumBlockerDepth = 0.0;
  523. float numBlocker = 0.0;
  524. for (int i = 0; i < searchTapCount; i ++) {
  525. blockerDepth = texture(depthSampler, vec3(uvDepth.xy + (lightSizeUV * lightSizeUVCorrection * shadowMapSizeInverse * PoissonSamplers32[i].xy), layer)).r;
  526. if (blockerDepth < depthMetric) {
  527. sumBlockerDepth += blockerDepth;
  528. numBlocker++;
  529. }
  530. }
  531. if (numBlocker < 1.0) {
  532. return 1.0;
  533. }
  534. else
  535. {
  536. float avgBlockerDepth = sumBlockerDepth / numBlocker;
  537. // Offset preventing aliasing on contact.
  538. float AAOffset = shadowMapSizeInverse * 10.;
  539. // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
  540. // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
  541. float penumbraRatio = ((depthMetric - avgBlockerDepth) * depthCorrection + AAOffset);
  542. vec4 filterRadius = vec4(penumbraRatio * lightSizeUV * lightSizeUVCorrection * shadowMapSizeInverse, 0., 0.);
  543. float random = getRand(vPositionFromLight.xy);
  544. float rotationAngle = random * 3.1415926;
  545. vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
  546. float shadow = 0.;
  547. for (int i = 0; i < pcfTapCount; i++) {
  548. vec4 offset = vec4(poissonSamplers[i], 0.);
  549. // Rotated offset.
  550. offset = vec4(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0., 0.);
  551. shadow += texture2D(shadowSampler, uvDepthLayer + offset * filterRadius);
  552. }
  553. shadow /= float(pcfTapCount);
  554. // Blocker distance falloff
  555. shadow = mix(shadow, 1., min((depthMetric - avgBlockerDepth) * depthCorrection * penumbraDarkness, 1.));
  556. // Apply darkness
  557. shadow = mix(darkness, 1., shadow);
  558. // Apply light frustrum fallof
  559. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  560. }
  561. }
  562. // PCSS
  563. // This helps to achieve a contact hardening effect on the shadow
  564. // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
  565. // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
  566. // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
  567. #define inline
  568. 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)
  569. {
  570. if (depthMetric > 1.0 || depthMetric < 0.0) {
  571. return 1.0;
  572. }
  573. else
  574. {
  575. vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
  576. vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
  577. float blockerDepth = 0.0;
  578. float sumBlockerDepth = 0.0;
  579. float numBlocker = 0.0;
  580. for (int i = 0; i < searchTapCount; i ++) {
  581. blockerDepth = texture(depthSampler, uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PoissonSamplers32[i].xy)).r;
  582. if (blockerDepth < depthMetric) {
  583. sumBlockerDepth += blockerDepth;
  584. numBlocker++;
  585. }
  586. }
  587. if (numBlocker < 1.0) {
  588. return 1.0;
  589. }
  590. else
  591. {
  592. float avgBlockerDepth = sumBlockerDepth / numBlocker;
  593. // Offset preventing aliasing on contact.
  594. float AAOffset = shadowMapSizeInverse * 10.;
  595. // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
  596. // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
  597. float penumbraRatio = ((depthMetric - avgBlockerDepth) + AAOffset);
  598. float filterRadius = penumbraRatio * lightSizeUV * shadowMapSizeInverse;
  599. float random = getRand(vPositionFromLight.xy);
  600. float rotationAngle = random * 3.1415926;
  601. vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
  602. float shadow = 0.;
  603. for (int i = 0; i < pcfTapCount; i++) {
  604. vec3 offset = poissonSamplers[i];
  605. // Rotated offset.
  606. offset = vec3(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0.);
  607. shadow += texture2D(shadowSampler, uvDepth + offset * filterRadius);
  608. }
  609. shadow /= float(pcfTapCount);
  610. // Blocker distance falloff
  611. shadow = mix(shadow, 1., depthMetric - avgBlockerDepth);
  612. // Apply darkness
  613. shadow = mix(darkness, 1., shadow);
  614. // Apply light frustrum fallof
  615. return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
  616. }
  617. }
  618. }
  619. #define inline
  620. float computeShadowWithPCSS16(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
  621. {
  622. return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32);
  623. }
  624. #define inline
  625. float computeShadowWithPCSS32(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
  626. {
  627. return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32);
  628. }
  629. #define inline
  630. float computeShadowWithPCSS64(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
  631. {
  632. return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
  633. }
  634. #define inline
  635. float computeShadowWithCSMPCSS16(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
  636. {
  637. return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32, lightSizeUVCorrection, depthCorrection, penumbraDarkness);
  638. }
  639. #define inline
  640. float computeShadowWithCSMPCSS32(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
  641. {
  642. return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32, lightSizeUVCorrection, depthCorrection, penumbraDarkness);
  643. }
  644. #define inline
  645. float computeShadowWithCSMPCSS64(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
  646. {
  647. return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64, lightSizeUVCorrection, depthCorrection, penumbraDarkness);
  648. }
  649. #endif
  650. #endif