GlobeSurfaceShaderSet.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. import defined from "../Core/defined.js";
  2. import destroyObject from "../Core/destroyObject.js";
  3. import TerrainQuantization from "../Core/TerrainQuantization.js";
  4. import ShaderProgram from "../Renderer/ShaderProgram.js";
  5. import getClippingFunction from "./getClippingFunction.js";
  6. import SceneMode from "./SceneMode.js";
  7. function GlobeSurfaceShader(
  8. numberOfDayTextures,
  9. flags,
  10. material,
  11. shaderProgram,
  12. clippingShaderState
  13. ) {
  14. this.numberOfDayTextures = numberOfDayTextures;
  15. this.flags = flags;
  16. this.material = material;
  17. this.shaderProgram = shaderProgram;
  18. this.clippingShaderState = clippingShaderState;
  19. }
  20. /**
  21. * Manages the shaders used to shade the surface of a {@link Globe}.
  22. *
  23. * @alias GlobeSurfaceShaderSet
  24. * @private
  25. */
  26. function GlobeSurfaceShaderSet() {
  27. this.baseVertexShaderSource = undefined;
  28. this.baseFragmentShaderSource = undefined;
  29. this._shadersByTexturesFlags = [];
  30. this.material = undefined;
  31. }
  32. function getPositionMode(sceneMode) {
  33. const getPosition3DMode =
  34. "vec4 getPosition(vec3 position, float height, vec2 textureCoordinates) { return getPosition3DMode(position, height, textureCoordinates); }";
  35. const getPositionColumbusViewAnd2DMode =
  36. "vec4 getPosition(vec3 position, float height, vec2 textureCoordinates) { return getPositionColumbusViewMode(position, height, textureCoordinates); }";
  37. const getPositionMorphingMode =
  38. "vec4 getPosition(vec3 position, float height, vec2 textureCoordinates) { return getPositionMorphingMode(position, height, textureCoordinates); }";
  39. let positionMode;
  40. switch (sceneMode) {
  41. case SceneMode.SCENE3D:
  42. positionMode = getPosition3DMode;
  43. break;
  44. case SceneMode.SCENE2D:
  45. case SceneMode.COLUMBUS_VIEW:
  46. positionMode = getPositionColumbusViewAnd2DMode;
  47. break;
  48. case SceneMode.MORPHING:
  49. positionMode = getPositionMorphingMode;
  50. break;
  51. }
  52. return positionMode;
  53. }
  54. function get2DYPositionFraction(useWebMercatorProjection) {
  55. const get2DYPositionFractionGeographicProjection =
  56. "float get2DYPositionFraction(vec2 textureCoordinates) { return get2DGeographicYPositionFraction(textureCoordinates); }";
  57. const get2DYPositionFractionMercatorProjection =
  58. "float get2DYPositionFraction(vec2 textureCoordinates) { return get2DMercatorYPositionFraction(textureCoordinates); }";
  59. return useWebMercatorProjection
  60. ? get2DYPositionFractionMercatorProjection
  61. : get2DYPositionFractionGeographicProjection;
  62. }
  63. GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
  64. const frameState = options.frameState;
  65. const surfaceTile = options.surfaceTile;
  66. const numberOfDayTextures = options.numberOfDayTextures;
  67. const applyBrightness = options.applyBrightness;
  68. const applyContrast = options.applyContrast;
  69. const applyHue = options.applyHue;
  70. const applySaturation = options.applySaturation;
  71. const applyGamma = options.applyGamma;
  72. const applyAlpha = options.applyAlpha;
  73. const applyDayNightAlpha = options.applyDayNightAlpha;
  74. const applySplit = options.applySplit;
  75. const showReflectiveOcean = options.showReflectiveOcean;
  76. const showOceanWaves = options.showOceanWaves;
  77. const enableLighting = options.enableLighting;
  78. const dynamicAtmosphereLighting = options.dynamicAtmosphereLighting;
  79. const dynamicAtmosphereLightingFromSun =
  80. options.dynamicAtmosphereLightingFromSun;
  81. const showGroundAtmosphere = options.showGroundAtmosphere;
  82. const perFragmentGroundAtmosphere = options.perFragmentGroundAtmosphere;
  83. const hasVertexNormals = options.hasVertexNormals;
  84. const useWebMercatorProjection = options.useWebMercatorProjection;
  85. const enableFog = options.enableFog;
  86. const enableClippingPlanes = options.enableClippingPlanes;
  87. const clippingPlanes = options.clippingPlanes;
  88. const clippedByBoundaries = options.clippedByBoundaries;
  89. const hasImageryLayerCutout = options.hasImageryLayerCutout;
  90. const colorCorrect = options.colorCorrect;
  91. const highlightFillTile = options.highlightFillTile;
  92. const colorToAlpha = options.colorToAlpha;
  93. const hasGeodeticSurfaceNormals = options.hasGeodeticSurfaceNormals;
  94. const hasExaggeration = options.hasExaggeration;
  95. const showUndergroundColor = options.showUndergroundColor;
  96. const translucent = options.translucent;
  97. let quantization = 0;
  98. let quantizationDefine = "";
  99. const mesh = surfaceTile.renderedMesh;
  100. const terrainEncoding = mesh.encoding;
  101. const quantizationMode = terrainEncoding.quantization;
  102. if (quantizationMode === TerrainQuantization.BITS12) {
  103. quantization = 1;
  104. quantizationDefine = "QUANTIZATION_BITS12";
  105. }
  106. let cartographicLimitRectangleFlag = 0;
  107. let cartographicLimitRectangleDefine = "";
  108. if (clippedByBoundaries) {
  109. cartographicLimitRectangleFlag = 1;
  110. cartographicLimitRectangleDefine = "TILE_LIMIT_RECTANGLE";
  111. }
  112. let imageryCutoutFlag = 0;
  113. let imageryCutoutDefine = "";
  114. if (hasImageryLayerCutout) {
  115. imageryCutoutFlag = 1;
  116. imageryCutoutDefine = "APPLY_IMAGERY_CUTOUT";
  117. }
  118. const sceneMode = frameState.mode;
  119. const flags =
  120. sceneMode |
  121. (applyBrightness << 2) |
  122. (applyContrast << 3) |
  123. (applyHue << 4) |
  124. (applySaturation << 5) |
  125. (applyGamma << 6) |
  126. (applyAlpha << 7) |
  127. (showReflectiveOcean << 8) |
  128. (showOceanWaves << 9) |
  129. (enableLighting << 10) |
  130. (dynamicAtmosphereLighting << 11) |
  131. (dynamicAtmosphereLightingFromSun << 12) |
  132. (showGroundAtmosphere << 13) |
  133. (perFragmentGroundAtmosphere << 14) |
  134. (hasVertexNormals << 15) |
  135. (useWebMercatorProjection << 16) |
  136. (enableFog << 17) |
  137. (quantization << 18) |
  138. (applySplit << 19) |
  139. (enableClippingPlanes << 20) |
  140. (cartographicLimitRectangleFlag << 21) |
  141. (imageryCutoutFlag << 22) |
  142. (colorCorrect << 23) |
  143. (highlightFillTile << 24) |
  144. (colorToAlpha << 25) |
  145. (hasGeodeticSurfaceNormals << 26) |
  146. (hasExaggeration << 27) |
  147. (showUndergroundColor << 28) |
  148. (translucent << 29) |
  149. (applyDayNightAlpha << 30);
  150. let currentClippingShaderState = 0;
  151. if (defined(clippingPlanes) && clippingPlanes.length > 0) {
  152. currentClippingShaderState = enableClippingPlanes
  153. ? clippingPlanes.clippingPlanesState
  154. : 0;
  155. }
  156. let surfaceShader = surfaceTile.surfaceShader;
  157. if (
  158. defined(surfaceShader) &&
  159. surfaceShader.numberOfDayTextures === numberOfDayTextures &&
  160. surfaceShader.flags === flags &&
  161. surfaceShader.material === this.material &&
  162. surfaceShader.clippingShaderState === currentClippingShaderState
  163. ) {
  164. return surfaceShader.shaderProgram;
  165. }
  166. // New tile, or tile changed number of textures, flags, or clipping planes
  167. let shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures];
  168. if (!defined(shadersByFlags)) {
  169. shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures] = [];
  170. }
  171. surfaceShader = shadersByFlags[flags];
  172. if (
  173. !defined(surfaceShader) ||
  174. surfaceShader.material !== this.material ||
  175. surfaceShader.clippingShaderState !== currentClippingShaderState
  176. ) {
  177. // Cache miss - we've never seen this combination of numberOfDayTextures and flags before.
  178. const vs = this.baseVertexShaderSource.clone();
  179. const fs = this.baseFragmentShaderSource.clone();
  180. if (currentClippingShaderState !== 0) {
  181. fs.sources.unshift(
  182. getClippingFunction(clippingPlanes, frameState.context)
  183. ); // Need to go before GlobeFS
  184. }
  185. vs.defines.push(quantizationDefine);
  186. fs.defines.push(
  187. `TEXTURE_UNITS ${numberOfDayTextures}`,
  188. cartographicLimitRectangleDefine,
  189. imageryCutoutDefine
  190. );
  191. if (applyBrightness) {
  192. fs.defines.push("APPLY_BRIGHTNESS");
  193. }
  194. if (applyContrast) {
  195. fs.defines.push("APPLY_CONTRAST");
  196. }
  197. if (applyHue) {
  198. fs.defines.push("APPLY_HUE");
  199. }
  200. if (applySaturation) {
  201. fs.defines.push("APPLY_SATURATION");
  202. }
  203. if (applyGamma) {
  204. fs.defines.push("APPLY_GAMMA");
  205. }
  206. if (applyAlpha) {
  207. fs.defines.push("APPLY_ALPHA");
  208. }
  209. if (applyDayNightAlpha) {
  210. fs.defines.push("APPLY_DAY_NIGHT_ALPHA");
  211. }
  212. if (showReflectiveOcean) {
  213. fs.defines.push("SHOW_REFLECTIVE_OCEAN");
  214. vs.defines.push("SHOW_REFLECTIVE_OCEAN");
  215. }
  216. if (showOceanWaves) {
  217. fs.defines.push("SHOW_OCEAN_WAVES");
  218. }
  219. if (colorToAlpha) {
  220. fs.defines.push("APPLY_COLOR_TO_ALPHA");
  221. }
  222. if (showUndergroundColor) {
  223. vs.defines.push("UNDERGROUND_COLOR");
  224. fs.defines.push("UNDERGROUND_COLOR");
  225. }
  226. if (translucent) {
  227. vs.defines.push("TRANSLUCENT");
  228. fs.defines.push("TRANSLUCENT");
  229. }
  230. if (enableLighting) {
  231. if (hasVertexNormals) {
  232. vs.defines.push("ENABLE_VERTEX_LIGHTING");
  233. fs.defines.push("ENABLE_VERTEX_LIGHTING");
  234. } else {
  235. vs.defines.push("ENABLE_DAYNIGHT_SHADING");
  236. fs.defines.push("ENABLE_DAYNIGHT_SHADING");
  237. }
  238. }
  239. if (dynamicAtmosphereLighting) {
  240. vs.defines.push("DYNAMIC_ATMOSPHERE_LIGHTING");
  241. fs.defines.push("DYNAMIC_ATMOSPHERE_LIGHTING");
  242. if (dynamicAtmosphereLightingFromSun) {
  243. vs.defines.push("DYNAMIC_ATMOSPHERE_LIGHTING_FROM_SUN");
  244. fs.defines.push("DYNAMIC_ATMOSPHERE_LIGHTING_FROM_SUN");
  245. }
  246. }
  247. if (showGroundAtmosphere) {
  248. vs.defines.push("GROUND_ATMOSPHERE");
  249. fs.defines.push("GROUND_ATMOSPHERE");
  250. if (perFragmentGroundAtmosphere) {
  251. vs.defines.push("PER_FRAGMENT_GROUND_ATMOSPHERE");
  252. fs.defines.push("PER_FRAGMENT_GROUND_ATMOSPHERE");
  253. }
  254. }
  255. vs.defines.push("INCLUDE_WEB_MERCATOR_Y");
  256. fs.defines.push("INCLUDE_WEB_MERCATOR_Y");
  257. if (enableFog) {
  258. vs.defines.push("FOG");
  259. fs.defines.push("FOG");
  260. }
  261. if (applySplit) {
  262. fs.defines.push("APPLY_SPLIT");
  263. }
  264. if (enableClippingPlanes) {
  265. fs.defines.push("ENABLE_CLIPPING_PLANES");
  266. }
  267. if (colorCorrect) {
  268. fs.defines.push("COLOR_CORRECT");
  269. }
  270. if (highlightFillTile) {
  271. fs.defines.push("HIGHLIGHT_FILL_TILE");
  272. }
  273. if (hasGeodeticSurfaceNormals) {
  274. vs.defines.push("GEODETIC_SURFACE_NORMALS");
  275. }
  276. if (hasExaggeration) {
  277. vs.defines.push("EXAGGERATION");
  278. }
  279. let computeDayColor =
  280. "\
  281. vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates, float nightBlend)\n\
  282. {\n\
  283. vec4 color = initialColor;\n";
  284. if (hasImageryLayerCutout) {
  285. computeDayColor +=
  286. "\
  287. vec4 cutoutAndColorResult;\n\
  288. bool texelUnclipped;\n";
  289. }
  290. for (let i = 0; i < numberOfDayTextures; ++i) {
  291. if (hasImageryLayerCutout) {
  292. computeDayColor += `\
  293. cutoutAndColorResult = u_dayTextureCutoutRectangles[${i}];\n\
  294. texelUnclipped = v_textureCoordinates.x < cutoutAndColorResult.x || cutoutAndColorResult.z < v_textureCoordinates.x || v_textureCoordinates.y < cutoutAndColorResult.y || cutoutAndColorResult.w < v_textureCoordinates.y;\n\
  295. cutoutAndColorResult = sampleAndBlend(\n`;
  296. } else {
  297. computeDayColor += "\
  298. color = sampleAndBlend(\n";
  299. }
  300. computeDayColor += `\
  301. color,\n\
  302. u_dayTextures[${i}],\n\
  303. u_dayTextureUseWebMercatorT[${i}] ? textureCoordinates.xz : textureCoordinates.xy,\n\
  304. u_dayTextureTexCoordsRectangle[${i}],\n\
  305. u_dayTextureTranslationAndScale[${i}],\n\
  306. ${applyAlpha ? `u_dayTextureAlpha[${i}]` : "1.0"},\n\
  307. ${applyDayNightAlpha ? `u_dayTextureNightAlpha[${i}]` : "1.0"},\n${
  308. applyDayNightAlpha ? `u_dayTextureDayAlpha[${i}]` : "1.0"
  309. },\n${applyBrightness ? `u_dayTextureBrightness[${i}]` : "0.0"},\n\
  310. ${applyContrast ? `u_dayTextureContrast[${i}]` : "0.0"},\n\
  311. ${applyHue ? `u_dayTextureHue[${i}]` : "0.0"},\n\
  312. ${applySaturation ? `u_dayTextureSaturation[${i}]` : "0.0"},\n\
  313. ${applyGamma ? `u_dayTextureOneOverGamma[${i}]` : "0.0"},\n\
  314. ${applySplit ? `u_dayTextureSplit[${i}]` : "0.0"},\n\
  315. ${colorToAlpha ? `u_colorsToAlpha[${i}]` : "vec4(0.0)"},\n\
  316. nightBlend\
  317. );\n`;
  318. if (hasImageryLayerCutout) {
  319. computeDayColor +=
  320. "\
  321. color = czm_branchFreeTernary(texelUnclipped, cutoutAndColorResult, color);\n";
  322. }
  323. }
  324. computeDayColor += "\
  325. return color;\n\
  326. }";
  327. fs.sources.push(computeDayColor);
  328. vs.sources.push(getPositionMode(sceneMode));
  329. vs.sources.push(get2DYPositionFraction(useWebMercatorProjection));
  330. const shader = ShaderProgram.fromCache({
  331. context: frameState.context,
  332. vertexShaderSource: vs,
  333. fragmentShaderSource: fs,
  334. attributeLocations: terrainEncoding.getAttributeLocations(),
  335. });
  336. surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(
  337. numberOfDayTextures,
  338. flags,
  339. this.material,
  340. shader,
  341. currentClippingShaderState
  342. );
  343. }
  344. surfaceTile.surfaceShader = surfaceShader;
  345. return surfaceShader.shaderProgram;
  346. };
  347. GlobeSurfaceShaderSet.prototype.destroy = function () {
  348. let flags;
  349. let shader;
  350. const shadersByTexturesFlags = this._shadersByTexturesFlags;
  351. for (const textureCount in shadersByTexturesFlags) {
  352. if (shadersByTexturesFlags.hasOwnProperty(textureCount)) {
  353. const shadersByFlags = shadersByTexturesFlags[textureCount];
  354. if (!defined(shadersByFlags)) {
  355. continue;
  356. }
  357. for (flags in shadersByFlags) {
  358. if (shadersByFlags.hasOwnProperty(flags)) {
  359. shader = shadersByFlags[flags];
  360. if (defined(shader)) {
  361. shader.shaderProgram.destroy();
  362. }
  363. }
  364. }
  365. }
  366. }
  367. return destroyObject(this);
  368. };
  369. export default GlobeSurfaceShaderSet;