GlobeFS.glsl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. uniform vec4 u_initialColor;
  2. #if TEXTURE_UNITS > 0
  3. uniform sampler2D u_dayTextures[TEXTURE_UNITS];
  4. uniform vec4 u_dayTextureTranslationAndScale[TEXTURE_UNITS];
  5. uniform bool u_dayTextureUseWebMercatorT[TEXTURE_UNITS];
  6. #ifdef APPLY_ALPHA
  7. uniform float u_dayTextureAlpha[TEXTURE_UNITS];
  8. #endif
  9. #ifdef APPLY_SPLIT
  10. uniform float u_dayTextureSplit[TEXTURE_UNITS];
  11. #endif
  12. #ifdef APPLY_BRIGHTNESS
  13. uniform float u_dayTextureBrightness[TEXTURE_UNITS];
  14. #endif
  15. #ifdef APPLY_CONTRAST
  16. uniform float u_dayTextureContrast[TEXTURE_UNITS];
  17. #endif
  18. #ifdef APPLY_HUE
  19. uniform float u_dayTextureHue[TEXTURE_UNITS];
  20. #endif
  21. #ifdef APPLY_SATURATION
  22. uniform float u_dayTextureSaturation[TEXTURE_UNITS];
  23. #endif
  24. #ifdef APPLY_GAMMA
  25. uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];
  26. #endif
  27. #ifdef APPLY_IMAGERY_CUTOUT
  28. uniform vec4 u_dayTextureCutoutRectangles[TEXTURE_UNITS];
  29. #endif
  30. #ifdef APPLY_COLOR_TO_ALPHA
  31. uniform vec4 u_colorsToAlpha[TEXTURE_UNITS];
  32. #endif
  33. uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];
  34. #endif
  35. #ifdef SHOW_REFLECTIVE_OCEAN
  36. uniform sampler2D u_waterMask;
  37. uniform vec4 u_waterMaskTranslationAndScale;
  38. uniform float u_zoomedOutOceanSpecularIntensity;
  39. #endif
  40. #ifdef SHOW_OCEAN_WAVES
  41. uniform sampler2D u_oceanNormalMap;
  42. #endif
  43. #if defined(ENABLE_DAYNIGHT_SHADING) || defined(GROUND_ATMOSPHERE)
  44. uniform vec2 u_lightingFadeDistance;
  45. #endif
  46. #ifdef TILE_LIMIT_RECTANGLE
  47. uniform vec4 u_cartographicLimitRectangle;
  48. #endif
  49. #ifdef GROUND_ATMOSPHERE
  50. uniform vec2 u_nightFadeDistance;
  51. #endif
  52. #ifdef ENABLE_CLIPPING_PLANES
  53. uniform sampler2D u_clippingPlanes;
  54. uniform mat4 u_clippingPlanesMatrix;
  55. uniform vec4 u_clippingPlanesEdgeStyle;
  56. #endif
  57. #if defined(FOG) && (defined(ENABLE_VERTEX_LIGHTING) || defined(ENABLE_DAYNIGHT_SHADING)) || defined(GROUND_ATMOSPHERE)
  58. uniform float u_minimumBrightness;
  59. #endif
  60. #ifdef COLOR_CORRECT
  61. uniform vec3 u_hsbShift; // Hue, saturation, brightness
  62. #endif
  63. #ifdef HIGHLIGHT_FILL_TILE
  64. uniform vec4 u_fillHighlightColor;
  65. #endif
  66. varying vec3 v_positionMC;
  67. varying vec3 v_positionEC;
  68. varying vec3 v_textureCoordinates;
  69. varying vec3 v_normalMC;
  70. varying vec3 v_normalEC;
  71. #ifdef APPLY_MATERIAL
  72. varying float v_height;
  73. varying float v_slope;
  74. varying float v_aspect;
  75. #endif
  76. #if defined(FOG) || defined(GROUND_ATMOSPHERE)
  77. varying float v_distance;
  78. varying vec3 v_fogRayleighColor;
  79. varying vec3 v_fogMieColor;
  80. #endif
  81. #ifdef GROUND_ATMOSPHERE
  82. varying vec3 v_rayleighColor;
  83. varying vec3 v_mieColor;
  84. #endif
  85. vec4 sampleAndBlend(
  86. vec4 previousColor,
  87. sampler2D textureToSample,
  88. vec2 tileTextureCoordinates,
  89. vec4 textureCoordinateRectangle,
  90. vec4 textureCoordinateTranslationAndScale,
  91. float textureAlpha,
  92. float textureBrightness,
  93. float textureContrast,
  94. float textureHue,
  95. float textureSaturation,
  96. float textureOneOverGamma,
  97. float split,
  98. vec4 colorToAlpha)
  99. {
  100. // This crazy step stuff sets the alpha to 0.0 if this following condition is true:
  101. // tileTextureCoordinates.s < textureCoordinateRectangle.s ||
  102. // tileTextureCoordinates.s > textureCoordinateRectangle.p ||
  103. // tileTextureCoordinates.t < textureCoordinateRectangle.t ||
  104. // tileTextureCoordinates.t > textureCoordinateRectangle.q
  105. // In other words, the alpha is zero if the fragment is outside the rectangle
  106. // covered by this texture. Would an actual 'if' yield better performance?
  107. vec2 alphaMultiplier = step(textureCoordinateRectangle.st, tileTextureCoordinates);
  108. textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;
  109. alphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates);
  110. textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;
  111. vec2 translation = textureCoordinateTranslationAndScale.xy;
  112. vec2 scale = textureCoordinateTranslationAndScale.zw;
  113. vec2 textureCoordinates = tileTextureCoordinates * scale + translation;
  114. vec4 value = texture2D(textureToSample, textureCoordinates);
  115. vec3 color = value.rgb;
  116. float alpha = value.a;
  117. #ifdef APPLY_COLOR_TO_ALPHA
  118. vec3 colorDiff = abs(color.rgb - colorToAlpha.rgb);
  119. colorDiff.r = max(max(colorDiff.r, colorDiff.g), colorDiff.b);
  120. alpha = czm_branchFreeTernary(colorDiff.r < colorToAlpha.a, 0.0, alpha);
  121. #endif
  122. #if !defined(APPLY_GAMMA)
  123. vec4 tempColor = czm_gammaCorrect(vec4(color, alpha));
  124. color = tempColor.rgb;
  125. alpha = tempColor.a;
  126. #else
  127. color = pow(color, vec3(textureOneOverGamma));
  128. #endif
  129. #ifdef APPLY_SPLIT
  130. float splitPosition = czm_imagerySplitPosition;
  131. // Split to the left
  132. if (split < 0.0 && gl_FragCoord.x > splitPosition) {
  133. alpha = 0.0;
  134. }
  135. // Split to the right
  136. else if (split > 0.0 && gl_FragCoord.x < splitPosition) {
  137. alpha = 0.0;
  138. }
  139. #endif
  140. #ifdef APPLY_BRIGHTNESS
  141. color = mix(vec3(0.0), color, textureBrightness);
  142. #endif
  143. #ifdef APPLY_CONTRAST
  144. color = mix(vec3(0.5), color, textureContrast);
  145. #endif
  146. #ifdef APPLY_HUE
  147. color = czm_hue(color, textureHue);
  148. #endif
  149. #ifdef APPLY_SATURATION
  150. color = czm_saturation(color, textureSaturation);
  151. #endif
  152. float sourceAlpha = alpha * textureAlpha;
  153. float outAlpha = mix(previousColor.a, 1.0, sourceAlpha);
  154. outAlpha += sign(outAlpha) - 1.0;
  155. vec3 outColor = mix(previousColor.rgb * previousColor.a, color, sourceAlpha) / outAlpha;
  156. // When rendering imagery for a tile in multiple passes,
  157. // some GPU/WebGL implementation combinations will not blend fragments in
  158. // additional passes correctly if their computation includes an unmasked
  159. // divide-by-zero operation,
  160. // even if it's not in the output or if the output has alpha zero.
  161. //
  162. // For example, without sanitization for outAlpha,
  163. // this renders without artifacts:
  164. // if (outAlpha == 0.0) { outColor = vec3(0.0); }
  165. //
  166. // but using czm_branchFreeTernary will cause portions of the tile that are
  167. // alpha-zero in the additional pass to render as black instead of blending
  168. // with the previous pass:
  169. // outColor = czm_branchFreeTernary(outAlpha == 0.0, vec3(0.0), outColor);
  170. //
  171. // So instead, sanitize against divide-by-zero,
  172. // store this state on the sign of outAlpha, and correct on return.
  173. return vec4(outColor, max(outAlpha, 0.0));
  174. }
  175. vec3 colorCorrect(vec3 rgb) {
  176. #ifdef COLOR_CORRECT
  177. // Convert rgb color to hsb
  178. vec3 hsb = czm_RGBToHSB(rgb);
  179. // Perform hsb shift
  180. hsb.x += u_hsbShift.x; // hue
  181. hsb.y = clamp(hsb.y + u_hsbShift.y, 0.0, 1.0); // saturation
  182. hsb.z = hsb.z > czm_epsilon7 ? hsb.z + u_hsbShift.z : 0.0; // brightness
  183. // Convert shifted hsb back to rgb
  184. rgb = czm_HSBToRGB(hsb);
  185. #endif
  186. return rgb;
  187. }
  188. vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates);
  189. vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float specularMapValue, float fade);
  190. void main()
  191. {
  192. #ifdef TILE_LIMIT_RECTANGLE
  193. if (v_textureCoordinates.x < u_cartographicLimitRectangle.x || u_cartographicLimitRectangle.z < v_textureCoordinates.x ||
  194. v_textureCoordinates.y < u_cartographicLimitRectangle.y || u_cartographicLimitRectangle.w < v_textureCoordinates.y)
  195. {
  196. discard;
  197. }
  198. #endif
  199. #ifdef ENABLE_CLIPPING_PLANES
  200. float clipDistance = clip(gl_FragCoord, u_clippingPlanes, u_clippingPlanesMatrix);
  201. #endif
  202. // The clamp below works around an apparent bug in Chrome Canary v23.0.1241.0
  203. // where the fragment shader sees textures coordinates < 0.0 and > 1.0 for the
  204. // fragments on the edges of tiles even though the vertex shader is outputting
  205. // coordinates strictly in the 0-1 range.
  206. vec4 color = computeDayColor(u_initialColor, clamp(v_textureCoordinates, 0.0, 1.0));
  207. #ifdef SHOW_TILE_BOUNDARIES
  208. if (v_textureCoordinates.x < (1.0/256.0) || v_textureCoordinates.x > (255.0/256.0) ||
  209. v_textureCoordinates.y < (1.0/256.0) || v_textureCoordinates.y > (255.0/256.0))
  210. {
  211. color = vec4(1.0, 0.0, 0.0, 1.0);
  212. }
  213. #endif
  214. #if defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING) || defined(HDR)
  215. vec3 normalMC = czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)); // normalized surface normal in model coordinates
  216. vec3 normalEC = czm_normal3D * normalMC; // normalized surface normal in eye coordiantes
  217. #endif
  218. #if defined(ENABLE_DAYNIGHT_SHADING) || defined(GROUND_ATMOSPHERE)
  219. float cameraDist;
  220. if (czm_sceneMode == czm_sceneMode2D)
  221. {
  222. cameraDist = max(czm_frustumPlanes.x - czm_frustumPlanes.y, czm_frustumPlanes.w - czm_frustumPlanes.z) * 0.5;
  223. }
  224. else if (czm_sceneMode == czm_sceneModeColumbusView)
  225. {
  226. cameraDist = -czm_view[3].z;
  227. }
  228. else
  229. {
  230. cameraDist = length(czm_view[3]);
  231. }
  232. float fadeOutDist = u_lightingFadeDistance.x;
  233. float fadeInDist = u_lightingFadeDistance.y;
  234. if (czm_sceneMode != czm_sceneMode3D) {
  235. vec3 radii = czm_ellipsoidRadii;
  236. float maxRadii = max(radii.x, max(radii.y, radii.z));
  237. fadeOutDist -= maxRadii;
  238. fadeInDist -= maxRadii;
  239. }
  240. float fade = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0);
  241. #else
  242. float fade = 0.0;
  243. #endif
  244. #ifdef SHOW_REFLECTIVE_OCEAN
  245. vec2 waterMaskTranslation = u_waterMaskTranslationAndScale.xy;
  246. vec2 waterMaskScale = u_waterMaskTranslationAndScale.zw;
  247. vec2 waterMaskTextureCoordinates = v_textureCoordinates.xy * waterMaskScale + waterMaskTranslation;
  248. waterMaskTextureCoordinates.y = 1.0 - waterMaskTextureCoordinates.y;
  249. float mask = texture2D(u_waterMask, waterMaskTextureCoordinates).r;
  250. if (mask > 0.0)
  251. {
  252. mat3 enuToEye = czm_eastNorthUpToEyeCoordinates(v_positionMC, normalEC);
  253. vec2 ellipsoidTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC);
  254. vec2 ellipsoidFlippedTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC.zyx);
  255. vec2 textureCoordinates = mix(ellipsoidTextureCoordinates, ellipsoidFlippedTextureCoordinates, czm_morphTime * smoothstep(0.9, 0.95, normalMC.z));
  256. color = computeWaterColor(v_positionEC, textureCoordinates, enuToEye, color, mask, fade);
  257. }
  258. #endif
  259. #ifdef APPLY_MATERIAL
  260. czm_materialInput materialInput;
  261. materialInput.st = v_textureCoordinates.st;
  262. materialInput.normalEC = normalize(v_normalEC);
  263. materialInput.slope = v_slope;
  264. materialInput.height = v_height;
  265. materialInput.aspect = v_aspect;
  266. czm_material material = czm_getMaterial(materialInput);
  267. color.xyz = mix(color.xyz, material.diffuse, material.alpha);
  268. #endif
  269. #ifdef ENABLE_VERTEX_LIGHTING
  270. float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalize(v_normalEC)) * 0.9 + 0.3, 0.0, 1.0);
  271. vec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);
  272. #elif defined(ENABLE_DAYNIGHT_SHADING)
  273. float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * 5.0 + 0.3, 0.0, 1.0);
  274. diffuseIntensity = mix(1.0, diffuseIntensity, fade);
  275. vec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);
  276. #else
  277. vec4 finalColor = color;
  278. #endif
  279. #ifdef ENABLE_CLIPPING_PLANES
  280. vec4 clippingPlanesEdgeColor = vec4(1.0);
  281. clippingPlanesEdgeColor.rgb = u_clippingPlanesEdgeStyle.rgb;
  282. float clippingPlanesEdgeWidth = u_clippingPlanesEdgeStyle.a;
  283. if (clipDistance < clippingPlanesEdgeWidth)
  284. {
  285. finalColor = clippingPlanesEdgeColor;
  286. }
  287. #endif
  288. #ifdef HIGHLIGHT_FILL_TILE
  289. finalColor = vec4(mix(finalColor.rgb, u_fillHighlightColor.rgb, u_fillHighlightColor.a), finalColor.a);
  290. #endif
  291. #if defined(FOG) || defined(GROUND_ATMOSPHERE)
  292. vec3 fogColor = colorCorrect(v_fogMieColor) + finalColor.rgb * colorCorrect(v_fogRayleighColor);
  293. #ifndef HDR
  294. const float fExposure = 2.0;
  295. fogColor = vec3(1.0) - exp(-fExposure * fogColor);
  296. #endif
  297. #endif
  298. #ifdef FOG
  299. #if defined(ENABLE_VERTEX_LIGHTING) || defined(ENABLE_DAYNIGHT_SHADING)
  300. float darken = clamp(dot(normalize(czm_viewerPositionWC), normalize(czm_sunPositionWC)), u_minimumBrightness, 1.0);
  301. fogColor *= darken;
  302. #endif
  303. #ifdef HDR
  304. const float modifier = 0.15;
  305. finalColor = vec4(czm_fog(v_distance, finalColor.rgb, fogColor, modifier), finalColor.a);
  306. #else
  307. finalColor = vec4(czm_fog(v_distance, finalColor.rgb, fogColor), finalColor.a);
  308. #endif
  309. #endif
  310. #ifdef GROUND_ATMOSPHERE
  311. if (czm_sceneMode != czm_sceneMode3D)
  312. {
  313. gl_FragColor = finalColor;
  314. return;
  315. }
  316. #if defined(PER_FRAGMENT_GROUND_ATMOSPHERE) && (defined(ENABLE_DAYNIGHT_SHADING) || defined(ENABLE_VERTEX_LIGHTING))
  317. float mpp = czm_metersPerPixel(vec4(0.0, 0.0, -czm_currentFrustum.x, 1.0), 1.0);
  318. vec2 xy = gl_FragCoord.xy / czm_viewport.zw * 2.0 - vec2(1.0);
  319. xy *= czm_viewport.zw * mpp * 0.5;
  320. vec3 direction = normalize(vec3(xy, -czm_currentFrustum.x));
  321. czm_ray ray = czm_ray(vec3(0.0), direction);
  322. vec3 ellipsoid_center = czm_view[3].xyz;
  323. czm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid_center, czm_ellipsoidInverseRadii);
  324. vec3 ellipsoidPosition = czm_pointAlongRay(ray, intersection.start);
  325. ellipsoidPosition = (czm_inverseView * vec4(ellipsoidPosition, 1.0)).xyz;
  326. AtmosphereColor atmosColor = computeGroundAtmosphereFromSpace(ellipsoidPosition, true);
  327. vec3 groundAtmosphereColor = colorCorrect(atmosColor.mie) + finalColor.rgb * colorCorrect(atmosColor.rayleigh);
  328. #ifndef HDR
  329. groundAtmosphereColor = vec3(1.0) - exp(-fExposure * groundAtmosphereColor);
  330. #endif
  331. fadeInDist = u_nightFadeDistance.x;
  332. fadeOutDist = u_nightFadeDistance.y;
  333. float sunlitAtmosphereIntensity = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0);
  334. #ifdef HDR
  335. // Some tweaking to make HDR look better
  336. sunlitAtmosphereIntensity = max(sunlitAtmosphereIntensity * sunlitAtmosphereIntensity, 0.03);
  337. #endif
  338. groundAtmosphereColor = mix(groundAtmosphereColor, fogColor, sunlitAtmosphereIntensity);
  339. #else
  340. vec3 groundAtmosphereColor = fogColor;
  341. #endif
  342. #ifdef HDR
  343. // Some tweaking to make HDR look better
  344. groundAtmosphereColor = czm_saturation(groundAtmosphereColor, 1.6);
  345. #endif
  346. finalColor = vec4(mix(finalColor.rgb, groundAtmosphereColor, fade), finalColor.a);
  347. #endif
  348. gl_FragColor = finalColor;
  349. }
  350. #ifdef SHOW_REFLECTIVE_OCEAN
  351. float waveFade(float edge0, float edge1, float x)
  352. {
  353. float y = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
  354. return pow(1.0 - y, 5.0);
  355. }
  356. float linearFade(float edge0, float edge1, float x)
  357. {
  358. return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
  359. }
  360. // Based on water rendering by Jonas Wagner:
  361. // http://29a.ch/2012/7/19/webgl-terrain-rendering-water-fog
  362. // low altitude wave settings
  363. const float oceanFrequencyLowAltitude = 825000.0;
  364. const float oceanAnimationSpeedLowAltitude = 0.004;
  365. const float oceanOneOverAmplitudeLowAltitude = 1.0 / 2.0;
  366. const float oceanSpecularIntensity = 0.5;
  367. // high altitude wave settings
  368. const float oceanFrequencyHighAltitude = 125000.0;
  369. const float oceanAnimationSpeedHighAltitude = 0.008;
  370. const float oceanOneOverAmplitudeHighAltitude = 1.0 / 2.0;
  371. vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float maskValue, float fade)
  372. {
  373. vec3 positionToEyeEC = -positionEyeCoordinates;
  374. float positionToEyeECLength = length(positionToEyeEC);
  375. // The double normalize below works around a bug in Firefox on Android devices.
  376. vec3 normalizedpositionToEyeEC = normalize(normalize(positionToEyeEC));
  377. // Fade out the waves as the camera moves far from the surface.
  378. float waveIntensity = waveFade(70000.0, 1000000.0, positionToEyeECLength);
  379. #ifdef SHOW_OCEAN_WAVES
  380. // high altitude waves
  381. float time = czm_frameNumber * oceanAnimationSpeedHighAltitude;
  382. vec4 noise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyHighAltitude, time, 0.0);
  383. vec3 normalTangentSpaceHighAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeHighAltitude);
  384. // low altitude waves
  385. time = czm_frameNumber * oceanAnimationSpeedLowAltitude;
  386. noise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyLowAltitude, time, 0.0);
  387. vec3 normalTangentSpaceLowAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeLowAltitude);
  388. // blend the 2 wave layers based on distance to surface
  389. float highAltitudeFade = linearFade(0.0, 60000.0, positionToEyeECLength);
  390. float lowAltitudeFade = 1.0 - linearFade(20000.0, 60000.0, positionToEyeECLength);
  391. vec3 normalTangentSpace =
  392. (highAltitudeFade * normalTangentSpaceHighAltitude) +
  393. (lowAltitudeFade * normalTangentSpaceLowAltitude);
  394. normalTangentSpace = normalize(normalTangentSpace);
  395. // fade out the normal perturbation as we move farther from the water surface
  396. normalTangentSpace.xy *= waveIntensity;
  397. normalTangentSpace = normalize(normalTangentSpace);
  398. #else
  399. vec3 normalTangentSpace = vec3(0.0, 0.0, 1.0);
  400. #endif
  401. vec3 normalEC = enuToEye * normalTangentSpace;
  402. const vec3 waveHighlightColor = vec3(0.3, 0.45, 0.6);
  403. // Use diffuse light to highlight the waves
  404. float diffuseIntensity = czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * maskValue;
  405. vec3 diffuseHighlight = waveHighlightColor * diffuseIntensity * (1.0 - fade);
  406. #ifdef SHOW_OCEAN_WAVES
  407. // Where diffuse light is low or non-existent, use wave highlights based solely on
  408. // the wave bumpiness and no particular light direction.
  409. float tsPerturbationRatio = normalTangentSpace.z;
  410. vec3 nonDiffuseHighlight = mix(waveHighlightColor * 5.0 * (1.0 - tsPerturbationRatio), vec3(0.0), diffuseIntensity);
  411. #else
  412. vec3 nonDiffuseHighlight = vec3(0.0);
  413. #endif
  414. // Add specular highlights in 3D, and in all modes when zoomed in.
  415. float specularIntensity = czm_getSpecular(czm_sunDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0) + 0.25 * czm_getSpecular(czm_moonDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0);
  416. float surfaceReflectance = mix(0.0, mix(u_zoomedOutOceanSpecularIntensity, oceanSpecularIntensity, waveIntensity), maskValue);
  417. float specular = specularIntensity * surfaceReflectance;
  418. #ifdef HDR
  419. specular *= 1.4;
  420. float e = 0.2;
  421. float d = 3.3;
  422. float c = 1.7;
  423. vec3 color = imageryColor.rgb + (c * (vec3(e) + imageryColor.rgb * d) * (diffuseHighlight + nonDiffuseHighlight + specular));
  424. #else
  425. vec3 color = imageryColor.rgb + diffuseHighlight + nonDiffuseHighlight + specular;
  426. #endif
  427. return vec4(color, imageryColor.a);
  428. }
  429. #endif // #ifdef SHOW_REFLECTIVE_OCEAN