Fog.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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.03
  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 = [
  48. 359.393,
  49. 800.749,
  50. 1275.6501,
  51. 2151.1192,
  52. 3141.7763,
  53. 4777.5198,
  54. 6281.2493,
  55. 12364.307,
  56. 15900.765,
  57. 49889.0549,
  58. 78026.8259,
  59. 99260.7344,
  60. 120036.3873,
  61. 151011.0158,
  62. 156091.1953,
  63. 203849.3112,
  64. 274866.9803,
  65. 319916.3149,
  66. 493552.0528,
  67. 628733.5874,
  68. ];
  69. var densityTable = [
  70. 2.0e-5,
  71. 2.0e-4,
  72. 1.0e-4,
  73. 7.0e-5,
  74. 5.0e-5,
  75. 4.0e-5,
  76. 3.0e-5,
  77. 1.9e-5,
  78. 1.0e-5,
  79. 8.5e-6,
  80. 6.2e-6,
  81. 5.8e-6,
  82. 5.3e-6,
  83. 5.2e-6,
  84. 5.1e-6,
  85. 4.2e-6,
  86. 4.0e-6,
  87. 3.4e-6,
  88. 2.6e-6,
  89. 2.2e-6,
  90. ];
  91. // Scale densities by 1e6 to bring lowest value to ~1. Prevents divide by zero.
  92. for (var i = 0; i < densityTable.length; ++i) {
  93. densityTable[i] *= 1.0e6;
  94. }
  95. // Change range to [0, 1].
  96. var tableStartDensity = densityTable[1];
  97. var tableEndDensity = densityTable[densityTable.length - 1];
  98. for (var j = 0; j < densityTable.length; ++j) {
  99. densityTable[j] =
  100. (densityTable[j] - tableEndDensity) / (tableStartDensity - tableEndDensity);
  101. }
  102. var tableLastIndex = 0;
  103. function findInterval(height) {
  104. var heights = heightsTable;
  105. var length = heights.length;
  106. if (height < heights[0]) {
  107. tableLastIndex = 0;
  108. return tableLastIndex;
  109. } else if (height > heights[length - 1]) {
  110. tableLastIndex = length - 2;
  111. return tableLastIndex;
  112. }
  113. // Take advantage of temporal coherence by checking current, next and previous intervals
  114. // for containment of time.
  115. if (height >= heights[tableLastIndex]) {
  116. if (tableLastIndex + 1 < length && height < heights[tableLastIndex + 1]) {
  117. return tableLastIndex;
  118. } else if (
  119. tableLastIndex + 2 < length &&
  120. height < heights[tableLastIndex + 2]
  121. ) {
  122. ++tableLastIndex;
  123. return tableLastIndex;
  124. }
  125. } else if (tableLastIndex - 1 >= 0 && height >= heights[tableLastIndex - 1]) {
  126. --tableLastIndex;
  127. return tableLastIndex;
  128. }
  129. // The above failed so do a linear search.
  130. var i;
  131. for (i = 0; i < length - 2; ++i) {
  132. if (height >= heights[i] && height < heights[i + 1]) {
  133. break;
  134. }
  135. }
  136. tableLastIndex = i;
  137. return tableLastIndex;
  138. }
  139. var scratchPositionNormal = new Cartesian3();
  140. Fog.prototype.update = function (frameState) {
  141. var enabled = (frameState.fog.enabled = this.enabled);
  142. if (!enabled) {
  143. return;
  144. }
  145. var camera = frameState.camera;
  146. var positionCartographic = camera.positionCartographic;
  147. // Turn off fog in space.
  148. if (
  149. !defined(positionCartographic) ||
  150. positionCartographic.height > 800000.0 ||
  151. frameState.mode !== SceneMode.SCENE3D
  152. ) {
  153. frameState.fog.enabled = false;
  154. return;
  155. }
  156. var height = positionCartographic.height;
  157. var i = findInterval(height);
  158. var t = CesiumMath.clamp(
  159. (height - heightsTable[i]) / (heightsTable[i + 1] - heightsTable[i]),
  160. 0.0,
  161. 1.0
  162. );
  163. var density = CesiumMath.lerp(densityTable[i], densityTable[i + 1], t);
  164. // Again, scale value to be in the range of densityTable (prevents divide by zero) and change to new range.
  165. var startDensity = this.density * 1.0e6;
  166. var endDensity = (startDensity / tableStartDensity) * tableEndDensity;
  167. density = density * (startDensity - endDensity) * 1.0e-6;
  168. // Fade fog in as the camera tilts toward the horizon.
  169. var positionNormal = Cartesian3.normalize(
  170. camera.positionWC,
  171. scratchPositionNormal
  172. );
  173. var dot = Math.abs(Cartesian3.dot(camera.directionWC, positionNormal));
  174. density *= 1.0 - dot;
  175. frameState.fog.density = density;
  176. frameState.fog.sse = this.screenSpaceErrorFactor;
  177. frameState.fog.minimumBrightness = this.minimumBrightness;
  178. };
  179. export default Fog;