opengl_fragment.glsl 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. uniform sampler2D baseTexture;
  2. uniform vec4 emissiveColor;
  3. uniform vec3 dayLight;
  4. uniform vec4 skyBgColor;
  5. uniform float fogDistance;
  6. uniform vec3 eyePosition;
  7. // The cameraOffset is the current center of the visible world.
  8. uniform vec3 cameraOffset;
  9. uniform float animationTimer;
  10. #ifdef ENABLE_DYNAMIC_SHADOWS
  11. // shadow texture
  12. uniform sampler2D ShadowMapSampler;
  13. // shadow uniforms
  14. uniform vec3 v_LightDirection;
  15. uniform float f_textureresolution;
  16. uniform mat4 m_ShadowViewProj;
  17. uniform float f_shadowfar;
  18. uniform float f_shadow_strength;
  19. uniform vec4 CameraPos;
  20. varying float normalOffsetScale;
  21. varying float adj_shadow_strength;
  22. varying float cosLight;
  23. varying float f_normal_length;
  24. #endif
  25. varying vec3 vNormal;
  26. varying vec3 vPosition;
  27. // World position in the visible world (i.e. relative to the cameraOffset.)
  28. // This can be used for many shader effects without loss of precision.
  29. // If the absolute position is required it can be calculated with
  30. // cameraOffset + worldPosition (for large coordinates the limits of float
  31. // precision must be considered).
  32. varying vec3 worldPosition;
  33. varying lowp vec4 varColor;
  34. #ifdef GL_ES
  35. varying mediump vec2 varTexCoord;
  36. #else
  37. centroid varying vec2 varTexCoord;
  38. #endif
  39. varying vec3 eyeVec;
  40. varying float nightRatio;
  41. varying float vIDiff;
  42. const float fogStart = FOG_START;
  43. const float fogShadingParameter = 1.0 / (1.0 - fogStart);
  44. #ifdef ENABLE_DYNAMIC_SHADOWS
  45. uniform float xyPerspectiveBias0;
  46. uniform float xyPerspectiveBias1;
  47. uniform float zPerspectiveBias;
  48. vec4 getPerspectiveFactor(in vec4 shadowPosition)
  49. {
  50. vec2 s = vec2(shadowPosition.x > CameraPos.x ? 1.0 : -1.0, shadowPosition.y > CameraPos.y ? 1.0 : -1.0);
  51. vec2 l = s * (shadowPosition.xy - CameraPos.xy) / (1.0 - s * CameraPos.xy);
  52. float pDistance = length(l);
  53. float pFactor = pDistance * xyPerspectiveBias0 + xyPerspectiveBias1;
  54. l /= pFactor;
  55. shadowPosition.xy = CameraPos.xy * (1.0 - l) + s * l;
  56. shadowPosition.z *= zPerspectiveBias;
  57. return shadowPosition;
  58. }
  59. // assuming near is always 1.0
  60. float getLinearDepth()
  61. {
  62. return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
  63. }
  64. vec3 getLightSpacePosition()
  65. {
  66. vec4 pLightSpace;
  67. // some drawtypes have zero normals, so we need to handle it :(
  68. #if DRAW_TYPE == NDT_PLANTLIKE
  69. pLightSpace = m_ShadowViewProj * vec4(worldPosition, 1.0);
  70. #else
  71. pLightSpace = m_ShadowViewProj * vec4(worldPosition + normalOffsetScale * normalize(vNormal), 1.0);
  72. #endif
  73. pLightSpace = getPerspectiveFactor(pLightSpace);
  74. return pLightSpace.xyz * 0.5 + 0.5;
  75. }
  76. // custom smoothstep implementation because it's not defined in glsl1.2
  77. // https://docs.gl/sl4/smoothstep
  78. float mtsmoothstep(in float edge0, in float edge1, in float x)
  79. {
  80. float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
  81. return t * t * (3.0 - 2.0 * t);
  82. }
  83. #ifdef COLORED_SHADOWS
  84. // c_precision of 128 fits within 7 base-10 digits
  85. const float c_precision = 128.0;
  86. const float c_precisionp1 = c_precision + 1.0;
  87. float packColor(vec3 color)
  88. {
  89. return floor(color.b * c_precision + 0.5)
  90. + floor(color.g * c_precision + 0.5) * c_precisionp1
  91. + floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
  92. }
  93. vec3 unpackColor(float value)
  94. {
  95. vec3 color;
  96. color.b = mod(value, c_precisionp1) / c_precision;
  97. color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
  98. color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
  99. return color;
  100. }
  101. vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  102. {
  103. vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
  104. float visibility = step(0.0, realDistance - texDepth.r);
  105. vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
  106. if (visibility < 0.1) {
  107. visibility = step(0.0, realDistance - texDepth.b);
  108. result = vec4(visibility, unpackColor(texDepth.a));
  109. }
  110. return result;
  111. }
  112. #else
  113. float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  114. {
  115. float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
  116. float visibility = step(0.0, realDistance - texDepth);
  117. return visibility;
  118. }
  119. #endif
  120. #if SHADOW_FILTER == 2
  121. #define PCFBOUND 3.5
  122. #define PCFSAMPLES 64.0
  123. #elif SHADOW_FILTER == 1
  124. #define PCFBOUND 1.5
  125. #if defined(POISSON_FILTER)
  126. #define PCFSAMPLES 32.0
  127. #else
  128. #define PCFSAMPLES 16.0
  129. #endif
  130. #else
  131. #define PCFBOUND 0.0
  132. #if defined(POISSON_FILTER)
  133. #define PCFSAMPLES 4.0
  134. #else
  135. #define PCFSAMPLES 1.0
  136. #endif
  137. #endif
  138. #ifdef COLORED_SHADOWS
  139. float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  140. {
  141. vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
  142. float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
  143. return depth;
  144. }
  145. #else
  146. float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  147. {
  148. float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
  149. float depth = realDistance - texDepth;
  150. return depth;
  151. }
  152. #endif
  153. float getBaseLength(vec2 smTexCoord)
  154. {
  155. float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords
  156. return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords
  157. }
  158. float getDeltaPerspectiveFactor(float l)
  159. {
  160. return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
  161. }
  162. float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
  163. {
  164. float baseLength = getBaseLength(smTexCoord);
  165. float perspectiveFactor;
  166. // Return fast if sharp shadows are requested
  167. if (PCFBOUND == 0.0)
  168. return 0.0;
  169. if (SOFTSHADOWRADIUS <= 1.0) {
  170. perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
  171. return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
  172. }
  173. vec2 clampedpos;
  174. float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
  175. float y, x;
  176. float depth = 0.0;
  177. float pointDepth;
  178. float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
  179. float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND);
  180. int n = 0;
  181. for (y = -bound; y <= bound; y += 1.0)
  182. for (x = -bound; x <= bound; x += 1.0) {
  183. clampedpos = vec2(x,y);
  184. perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius);
  185. clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy;
  186. pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance);
  187. if (pointDepth > -0.01) {
  188. depth += pointDepth;
  189. n += 1;
  190. }
  191. }
  192. depth = depth / n;
  193. depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
  194. perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
  195. return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
  196. }
  197. #ifdef POISSON_FILTER
  198. const vec2[64] poissonDisk = vec2[64](
  199. vec2(0.170019, -0.040254),
  200. vec2(-0.299417, 0.791925),
  201. vec2(0.645680, 0.493210),
  202. vec2(-0.651784, 0.717887),
  203. vec2(0.421003, 0.027070),
  204. vec2(-0.817194, -0.271096),
  205. vec2(-0.705374, -0.668203),
  206. vec2(0.977050, -0.108615),
  207. vec2(0.063326, 0.142369),
  208. vec2(0.203528, 0.214331),
  209. vec2(-0.667531, 0.326090),
  210. vec2(-0.098422, -0.295755),
  211. vec2(-0.885922, 0.215369),
  212. vec2(0.566637, 0.605213),
  213. vec2(0.039766, -0.396100),
  214. vec2(0.751946, 0.453352),
  215. vec2(0.078707, -0.715323),
  216. vec2(-0.075838, -0.529344),
  217. vec2(0.724479, -0.580798),
  218. vec2(0.222999, -0.215125),
  219. vec2(-0.467574, -0.405438),
  220. vec2(-0.248268, -0.814753),
  221. vec2(0.354411, -0.887570),
  222. vec2(0.175817, 0.382366),
  223. vec2(0.487472, -0.063082),
  224. vec2(0.355476, 0.025357),
  225. vec2(-0.084078, 0.898312),
  226. vec2(0.488876, -0.783441),
  227. vec2(0.470016, 0.217933),
  228. vec2(-0.696890, -0.549791),
  229. vec2(-0.149693, 0.605762),
  230. vec2(0.034211, 0.979980),
  231. vec2(0.503098, -0.308878),
  232. vec2(-0.016205, -0.872921),
  233. vec2(0.385784, -0.393902),
  234. vec2(-0.146886, -0.859249),
  235. vec2(0.643361, 0.164098),
  236. vec2(0.634388, -0.049471),
  237. vec2(-0.688894, 0.007843),
  238. vec2(0.464034, -0.188818),
  239. vec2(-0.440840, 0.137486),
  240. vec2(0.364483, 0.511704),
  241. vec2(0.034028, 0.325968),
  242. vec2(0.099094, -0.308023),
  243. vec2(0.693960, -0.366253),
  244. vec2(0.678884, -0.204688),
  245. vec2(0.001801, 0.780328),
  246. vec2(0.145177, -0.898984),
  247. vec2(0.062655, -0.611866),
  248. vec2(0.315226, -0.604297),
  249. vec2(-0.780145, 0.486251),
  250. vec2(-0.371868, 0.882138),
  251. vec2(0.200476, 0.494430),
  252. vec2(-0.494552, -0.711051),
  253. vec2(0.612476, 0.705252),
  254. vec2(-0.578845, -0.768792),
  255. vec2(-0.772454, -0.090976),
  256. vec2(0.504440, 0.372295),
  257. vec2(0.155736, 0.065157),
  258. vec2(0.391522, 0.849605),
  259. vec2(-0.620106, -0.328104),
  260. vec2(0.789239, -0.419965),
  261. vec2(-0.545396, 0.538133),
  262. vec2(-0.178564, -0.596057)
  263. );
  264. #ifdef COLORED_SHADOWS
  265. vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  266. {
  267. vec2 clampedpos;
  268. vec4 visibility = vec4(0.0);
  269. float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
  270. if (radius < 0.1) {
  271. // we are in the middle of even brightness, no need for filtering
  272. return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
  273. }
  274. float baseLength = getBaseLength(smTexCoord);
  275. float perspectiveFactor;
  276. float texture_size = 1.0 / (f_textureresolution * 0.5);
  277. int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
  278. int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
  279. int end_offset = int(samples) + init_offset;
  280. for (int x = init_offset; x < end_offset; x++) {
  281. clampedpos = poissonDisk[x];
  282. perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
  283. clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
  284. visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
  285. }
  286. return visibility / samples;
  287. }
  288. #else
  289. float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  290. {
  291. vec2 clampedpos;
  292. float visibility = 0.0;
  293. float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
  294. if (radius < 0.1) {
  295. // we are in the middle of even brightness, no need for filtering
  296. return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
  297. }
  298. float baseLength = getBaseLength(smTexCoord);
  299. float perspectiveFactor;
  300. float texture_size = 1.0 / (f_textureresolution * 0.5);
  301. int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
  302. int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
  303. int end_offset = int(samples) + init_offset;
  304. for (int x = init_offset; x < end_offset; x++) {
  305. clampedpos = poissonDisk[x];
  306. perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
  307. clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
  308. visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
  309. }
  310. return visibility / samples;
  311. }
  312. #endif
  313. #else
  314. /* poisson filter disabled */
  315. #ifdef COLORED_SHADOWS
  316. vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  317. {
  318. vec2 clampedpos;
  319. vec4 visibility = vec4(0.0);
  320. float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
  321. if (radius < 0.1) {
  322. // we are in the middle of even brightness, no need for filtering
  323. return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
  324. }
  325. float baseLength = getBaseLength(smTexCoord);
  326. float perspectiveFactor;
  327. float texture_size = 1.0 / (f_textureresolution * 0.5);
  328. float y, x;
  329. float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
  330. int n = 0;
  331. // basic PCF filter
  332. for (y = -bound; y <= bound; y += 1.0)
  333. for (x = -bound; x <= bound; x += 1.0) {
  334. clampedpos = vec2(x,y); // screen offset
  335. perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
  336. clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
  337. visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
  338. n += 1;
  339. }
  340. return visibility / n;
  341. }
  342. #else
  343. float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
  344. {
  345. vec2 clampedpos;
  346. float visibility = 0.0;
  347. float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
  348. if (radius < 0.1) {
  349. // we are in the middle of even brightness, no need for filtering
  350. return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
  351. }
  352. float baseLength = getBaseLength(smTexCoord);
  353. float perspectiveFactor;
  354. float texture_size = 1.0 / (f_textureresolution * 0.5);
  355. float y, x;
  356. float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
  357. int n = 0;
  358. // basic PCF filter
  359. for (y = -bound; y <= bound; y += 1.0)
  360. for (x = -bound; x <= bound; x += 1.0) {
  361. clampedpos = vec2(x,y); // screen offset
  362. perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
  363. clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
  364. visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
  365. n += 1;
  366. }
  367. return visibility / n;
  368. }
  369. #endif
  370. #endif
  371. #endif
  372. #if ENABLE_TONE_MAPPING
  373. /* Hable's UC2 Tone mapping parameters
  374. A = 0.22;
  375. B = 0.30;
  376. C = 0.10;
  377. D = 0.20;
  378. E = 0.01;
  379. F = 0.30;
  380. W = 11.2;
  381. equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
  382. */
  383. vec3 uncharted2Tonemap(vec3 x)
  384. {
  385. return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
  386. }
  387. vec4 applyToneMapping(vec4 color)
  388. {
  389. color = vec4(pow(color.rgb, vec3(2.2)), color.a);
  390. const float gamma = 1.6;
  391. const float exposureBias = 5.5;
  392. color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
  393. // Precalculated white_scale from
  394. //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
  395. vec3 whiteScale = vec3(1.036015346);
  396. color.rgb *= whiteScale;
  397. return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
  398. }
  399. #endif
  400. void main(void)
  401. {
  402. vec3 color;
  403. vec2 uv = varTexCoord.st;
  404. vec4 base = texture2D(baseTexture, uv).rgba;
  405. // If alpha is zero, we can just discard the pixel. This fixes transparency
  406. // on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
  407. // and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
  408. #ifdef USE_DISCARD
  409. if (base.a == 0.0)
  410. discard;
  411. #endif
  412. #ifdef USE_DISCARD_REF
  413. if (base.a < 0.5)
  414. discard;
  415. #endif
  416. color = base.rgb;
  417. vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
  418. col.rgb *= vIDiff;
  419. #ifdef ENABLE_DYNAMIC_SHADOWS
  420. if (f_shadow_strength > 0.0) {
  421. float shadow_int = 0.0;
  422. vec3 shadow_color = vec3(0.0, 0.0, 0.0);
  423. vec3 posLightSpace = getLightSpacePosition();
  424. float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
  425. if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
  426. distance_rate = 0.0;
  427. float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);
  428. if (distance_rate > 1e-7) {
  429. #ifdef COLORED_SHADOWS
  430. vec4 visibility;
  431. if (cosLight > 0.0)
  432. visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
  433. else
  434. visibility = vec4(1.0, 0.0, 0.0, 0.0);
  435. shadow_int = visibility.r;
  436. shadow_color = visibility.gba;
  437. #else
  438. if (cosLight > 0.0)
  439. shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
  440. else
  441. shadow_int = 1.0;
  442. #endif
  443. shadow_int *= distance_rate;
  444. shadow_int = clamp(shadow_int, 0.0, 1.0);
  445. }
  446. // turns out that nightRatio falls off much faster than
  447. // actual brightness of artificial light in relation to natual light.
  448. // Power ratio was measured on torches in MTG (brightness = 14).
  449. float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);
  450. // Apply self-shadowing when light falls at a narrow angle to the surface
  451. // Cosine of the cut-off angle.
  452. const float self_shadow_cutoff_cosine = 0.14;
  453. if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
  454. shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
  455. shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
  456. }
  457. shadow_int *= f_adj_shadow_strength;
  458. // calculate fragment color from components:
  459. col.rgb =
  460. adjusted_night_ratio * col.rgb + // artificial light
  461. (1.0 - adjusted_night_ratio) * ( // natural light
  462. col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
  463. dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
  464. }
  465. #endif
  466. #if ENABLE_TONE_MAPPING
  467. col = applyToneMapping(col);
  468. #endif
  469. // Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
  470. // the fog will only be rendered correctly if the last operation before the
  471. // clamp() is an addition. Else, the clamp() seems to be ignored.
  472. // E.g. the following won't work:
  473. // float clarity = clamp(fogShadingParameter
  474. // * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
  475. // As additions usually come for free following a multiplication, the new formula
  476. // should be more efficient as well.
  477. // Note: clarity = (1 - fogginess)
  478. float clarity = clamp(fogShadingParameter
  479. - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
  480. col = mix(skyBgColor, col, clarity);
  481. col = vec4(col.rgb, base.a);
  482. gl_FragColor = col;
  483. }