SkyAtmosphereCommon.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /**
  2. * @license
  3. * Copyright (c) 2000-2005, Sean O'Neil (s_p_oneil@hotmail.com)
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * * Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. * * Neither the name of the project nor the names of its contributors may be
  16. * used to endorse or promote products derived from this software without
  17. * specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  25. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  26. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * Modifications made by Cesium GS, Inc.
  31. */
  32. //This file is automatically rebuilt by the Cesium build process.
  33. export default "/**\n\
  34. * @license\n\
  35. * Copyright (c) 2000-2005, Sean O'Neil (s_p_oneil@hotmail.com)\n\
  36. * All rights reserved.\n\
  37. *\n\
  38. * Redistribution and use in source and binary forms, with or without\n\
  39. * modification, are permitted provided that the following conditions\n\
  40. * are met:\n\
  41. *\n\
  42. * * Redistributions of source code must retain the above copyright notice,\n\
  43. * this list of conditions and the following disclaimer.\n\
  44. * * Redistributions in binary form must reproduce the above copyright notice,\n\
  45. * this list of conditions and the following disclaimer in the documentation\n\
  46. * and/or other materials provided with the distribution.\n\
  47. * * Neither the name of the project nor the names of its contributors may be\n\
  48. * used to endorse or promote products derived from this software without\n\
  49. * specific prior written permission.\n\
  50. *\n\
  51. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n\
  52. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\
  53. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n\
  54. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\n\
  55. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\
  56. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n\
  57. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n\
  58. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n\
  59. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\
  60. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
  61. *\n\
  62. * Modifications made by Cesium GS, Inc.\n\
  63. */\n\
  64. \n\
  65. // Code: http://sponeil.net/\n\
  66. // GPU Gems 2 Article: https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter16.html\n\
  67. \n\
  68. const float Kr = 0.0025;\n\
  69. const float Kr4PI = Kr * 4.0 * czm_pi;\n\
  70. const float Km = 0.0015;\n\
  71. const float Km4PI = Km * 4.0 * czm_pi;\n\
  72. const float ESun = 15.0;\n\
  73. const float KmESun = Km * ESun;\n\
  74. const float KrESun = Kr * ESun;\n\
  75. const vec3 InvWavelength = vec3(\n\
  76. 5.60204474633241, // Red = 1.0 / Math.pow(0.650, 4.0)\n\
  77. 9.473284437923038, // Green = 1.0 / Math.pow(0.570, 4.0)\n\
  78. 19.643802610477206); // Blue = 1.0 / Math.pow(0.475, 4.0)\n\
  79. const float rayleighScaleDepth = 0.25;\n\
  80. \n\
  81. const int nSamples = 2;\n\
  82. const float fSamples = 2.0;\n\
  83. \n\
  84. const float g = -0.95;\n\
  85. const float g2 = g * g;\n\
  86. \n\
  87. #ifdef COLOR_CORRECT\n\
  88. uniform vec3 u_hsbShift; // Hue, saturation, brightness\n\
  89. #endif\n\
  90. \n\
  91. uniform vec3 u_radiiAndDynamicAtmosphereColor; // outer radius, inner radius, dynamic atmosphere color flag\n\
  92. \n\
  93. float scale(float cosAngle)\n\
  94. {\n\
  95. float x = 1.0 - cosAngle;\n\
  96. return rayleighScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n\
  97. }\n\
  98. \n\
  99. vec3 getLightDirection(vec3 positionWC)\n\
  100. {\n\
  101. float lightEnum = u_radiiAndDynamicAtmosphereColor.z;\n\
  102. vec3 lightDirection =\n\
  103. positionWC * float(lightEnum == 0.0) +\n\
  104. czm_lightDirectionWC * float(lightEnum == 1.0) +\n\
  105. czm_sunDirectionWC * float(lightEnum == 2.0);\n\
  106. return normalize(lightDirection);\n\
  107. }\n\
  108. \n\
  109. void calculateRayScatteringFromSpace(in vec3 positionWC, in vec3 ray, in float innerRadius, in float outerRadius, inout float far, out vec3 start, out float startOffset)\n\
  110. {\n\
  111. // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)\n\
  112. float cameraHeight = length(positionWC);\n\
  113. float B = 2.0 * dot(positionWC, ray);\n\
  114. float C = cameraHeight * cameraHeight - outerRadius * outerRadius;\n\
  115. float det = max(0.0, B * B - 4.0 * C);\n\
  116. float near = 0.5 * (-B - sqrt(det));\n\
  117. \n\
  118. // Calculate the ray's starting position, then calculate its scattering offset\n\
  119. start = positionWC + ray * near;\n\
  120. far -= near;\n\
  121. float startAngle = dot(ray, start) / outerRadius;\n\
  122. float startDepth = exp(-1.0 / rayleighScaleDepth);\n\
  123. startOffset = startDepth * scale(startAngle);\n\
  124. }\n\
  125. \n\
  126. void calculateRayScatteringFromGround(in vec3 positionWC, in vec3 ray, in float atmosphereScale, in float innerRadius, out vec3 start, out float startOffset)\n\
  127. {\n\
  128. // Calculate the ray's starting position, then calculate its scattering offset\n\
  129. float cameraHeight = length(positionWC);\n\
  130. start = positionWC;\n\
  131. float height = length(start);\n\
  132. float depth = exp((atmosphereScale / rayleighScaleDepth ) * (innerRadius - cameraHeight));\n\
  133. float startAngle = dot(ray, start) / height;\n\
  134. startOffset = depth*scale(startAngle);\n\
  135. }\n\
  136. \n\
  137. czm_raySegment rayEllipsoidIntersection(czm_ray ray, vec3 inverseRadii)\n\
  138. {\n\
  139. vec3 o = inverseRadii * (czm_inverseView * vec4(ray.origin, 1.0)).xyz;\n\
  140. vec3 d = inverseRadii * (czm_inverseView * vec4(ray.direction, 0.0)).xyz;\n\
  141. \n\
  142. float a = dot(d, d);\n\
  143. float b = dot(d, o);\n\
  144. float c = dot(o, o) - 1.0;\n\
  145. float discriminant = b * b - a * c;\n\
  146. if (discriminant < 0.0)\n\
  147. {\n\
  148. return czm_emptyRaySegment;\n\
  149. }\n\
  150. discriminant = sqrt(discriminant);\n\
  151. float t1 = (-b - discriminant) / a;\n\
  152. float t2 = (-b + discriminant) / a;\n\
  153. \n\
  154. if (t1 < 0.0 && t2 < 0.0)\n\
  155. {\n\
  156. return czm_emptyRaySegment;\n\
  157. }\n\
  158. \n\
  159. if (t1 < 0.0 && t2 >= 0.0)\n\
  160. {\n\
  161. t1 = 0.0;\n\
  162. }\n\
  163. \n\
  164. return czm_raySegment(t1, t2);\n\
  165. }\n\
  166. \n\
  167. vec3 getAdjustedPosition(vec3 positionWC, float innerRadius)\n\
  168. {\n\
  169. // Adjust the camera position so that atmosphere color looks the same wherever the eye height is the same\n\
  170. float cameraHeight = czm_eyeHeight + innerRadius;\n\
  171. return normalize(positionWC) * cameraHeight;\n\
  172. }\n\
  173. \n\
  174. vec3 getTranslucentPosition(vec3 positionWC, vec3 outerPositionWC, float innerRadius, out bool intersectsEllipsoid)\n\
  175. {\n\
  176. vec3 directionWC = normalize(outerPositionWC - positionWC);\n\
  177. vec3 directionEC = czm_viewRotation * directionWC;\n\
  178. czm_ray viewRay = czm_ray(vec3(0.0), directionEC);\n\
  179. czm_raySegment raySegment = rayEllipsoidIntersection(viewRay, czm_ellipsoidInverseRadii);\n\
  180. intersectsEllipsoid = raySegment.start >= 0.0;\n\
  181. \n\
  182. if (intersectsEllipsoid)\n\
  183. {\n\
  184. return positionWC + raySegment.stop * directionWC;\n\
  185. }\n\
  186. \n\
  187. return getAdjustedPosition(positionWC, innerRadius);\n\
  188. }\n\
  189. \n\
  190. void calculateMieColorAndRayleighColor(vec3 outerPositionWC, out vec3 mieColor, out vec3 rayleighColor)\n\
  191. {\n\
  192. // Unpack attributes\n\
  193. float outerRadius = u_radiiAndDynamicAtmosphereColor.x;\n\
  194. float innerRadius = u_radiiAndDynamicAtmosphereColor.y;\n\
  195. \n\
  196. #ifdef GLOBE_TRANSLUCENT\n\
  197. bool intersectsEllipsoid = false;\n\
  198. vec3 startPositionWC = getTranslucentPosition(czm_viewerPositionWC, outerPositionWC, innerRadius, intersectsEllipsoid);\n\
  199. #else\n\
  200. vec3 startPositionWC = getAdjustedPosition(czm_viewerPositionWC, innerRadius);\n\
  201. #endif\n\
  202. \n\
  203. vec3 lightDirection = getLightDirection(startPositionWC);\n\
  204. \n\
  205. // Get the ray from the start position to the outer position and its length (which is the far point of the ray passing through the atmosphere)\n\
  206. vec3 ray = outerPositionWC - startPositionWC;\n\
  207. float far = length(ray);\n\
  208. ray /= far;\n\
  209. \n\
  210. float atmosphereScale = 1.0 / (outerRadius - innerRadius);\n\
  211. \n\
  212. vec3 start;\n\
  213. float startOffset;\n\
  214. \n\
  215. #ifdef SKY_FROM_SPACE\n\
  216. #ifdef GLOBE_TRANSLUCENT\n\
  217. if (intersectsEllipsoid)\n\
  218. {\n\
  219. calculateRayScatteringFromGround(startPositionWC, ray, atmosphereScale, innerRadius, start, startOffset);\n\
  220. }\n\
  221. else\n\
  222. {\n\
  223. calculateRayScatteringFromSpace(startPositionWC, ray, innerRadius, outerRadius, far, start, startOffset);\n\
  224. }\n\
  225. #else\n\
  226. calculateRayScatteringFromSpace(startPositionWC, ray, innerRadius, outerRadius, far, start, startOffset);\n\
  227. #endif\n\
  228. #else\n\
  229. calculateRayScatteringFromGround(startPositionWC, ray, atmosphereScale, innerRadius, start, startOffset);\n\
  230. #endif\n\
  231. \n\
  232. // Initialize the scattering loop variables\n\
  233. float sampleLength = far / fSamples;\n\
  234. float scaledLength = sampleLength * atmosphereScale;\n\
  235. vec3 sampleRay = ray * sampleLength;\n\
  236. vec3 samplePoint = start + sampleRay * 0.5;\n\
  237. \n\
  238. // Now loop through the sample rays\n\
  239. vec3 frontColor = vec3(0.0, 0.0, 0.0);\n\
  240. \n\
  241. for (int i = 0; i<nSamples; i++)\n\
  242. {\n\
  243. float height = length(samplePoint);\n\
  244. float depth = exp((atmosphereScale / rayleighScaleDepth ) * (innerRadius - height));\n\
  245. float fLightAngle = dot(lightDirection, samplePoint) / height;\n\
  246. float fCameraAngle = dot(ray, samplePoint) / height;\n\
  247. float fScatter = (startOffset + depth*(scale(fLightAngle) - scale(fCameraAngle)));\n\
  248. vec3 attenuate = exp(-fScatter * (InvWavelength * Kr4PI + Km4PI));\n\
  249. frontColor += attenuate * (depth * scaledLength);\n\
  250. samplePoint += sampleRay;\n\
  251. }\n\
  252. \n\
  253. // Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader\n\
  254. mieColor = frontColor * KmESun;\n\
  255. rayleighColor = frontColor * (InvWavelength * KrESun);\n\
  256. \n\
  257. // Cap mie and rayleigh colors to prevent NaNs when vertex interpolation happens\n\
  258. mieColor = min(mieColor, vec3(10000000.0));\n\
  259. rayleighColor = min(rayleighColor, vec3(10000000.0));\n\
  260. }\n\
  261. \n\
  262. vec4 calculateFinalColor(vec3 positionWC, vec3 toCamera, vec3 lightDirection, vec3 mieColor, vec3 rayleighColor)\n\
  263. {\n\
  264. // Extra normalize added for Android\n\
  265. float cosAngle = dot(lightDirection, normalize(toCamera)) / length(toCamera);\n\
  266. float rayleighPhase = 0.75 * (1.0 + cosAngle * cosAngle);\n\
  267. float miePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + cosAngle * cosAngle) / pow(1.0 + g2 - 2.0 * g * cosAngle, 1.5);\n\
  268. \n\
  269. vec3 rgb = rayleighPhase * rayleighColor + miePhase * mieColor;\n\
  270. \n\
  271. const float exposure = 2.0;\n\
  272. vec3 rgbExposure = vec3(1.0) - exp(-exposure * rgb);\n\
  273. \n\
  274. #ifndef HDR\n\
  275. rgb = rgbExposure;\n\
  276. #endif\n\
  277. \n\
  278. #ifdef COLOR_CORRECT\n\
  279. // Convert rgb color to hsb\n\
  280. vec3 hsb = czm_RGBToHSB(rgb);\n\
  281. // Perform hsb shift\n\
  282. hsb.x += u_hsbShift.x; // hue\n\
  283. hsb.y = clamp(hsb.y + u_hsbShift.y, 0.0, 1.0); // saturation\n\
  284. hsb.z = hsb.z > czm_epsilon7 ? hsb.z + u_hsbShift.z : 0.0; // brightness\n\
  285. // Convert shifted hsb back to rgb\n\
  286. rgb = czm_HSBToRGB(hsb);\n\
  287. #endif\n\
  288. \n\
  289. float outerRadius = u_radiiAndDynamicAtmosphereColor.x;\n\
  290. float innerRadius = u_radiiAndDynamicAtmosphereColor.y;\n\
  291. float lightEnum = u_radiiAndDynamicAtmosphereColor.z;\n\
  292. \n\
  293. float cameraHeight = czm_eyeHeight + innerRadius;\n\
  294. \n\
  295. // Alter alpha based on how close the viewer is to the ground (1.0 = on ground, 0.0 = at edge of atmosphere)\n\
  296. float atmosphereAlpha = clamp((outerRadius - cameraHeight) / (outerRadius - innerRadius), 0.0, 1.0);\n\
  297. \n\
  298. // Alter alpha based on time of day (0.0 = night , 1.0 = day)\n\
  299. float nightAlpha = (lightEnum != 0.0) ? clamp(dot(normalize(positionWC), lightDirection), 0.0, 1.0) : 1.0;\n\
  300. atmosphereAlpha *= pow(nightAlpha, 0.5);\n\
  301. \n\
  302. vec4 finalColor = vec4(rgb, mix(clamp(rgbExposure.b, 0.0, 1.0), 1.0, atmosphereAlpha) * smoothstep(0.0, 1.0, czm_morphTime));\n\
  303. \n\
  304. if (mieColor.b > 1.0)\n\
  305. {\n\
  306. // Fade atmosphere below the ellipsoid. As the camera zooms further away from the ellipsoid draw\n\
  307. // a larger atmosphere ring to cover empty space of lower LOD globe tiles.\n\
  308. float strength = mieColor.b;\n\
  309. float minDistance = outerRadius;\n\
  310. float maxDistance = outerRadius * 3.0;\n\
  311. float maxStrengthLerp = 1.0 - clamp((maxDistance - cameraHeight) / (maxDistance - minDistance), 0.0, 1.0);\n\
  312. float maxStrength = mix(100.0, 10000.0, maxStrengthLerp);\n\
  313. strength = min(strength, maxStrength);\n\
  314. float alpha = 1.0 - (strength / maxStrength);\n\
  315. finalColor.a = alpha;\n\
  316. }\n\
  317. \n\
  318. return finalColor;\n\
  319. }\n\
  320. ";