Fog.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import Cartesian3 from '../Core/Cartesian3.js';
  2. import defined from '../Core/defined.js';
  3. import CesiumMath from '../Core/Math.js';
  4. import SceneMode from './SceneMode.js';
  5. /**
  6. * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional
  7. * performance improvements by rendering less geometry and dispatching less terrain requests.
  8. *
  9. * @alias Fog
  10. * @constructor
  11. */
  12. function Fog() {
  13. /**
  14. * <code>true</code> if fog is enabled, <code>false</code> otherwise.
  15. * @type {Boolean}
  16. * @default true
  17. */
  18. this.enabled = true;
  19. /**
  20. * A scalar that determines the density of the fog. Terrain that is in full fog are culled.
  21. * The density of the fog increases as this number approaches 1.0 and becomes less dense as it approaches zero.
  22. * The more dense the fog is, the more aggressively the terrain is culled. For example, if the camera is a height of
  23. * 1000.0m above the ellipsoid, increasing the value to 3.0e-3 will cause many tiles close to the viewer be culled.
  24. * Decreasing the value will push the fog further from the viewer, but decrease performance as more of the terrain is rendered.
  25. * @type {Number}
  26. * @default 2.0e-4
  27. */
  28. this.density = 2.0e-4;
  29. /**
  30. * A factor used to increase the screen space error of terrain tiles when they are partially in fog. The effect is to reduce
  31. * the number of terrain tiles requested for rendering. If set to zero, the feature will be disabled. If the value is increased
  32. * for mountainous regions, less tiles will need to be requested, but the terrain meshes near the horizon may be a noticeably
  33. * lower resolution. If the value is increased in a relatively flat area, there will be little noticeable change on the horizon.
  34. * @type {Number}
  35. * @default 2.0
  36. */
  37. this.screenSpaceErrorFactor = 2.0;
  38. /**
  39. * The minimum brightness of the fog color from lighting. A value of 0.0 can cause the fog to be completely black. A value of 1.0 will not affect
  40. * the brightness at all.
  41. * @type {Number}
  42. * @default 0.1
  43. */
  44. this.minimumBrightness = 0.03;
  45. }
  46. // These values were found by sampling the density at certain views and finding at what point culled tiles impacted the view at the horizon.
  47. var heightsTable = [359.393, 800.749, 1275.6501, 2151.1192, 3141.7763, 4777.5198, 6281.2493, 12364.307, 15900.765, 49889.0549, 78026.8259, 99260.7344, 120036.3873, 151011.0158, 156091.1953, 203849.3112, 274866.9803, 319916.3149, 493552.0528, 628733.5874];
  48. var densityTable = [2.0e-5, 2.0e-4, 1.0e-4, 7.0e-5, 5.0e-5, 4.0e-5, 3.0e-5, 1.9e-5, 1.0e-5, 8.5e-6, 6.2e-6, 5.8e-6, 5.3e-6, 5.2e-6, 5.1e-6, 4.2e-6, 4.0e-6, 3.4e-6, 2.6e-6, 2.2e-6];
  49. // Scale densities by 1e6 to bring lowest value to ~1. Prevents divide by zero.
  50. for (var i = 0; i < densityTable.length; ++i) {
  51. densityTable[i] *= 1.0e6;
  52. }
  53. // Change range to [0, 1].
  54. var tableStartDensity = densityTable[1];
  55. var tableEndDensity = densityTable[densityTable.length - 1];
  56. for (var j = 0; j < densityTable.length; ++j) {
  57. densityTable[j] = (densityTable[j] - tableEndDensity) / (tableStartDensity - tableEndDensity);
  58. }
  59. var tableLastIndex = 0;
  60. function findInterval(height) {
  61. var heights = heightsTable;
  62. var length = heights.length;
  63. if (height < heights[0]) {
  64. tableLastIndex = 0;
  65. return tableLastIndex;
  66. } else if (height > heights[length - 1]) {
  67. tableLastIndex = length - 2;
  68. return tableLastIndex;
  69. }
  70. // Take advantage of temporal coherence by checking current, next and previous intervals
  71. // for containment of time.
  72. if (height >= heights[tableLastIndex]) {
  73. if (tableLastIndex + 1 < length && height < heights[tableLastIndex + 1]) {
  74. return tableLastIndex;
  75. } else if (tableLastIndex + 2 < length && height < heights[tableLastIndex + 2]) {
  76. ++tableLastIndex;
  77. return tableLastIndex;
  78. }
  79. } else if (tableLastIndex - 1 >= 0 && height >= heights[tableLastIndex - 1]) {
  80. --tableLastIndex;
  81. return tableLastIndex;
  82. }
  83. // The above failed so do a linear search.
  84. var i;
  85. for (i = 0; i < length - 2; ++i) {
  86. if (height >= heights[i] && height < heights[i + 1]) {
  87. break;
  88. }
  89. }
  90. tableLastIndex = i;
  91. return tableLastIndex;
  92. }
  93. var scratchPositionNormal = new Cartesian3();
  94. Fog.prototype.update = function(frameState) {
  95. var enabled = frameState.fog.enabled = this.enabled;
  96. if (!enabled) {
  97. return;
  98. }
  99. var camera = frameState.camera;
  100. var positionCartographic = camera.positionCartographic;
  101. // Turn off fog in space.
  102. if (!defined(positionCartographic) || positionCartographic.height > 800000.0 || frameState.mode !== SceneMode.SCENE3D) {
  103. frameState.fog.enabled = false;
  104. return;
  105. }
  106. var height = positionCartographic.height;
  107. var i = findInterval(height);
  108. var t = CesiumMath.clamp((height - heightsTable[i]) / (heightsTable[i + 1] - heightsTable[i]), 0.0, 1.0);
  109. var density = CesiumMath.lerp(densityTable[i], densityTable[i + 1], t);
  110. // Again, scale value to be in the range of densityTable (prevents divide by zero) and change to new range.
  111. var startDensity = this.density * 1.0e6;
  112. var endDensity = (startDensity / tableStartDensity) * tableEndDensity;
  113. density = (density * (startDensity - endDensity)) * 1.0e-6;
  114. // Fade fog in as the camera tilts toward the horizon.
  115. var positionNormal = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
  116. var dot = Math.abs(Cartesian3.dot(camera.directionWC, positionNormal));
  117. density *= 1.0 - dot;
  118. frameState.fog.density = density;
  119. frameState.fog.sse = this.screenSpaceErrorFactor;
  120. frameState.fog.minimumBrightness = this.minimumBrightness;
  121. };
  122. export default Fog;