GlobeTranslucencyState.js 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  1. import combine from "../Core/combine.js";
  2. import defaultValue from "../Core/defaultValue.js";
  3. import defined from "../Core/defined.js";
  4. import NearFarScalar from "../Core/NearFarScalar.js";
  5. import Rectangle from "../Core/Rectangle.js";
  6. import DrawCommand from "../Renderer/DrawCommand.js";
  7. import Pass from "../Renderer/Pass.js";
  8. import RenderState from "../Renderer/RenderState.js";
  9. import ShaderSource from "../Renderer/ShaderSource.js";
  10. import BlendingState from "./BlendingState.js";
  11. import CullFace from "./CullFace.js";
  12. import SceneMode from "./SceneMode.js";
  13. const DerivedCommandType = {
  14. OPAQUE_FRONT_FACE: 0,
  15. OPAQUE_BACK_FACE: 1,
  16. DEPTH_ONLY_FRONT_FACE: 2,
  17. DEPTH_ONLY_BACK_FACE: 3,
  18. DEPTH_ONLY_FRONT_AND_BACK_FACE: 4,
  19. TRANSLUCENT_FRONT_FACE: 5,
  20. TRANSLUCENT_BACK_FACE: 6,
  21. TRANSLUCENT_FRONT_FACE_MANUAL_DEPTH_TEST: 7,
  22. TRANSLUCENT_BACK_FACE_MANUAL_DEPTH_TEST: 8,
  23. PICK_FRONT_FACE: 9,
  24. PICK_BACK_FACE: 10,
  25. DERIVED_COMMANDS_MAXIMUM_LENGTH: 11,
  26. };
  27. const derivedCommandsMaximumLength =
  28. DerivedCommandType.DERIVED_COMMANDS_MAXIMUM_LENGTH;
  29. const DerivedCommandNames = [
  30. "opaqueFrontFaceCommand",
  31. "opaqueBackFaceCommand",
  32. "depthOnlyFrontFaceCommand",
  33. "depthOnlyBackFaceCommand",
  34. "depthOnlyFrontAndBackFaceCommand",
  35. "translucentFrontFaceCommand",
  36. "translucentBackFaceCommand",
  37. "translucentFrontFaceManualDepthTestCommand",
  38. "translucentBackFaceManualDepthTestCommand",
  39. "pickFrontFaceCommand",
  40. "pickBackFaceCommand",
  41. ];
  42. /**
  43. * @private
  44. */
  45. function GlobeTranslucencyState() {
  46. this._frontFaceAlphaByDistance = new NearFarScalar(0.0, 1.0, 0.0, 1.0);
  47. this._backFaceAlphaByDistance = new NearFarScalar(0.0, 1.0, 0.0, 1.0);
  48. this._frontFaceTranslucent = false;
  49. this._backFaceTranslucent = false;
  50. this._requiresManualDepthTest = false;
  51. this._sunVisibleThroughGlobe = false;
  52. this._environmentVisible = false;
  53. this._useDepthPlane = false;
  54. this._numberOfTextureUniforms = 0;
  55. this._globeTranslucencyFramebuffer = undefined;
  56. this._rectangle = Rectangle.clone(Rectangle.MAX_VALUE);
  57. this._derivedCommandKey = 0;
  58. this._derivedCommandsDirty = false;
  59. this._derivedCommandPacks = undefined;
  60. this._derivedCommandTypes = new Array(derivedCommandsMaximumLength);
  61. this._derivedBlendCommandTypes = new Array(derivedCommandsMaximumLength);
  62. this._derivedPickCommandTypes = new Array(derivedCommandsMaximumLength);
  63. this._derivedCommandTypesToUpdate = new Array(derivedCommandsMaximumLength);
  64. this._derivedCommandsLength = 0;
  65. this._derivedBlendCommandsLength = 0;
  66. this._derivedPickCommandsLength = 0;
  67. this._derivedCommandsToUpdateLength = 0;
  68. }
  69. Object.defineProperties(GlobeTranslucencyState.prototype, {
  70. frontFaceAlphaByDistance: {
  71. get: function () {
  72. return this._frontFaceAlphaByDistance;
  73. },
  74. },
  75. backFaceAlphaByDistance: {
  76. get: function () {
  77. return this._backFaceAlphaByDistance;
  78. },
  79. },
  80. translucent: {
  81. get: function () {
  82. return this._frontFaceTranslucent;
  83. },
  84. },
  85. sunVisibleThroughGlobe: {
  86. get: function () {
  87. return this._sunVisibleThroughGlobe;
  88. },
  89. },
  90. environmentVisible: {
  91. get: function () {
  92. return this._environmentVisible;
  93. },
  94. },
  95. useDepthPlane: {
  96. get: function () {
  97. return this._useDepthPlane;
  98. },
  99. },
  100. numberOfTextureUniforms: {
  101. get: function () {
  102. return this._numberOfTextureUniforms;
  103. },
  104. },
  105. rectangle: {
  106. get: function () {
  107. return this._rectangle;
  108. },
  109. },
  110. });
  111. GlobeTranslucencyState.prototype.update = function (scene) {
  112. const globe = scene.globe;
  113. if (!defined(globe) || !globe.show) {
  114. this._frontFaceTranslucent = false;
  115. this._backFaceTranslucent = false;
  116. this._sunVisibleThroughGlobe = true;
  117. this._environmentVisible = true;
  118. this._useDepthPlane = false;
  119. return;
  120. }
  121. this._frontFaceAlphaByDistance = updateAlphaByDistance(
  122. globe.translucency.enabled,
  123. globe.translucency.frontFaceAlpha,
  124. globe.translucency.frontFaceAlphaByDistance,
  125. this._frontFaceAlphaByDistance
  126. );
  127. this._backFaceAlphaByDistance = updateAlphaByDistance(
  128. globe.translucency.enabled,
  129. globe.translucency.backFaceAlpha,
  130. globe.translucency.backFaceAlphaByDistance,
  131. this._backFaceAlphaByDistance
  132. );
  133. this._frontFaceTranslucent = isFaceTranslucent(
  134. globe.translucency.enabled,
  135. this._frontFaceAlphaByDistance,
  136. globe
  137. );
  138. this._backFaceTranslucent = isFaceTranslucent(
  139. globe.translucency.enabled,
  140. this._backFaceAlphaByDistance,
  141. globe
  142. );
  143. this._requiresManualDepthTest = requiresManualDepthTest(this, scene, globe);
  144. this._sunVisibleThroughGlobe = isSunVisibleThroughGlobe(this, scene);
  145. this._environmentVisible = isEnvironmentVisible(this, scene);
  146. this._useDepthPlane = useDepthPlane(this, scene);
  147. this._numberOfTextureUniforms = getNumberOfTextureUniforms(this);
  148. this._rectangle = Rectangle.clone(
  149. globe.translucency.rectangle,
  150. this._rectangle
  151. );
  152. gatherDerivedCommandRequirements(this, scene);
  153. };
  154. function updateAlphaByDistance(enabled, alpha, alphaByDistance, result) {
  155. if (!enabled) {
  156. result.nearValue = 1.0;
  157. result.farValue = 1.0;
  158. return result;
  159. }
  160. if (!defined(alphaByDistance)) {
  161. result.nearValue = alpha;
  162. result.farValue = alpha;
  163. return result;
  164. }
  165. NearFarScalar.clone(alphaByDistance, result);
  166. result.nearValue *= alpha;
  167. result.farValue *= alpha;
  168. return result;
  169. }
  170. function isFaceTranslucent(translucencyEnabled, alphaByDistance, globe) {
  171. return (
  172. translucencyEnabled &&
  173. (globe.baseColor.alpha < 1.0 ||
  174. alphaByDistance.nearValue < 1.0 ||
  175. alphaByDistance.farValue < 1.0)
  176. );
  177. }
  178. function isSunVisibleThroughGlobe(state, scene) {
  179. // The sun is visible through the globe if the front and back faces are translucent when above ground
  180. // or if front faces are translucent when below ground
  181. const frontTranslucent = state._frontFaceTranslucent;
  182. const backTranslucent = state._backFaceTranslucent;
  183. return frontTranslucent && (scene.cameraUnderground || backTranslucent);
  184. }
  185. function isEnvironmentVisible(state, scene) {
  186. // The environment is visible if the camera is above ground or underground with translucency
  187. return !scene.cameraUnderground || state._frontFaceTranslucent;
  188. }
  189. function useDepthPlane(state, scene) {
  190. // Use the depth plane when the camera is above ground and the globe is opaque
  191. return !scene.cameraUnderground && !state._frontFaceTranslucent;
  192. }
  193. function requiresManualDepthTest(state, scene, globe) {
  194. return (
  195. state._frontFaceTranslucent &&
  196. !state._backFaceTranslucent &&
  197. !globe.depthTestAgainstTerrain &&
  198. scene.mode !== SceneMode.SCENE2D &&
  199. scene.context.depthTexture
  200. );
  201. }
  202. function getNumberOfTextureUniforms(state) {
  203. let numberOfTextureUniforms = 0;
  204. if (state._frontFaceTranslucent) {
  205. ++numberOfTextureUniforms; // classification texture
  206. }
  207. if (state._requiresManualDepthTest) {
  208. ++numberOfTextureUniforms; // czm_globeDepthTexture for manual depth testing
  209. }
  210. return numberOfTextureUniforms;
  211. }
  212. function gatherDerivedCommandRequirements(state, scene) {
  213. state._derivedCommandsLength = getDerivedCommandTypes(
  214. state,
  215. scene,
  216. false,
  217. false,
  218. state._derivedCommandTypes
  219. );
  220. state._derivedBlendCommandsLength = getDerivedCommandTypes(
  221. state,
  222. scene,
  223. true,
  224. false,
  225. state._derivedBlendCommandTypes
  226. );
  227. state._derivedPickCommandsLength = getDerivedCommandTypes(
  228. state,
  229. scene,
  230. false,
  231. true,
  232. state._derivedPickCommandTypes
  233. );
  234. let i;
  235. let derivedCommandKey = 0;
  236. for (i = 0; i < state._derivedCommandsLength; ++i) {
  237. derivedCommandKey |= 1 << state._derivedCommandTypes[i];
  238. }
  239. for (i = 0; i < state._derivedBlendCommandsLength; ++i) {
  240. derivedCommandKey |= 1 << state._derivedBlendCommandTypes[i];
  241. }
  242. for (i = 0; i < state._derivedPickCommandsLength; ++i) {
  243. derivedCommandKey |= 1 << state._derivedPickCommandTypes[i];
  244. }
  245. let derivedCommandsToUpdateLength = 0;
  246. for (i = 0; i < derivedCommandsMaximumLength; ++i) {
  247. if ((derivedCommandKey & (1 << i)) > 0) {
  248. state._derivedCommandTypesToUpdate[derivedCommandsToUpdateLength++] = i;
  249. }
  250. }
  251. state._derivedCommandsToUpdateLength = derivedCommandsToUpdateLength;
  252. const derivedCommandsDirty = derivedCommandKey !== state._derivedCommandKey;
  253. state._derivedCommandKey = derivedCommandKey;
  254. state._derivedCommandsDirty = derivedCommandsDirty;
  255. if (!defined(state._derivedCommandPacks) && state._frontFaceTranslucent) {
  256. state._derivedCommandPacks = createDerivedCommandPacks();
  257. }
  258. }
  259. function getDerivedCommandTypes(
  260. state,
  261. scene,
  262. isBlendCommand,
  263. isPickCommand,
  264. types
  265. ) {
  266. let length = 0;
  267. const frontTranslucent = state._frontFaceTranslucent;
  268. const backTranslucent = state._backFaceTranslucent;
  269. if (!frontTranslucent) {
  270. // Don't use derived commands if the globe is opaque
  271. return length;
  272. }
  273. const cameraUnderground = scene.cameraUnderground;
  274. const requiresManualDepthTest = state._requiresManualDepthTest;
  275. const translucentFrontFaceCommandType = isPickCommand
  276. ? DerivedCommandType.PICK_FRONT_FACE
  277. : requiresManualDepthTest
  278. ? DerivedCommandType.TRANSLUCENT_FRONT_FACE_MANUAL_DEPTH_TEST
  279. : DerivedCommandType.TRANSLUCENT_FRONT_FACE;
  280. const translucentBackFaceCommandType = isPickCommand
  281. ? DerivedCommandType.PICK_BACK_FACE
  282. : requiresManualDepthTest
  283. ? DerivedCommandType.TRANSLUCENT_BACK_FACE_MANUAL_DEPTH_TEST
  284. : DerivedCommandType.TRANSLUCENT_BACK_FACE;
  285. if (scene.mode === SceneMode.SCENE2D) {
  286. types[length++] = DerivedCommandType.DEPTH_ONLY_FRONT_FACE;
  287. types[length++] = translucentFrontFaceCommandType;
  288. return length;
  289. }
  290. if (backTranslucent) {
  291. // Push depth-only command for classification. Blend commands do not need to write depth.
  292. // Push translucent commands for front and back faces.
  293. if (!isBlendCommand) {
  294. types[length++] = DerivedCommandType.DEPTH_ONLY_FRONT_AND_BACK_FACE;
  295. }
  296. if (cameraUnderground) {
  297. types[length++] = translucentFrontFaceCommandType;
  298. types[length++] = translucentBackFaceCommandType;
  299. } else {
  300. types[length++] = translucentBackFaceCommandType;
  301. types[length++] = translucentFrontFaceCommandType;
  302. }
  303. } else {
  304. // Push opaque command for the face that appears in back.
  305. // Push depth-only command and translucent command for the face that appears in front.
  306. // eslint-disable-next-line no-lonely-if
  307. if (cameraUnderground) {
  308. if (!isBlendCommand) {
  309. types[length++] = DerivedCommandType.DEPTH_ONLY_BACK_FACE;
  310. }
  311. types[length++] = DerivedCommandType.OPAQUE_FRONT_FACE;
  312. types[length++] = translucentBackFaceCommandType;
  313. } else {
  314. if (!isBlendCommand) {
  315. types[length++] = DerivedCommandType.DEPTH_ONLY_FRONT_FACE;
  316. }
  317. types[length++] = DerivedCommandType.OPAQUE_BACK_FACE;
  318. types[length++] = translucentFrontFaceCommandType;
  319. }
  320. }
  321. return length;
  322. }
  323. function removeDefine(defines, defineToRemove) {
  324. const index = defines.indexOf(defineToRemove);
  325. if (index > -1) {
  326. defines.splice(index, 1);
  327. }
  328. }
  329. function hasDefine(defines, define) {
  330. return defines.indexOf(define) > -1;
  331. }
  332. function getOpaqueFrontFaceShaderProgram(vs, fs) {
  333. removeDefine(vs.defines, "TRANSLUCENT");
  334. removeDefine(fs.defines, "TRANSLUCENT");
  335. }
  336. function getOpaqueBackFaceShaderProgram(vs, fs) {
  337. removeDefine(vs.defines, "GROUND_ATMOSPHERE");
  338. removeDefine(fs.defines, "GROUND_ATMOSPHERE");
  339. removeDefine(vs.defines, "FOG");
  340. removeDefine(fs.defines, "FOG");
  341. removeDefine(vs.defines, "TRANSLUCENT");
  342. removeDefine(fs.defines, "TRANSLUCENT");
  343. }
  344. function getDepthOnlyShaderProgram(vs, fs) {
  345. if (
  346. hasDefine(fs.defines, "TILE_LIMIT_RECTANGLE") ||
  347. hasDefine(fs.defines, "ENABLE_CLIPPING_PLANES")
  348. ) {
  349. // Need to execute the full shader if discard is called
  350. return;
  351. }
  352. const depthOnlyShader =
  353. "void main() \n" + "{ \n" + " out_FragColor = vec4(1.0); \n" + "} \n";
  354. fs.sources = [depthOnlyShader];
  355. }
  356. function getTranslucentShaderProgram(vs, fs) {
  357. const sources = fs.sources;
  358. const length = sources.length;
  359. for (let i = 0; i < length; ++i) {
  360. sources[i] = ShaderSource.replaceMain(
  361. sources[i],
  362. "czm_globe_translucency_main"
  363. );
  364. }
  365. const globeTranslucencyMain =
  366. "\n\n" +
  367. "uniform sampler2D u_classificationTexture; \n" +
  368. "void main() \n" +
  369. "{ \n" +
  370. " vec2 st = gl_FragCoord.xy / czm_viewport.zw; \n" +
  371. "#ifdef MANUAL_DEPTH_TEST \n" +
  372. " float logDepthOrDepth = czm_unpackDepth(texture(czm_globeDepthTexture, st)); \n" +
  373. " if (logDepthOrDepth != 0.0) \n" +
  374. " { \n" +
  375. " vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, logDepthOrDepth); \n" +
  376. " float depthEC = eyeCoordinate.z / eyeCoordinate.w; \n" +
  377. " if (v_positionEC.z < depthEC) \n" +
  378. " { \n" +
  379. " discard; \n" +
  380. " } \n" +
  381. " } \n" +
  382. "#endif \n" +
  383. " czm_globe_translucency_main(); \n" +
  384. " vec4 classificationColor = texture(u_classificationTexture, st); \n" +
  385. " if (classificationColor.a > 0.0) \n" +
  386. " { \n" +
  387. " // Reverse premultiplication process to get the correct composited result of the classification primitives \n" +
  388. " classificationColor.rgb /= classificationColor.a; \n" +
  389. " } \n" +
  390. " out_FragColor = classificationColor * vec4(classificationColor.aaa, 1.0) + out_FragColor * (1.0 - classificationColor.a); \n" +
  391. "} \n";
  392. sources.push(globeTranslucencyMain);
  393. }
  394. function getTranslucentBackFaceShaderProgram(vs, fs) {
  395. getTranslucentShaderProgram(vs, fs);
  396. removeDefine(vs.defines, "GROUND_ATMOSPHERE");
  397. removeDefine(fs.defines, "GROUND_ATMOSPHERE");
  398. removeDefine(vs.defines, "FOG");
  399. removeDefine(fs.defines, "FOG");
  400. }
  401. function getTranslucentFrontFaceManualDepthTestShaderProgram(vs, fs) {
  402. getTranslucentShaderProgram(vs, fs);
  403. vs.defines.push("GENERATE_POSITION");
  404. fs.defines.push("MANUAL_DEPTH_TEST");
  405. }
  406. function getTranslucentBackFaceManualDepthTestShaderProgram(vs, fs) {
  407. getTranslucentBackFaceShaderProgram(vs, fs);
  408. vs.defines.push("GENERATE_POSITION");
  409. fs.defines.push("MANUAL_DEPTH_TEST");
  410. }
  411. function getPickShaderProgram(vs, fs) {
  412. const pickShader =
  413. "uniform sampler2D u_classificationTexture; \n" +
  414. "void main() \n" +
  415. "{ \n" +
  416. " vec2 st = gl_FragCoord.xy / czm_viewport.zw; \n" +
  417. " vec4 pickColor = texture(u_classificationTexture, st); \n" +
  418. " if (pickColor == vec4(0.0)) \n" +
  419. " { \n" +
  420. " discard; \n" +
  421. " } \n" +
  422. " out_FragColor = pickColor; \n" +
  423. "} \n";
  424. fs.sources = [pickShader];
  425. }
  426. function getDerivedShaderProgram(
  427. context,
  428. shaderProgram,
  429. derivedShaderProgram,
  430. shaderProgramDirty,
  431. getShaderProgramFunction,
  432. cacheName
  433. ) {
  434. if (!defined(getShaderProgramFunction)) {
  435. return shaderProgram;
  436. }
  437. if (!shaderProgramDirty && defined(derivedShaderProgram)) {
  438. return derivedShaderProgram;
  439. }
  440. let shader = context.shaderCache.getDerivedShaderProgram(
  441. shaderProgram,
  442. cacheName
  443. );
  444. if (!defined(shader)) {
  445. const attributeLocations = shaderProgram._attributeLocations;
  446. const vs = shaderProgram.vertexShaderSource.clone();
  447. const fs = shaderProgram.fragmentShaderSource.clone();
  448. vs.defines = defined(vs.defines) ? vs.defines.slice(0) : [];
  449. fs.defines = defined(fs.defines) ? fs.defines.slice(0) : [];
  450. getShaderProgramFunction(vs, fs);
  451. shader = context.shaderCache.createDerivedShaderProgram(
  452. shaderProgram,
  453. cacheName,
  454. {
  455. vertexShaderSource: vs,
  456. fragmentShaderSource: fs,
  457. attributeLocations: attributeLocations,
  458. }
  459. );
  460. }
  461. return shader;
  462. }
  463. function getOpaqueFrontFaceRenderState(renderState) {
  464. renderState.cull.face = CullFace.BACK;
  465. renderState.cull.enabled = true;
  466. }
  467. function getOpaqueBackFaceRenderState(renderState) {
  468. renderState.cull.face = CullFace.FRONT;
  469. renderState.cull.enabled = true;
  470. }
  471. function getDepthOnlyFrontFaceRenderState(renderState) {
  472. renderState.cull.face = CullFace.BACK;
  473. renderState.cull.enabled = true;
  474. renderState.colorMask = {
  475. red: false,
  476. green: false,
  477. blue: false,
  478. alpha: false,
  479. };
  480. }
  481. function getDepthOnlyBackFaceRenderState(renderState) {
  482. renderState.cull.face = CullFace.FRONT;
  483. renderState.cull.enabled = true;
  484. renderState.colorMask = {
  485. red: false,
  486. green: false,
  487. blue: false,
  488. alpha: false,
  489. };
  490. }
  491. function getDepthOnlyFrontAndBackFaceRenderState(renderState) {
  492. renderState.cull.enabled = false;
  493. renderState.colorMask = {
  494. red: false,
  495. green: false,
  496. blue: false,
  497. alpha: false,
  498. };
  499. }
  500. function getTranslucentFrontFaceRenderState(renderState) {
  501. renderState.cull.face = CullFace.BACK;
  502. renderState.cull.enabled = true;
  503. renderState.depthMask = false;
  504. renderState.blending = BlendingState.ALPHA_BLEND;
  505. }
  506. function getTranslucentBackFaceRenderState(renderState) {
  507. renderState.cull.face = CullFace.FRONT;
  508. renderState.cull.enabled = true;
  509. renderState.depthMask = false;
  510. renderState.blending = BlendingState.ALPHA_BLEND;
  511. }
  512. function getPickFrontFaceRenderState(renderState) {
  513. renderState.cull.face = CullFace.BACK;
  514. renderState.cull.enabled = true;
  515. renderState.blending.enabled = false;
  516. }
  517. function getPickBackFaceRenderState(renderState) {
  518. renderState.cull.face = CullFace.FRONT;
  519. renderState.cull.enabled = true;
  520. renderState.blending.enabled = false;
  521. }
  522. function getDerivedRenderState(
  523. renderState,
  524. derivedRenderState,
  525. renderStateDirty,
  526. getRenderStateFunction,
  527. cache
  528. ) {
  529. if (!defined(getRenderStateFunction)) {
  530. return renderState;
  531. }
  532. if (!renderStateDirty && defined(derivedRenderState)) {
  533. return derivedRenderState;
  534. }
  535. let cachedRenderState = cache[renderState.id];
  536. if (!defined(cachedRenderState)) {
  537. const rs = RenderState.getState(renderState);
  538. getRenderStateFunction(rs);
  539. cachedRenderState = RenderState.fromCache(rs);
  540. cache[renderState.id] = cachedRenderState;
  541. }
  542. return cachedRenderState;
  543. }
  544. function getTranslucencyUniformMap(state) {
  545. return {
  546. u_classificationTexture: function () {
  547. return state._globeTranslucencyFramebuffer.classificationTexture;
  548. },
  549. };
  550. }
  551. function getDerivedUniformMap(
  552. state,
  553. uniformMap,
  554. derivedUniformMap,
  555. uniformMapDirty,
  556. getDerivedUniformMapFunction
  557. ) {
  558. if (!defined(getDerivedUniformMapFunction)) {
  559. return uniformMap;
  560. }
  561. if (!uniformMapDirty && defined(derivedUniformMap)) {
  562. return derivedUniformMap;
  563. }
  564. return combine(uniformMap, getDerivedUniformMapFunction(state), false);
  565. }
  566. function DerivedCommandPack(options) {
  567. this.pass = options.pass;
  568. this.pickOnly = options.pickOnly;
  569. this.getShaderProgramFunction = options.getShaderProgramFunction;
  570. this.getRenderStateFunction = options.getRenderStateFunction;
  571. this.getUniformMapFunction = options.getUniformMapFunction;
  572. this.renderStateCache = {};
  573. }
  574. function createDerivedCommandPacks() {
  575. return [
  576. // opaqueFrontFaceCommand
  577. new DerivedCommandPack({
  578. pass: Pass.GLOBE,
  579. pickOnly: false,
  580. getShaderProgramFunction: getOpaqueFrontFaceShaderProgram,
  581. getRenderStateFunction: getOpaqueFrontFaceRenderState,
  582. getUniformMapFunction: undefined,
  583. }),
  584. // opaqueBackFaceCommand
  585. new DerivedCommandPack({
  586. pass: Pass.GLOBE,
  587. pickOnly: false,
  588. getShaderProgramFunction: getOpaqueBackFaceShaderProgram,
  589. getRenderStateFunction: getOpaqueBackFaceRenderState,
  590. getUniformMapFunction: undefined,
  591. }),
  592. // depthOnlyFrontFaceCommand
  593. new DerivedCommandPack({
  594. pass: Pass.GLOBE,
  595. pickOnly: false,
  596. getShaderProgramFunction: getDepthOnlyShaderProgram,
  597. getRenderStateFunction: getDepthOnlyFrontFaceRenderState,
  598. getUniformMapFunction: undefined,
  599. }),
  600. // depthOnlyBackFaceCommand
  601. new DerivedCommandPack({
  602. pass: Pass.GLOBE,
  603. pickOnly: false,
  604. getShaderProgramFunction: getDepthOnlyShaderProgram,
  605. getRenderStateFunction: getDepthOnlyBackFaceRenderState,
  606. getUniformMapFunction: undefined,
  607. }),
  608. // depthOnlyFrontAndBackFaceCommand
  609. new DerivedCommandPack({
  610. pass: Pass.GLOBE,
  611. pickOnly: false,
  612. getShaderProgramFunction: getDepthOnlyShaderProgram,
  613. getRenderStateFunction: getDepthOnlyFrontAndBackFaceRenderState,
  614. getUniformMapFunction: undefined,
  615. }),
  616. // translucentFrontFaceCommand
  617. new DerivedCommandPack({
  618. pass: Pass.TRANSLUCENT,
  619. pickOnly: false,
  620. getShaderProgramFunction: getTranslucentShaderProgram,
  621. getRenderStateFunction: getTranslucentFrontFaceRenderState,
  622. getUniformMapFunction: getTranslucencyUniformMap,
  623. }),
  624. // translucentBackFaceCommand
  625. new DerivedCommandPack({
  626. pass: Pass.TRANSLUCENT,
  627. pickOnly: false,
  628. getShaderProgramFunction: getTranslucentBackFaceShaderProgram,
  629. getRenderStateFunction: getTranslucentBackFaceRenderState,
  630. getUniformMapFunction: getTranslucencyUniformMap,
  631. }),
  632. // translucentFrontFaceManualDepthTestCommand
  633. new DerivedCommandPack({
  634. pass: Pass.TRANSLUCENT,
  635. pickOnly: false,
  636. getShaderProgramFunction: getTranslucentFrontFaceManualDepthTestShaderProgram,
  637. getRenderStateFunction: getTranslucentFrontFaceRenderState,
  638. getUniformMapFunction: getTranslucencyUniformMap,
  639. }),
  640. // translucentBackFaceManualDepthTestCommand
  641. new DerivedCommandPack({
  642. pass: Pass.TRANSLUCENT,
  643. pickOnly: false,
  644. getShaderProgramFunction: getTranslucentBackFaceManualDepthTestShaderProgram,
  645. getRenderStateFunction: getTranslucentBackFaceRenderState,
  646. getUniformMapFunction: getTranslucencyUniformMap,
  647. }),
  648. // pickFrontFaceCommand
  649. new DerivedCommandPack({
  650. pass: Pass.TRANSLUCENT,
  651. pickOnly: true,
  652. getShaderProgramFunction: getPickShaderProgram,
  653. getRenderStateFunction: getPickFrontFaceRenderState,
  654. getUniformMapFunction: getTranslucencyUniformMap,
  655. }),
  656. // pickBackFaceCommand
  657. new DerivedCommandPack({
  658. pass: Pass.TRANSLUCENT,
  659. pickOnly: true,
  660. getShaderProgramFunction: getPickShaderProgram,
  661. getRenderStateFunction: getPickBackFaceRenderState,
  662. getUniformMapFunction: getTranslucencyUniformMap,
  663. }),
  664. ];
  665. }
  666. const derivedCommandNames = new Array(derivedCommandsMaximumLength);
  667. const derivedCommandPacks = new Array(derivedCommandsMaximumLength);
  668. GlobeTranslucencyState.prototype.updateDerivedCommands = function (
  669. command,
  670. frameState
  671. ) {
  672. const derivedCommandTypes = this._derivedCommandTypesToUpdate;
  673. const derivedCommandsLength = this._derivedCommandsToUpdateLength;
  674. if (derivedCommandsLength === 0) {
  675. return;
  676. }
  677. for (let i = 0; i < derivedCommandsLength; ++i) {
  678. derivedCommandPacks[i] = this._derivedCommandPacks[derivedCommandTypes[i]];
  679. derivedCommandNames[i] = DerivedCommandNames[derivedCommandTypes[i]];
  680. }
  681. updateDerivedCommands(
  682. this,
  683. command,
  684. derivedCommandsLength,
  685. derivedCommandTypes,
  686. derivedCommandNames,
  687. derivedCommandPacks,
  688. frameState
  689. );
  690. };
  691. function updateDerivedCommands(
  692. state,
  693. command,
  694. derivedCommandsLength,
  695. derivedCommandTypes,
  696. derivedCommandNames,
  697. derivedCommandPacks,
  698. frameState
  699. ) {
  700. let derivedCommandsObject = command.derivedCommands.globeTranslucency;
  701. const derivedCommandsDirty = state._derivedCommandsDirty;
  702. if (
  703. command.dirty ||
  704. !defined(derivedCommandsObject) ||
  705. derivedCommandsDirty
  706. ) {
  707. command.dirty = false;
  708. if (!defined(derivedCommandsObject)) {
  709. derivedCommandsObject = {};
  710. command.derivedCommands.globeTranslucency = derivedCommandsObject;
  711. }
  712. const frameNumber = frameState.frameNumber;
  713. const uniformMapDirtyFrame = defaultValue(
  714. derivedCommandsObject.uniformMapDirtyFrame,
  715. 0
  716. );
  717. const shaderProgramDirtyFrame = defaultValue(
  718. derivedCommandsObject.shaderProgramDirtyFrame,
  719. 0
  720. );
  721. const renderStateDirtyFrame = defaultValue(
  722. derivedCommandsObject.renderStateDirtyFrame,
  723. 0
  724. );
  725. const uniformMapDirty =
  726. derivedCommandsObject.uniformMap !== command.uniformMap;
  727. const shaderProgramDirty =
  728. derivedCommandsObject.shaderProgramId !== command.shaderProgram.id;
  729. const renderStateDirty =
  730. derivedCommandsObject.renderStateId !== command.renderState.id;
  731. if (uniformMapDirty) {
  732. derivedCommandsObject.uniformMapDirtyFrame = frameNumber;
  733. }
  734. if (shaderProgramDirty) {
  735. derivedCommandsObject.shaderProgramDirtyFrame = frameNumber;
  736. }
  737. if (renderStateDirty) {
  738. derivedCommandsObject.renderStateDirtyFrame = frameNumber;
  739. }
  740. derivedCommandsObject.uniformMap = command.uniformMap;
  741. derivedCommandsObject.shaderProgramId = command.shaderProgram.id;
  742. derivedCommandsObject.renderStateId = command.renderState.id;
  743. for (let i = 0; i < derivedCommandsLength; ++i) {
  744. const derivedCommandPack = derivedCommandPacks[i];
  745. const derivedCommandType = derivedCommandTypes[i];
  746. const derivedCommandName = derivedCommandNames[i];
  747. let derivedCommand = derivedCommandsObject[derivedCommandName];
  748. let derivedUniformMap;
  749. let derivedShaderProgram;
  750. let derivedRenderState;
  751. if (defined(derivedCommand)) {
  752. derivedUniformMap = derivedCommand.uniformMap;
  753. derivedShaderProgram = derivedCommand.shaderProgram;
  754. derivedRenderState = derivedCommand.renderState;
  755. } else {
  756. derivedUniformMap = undefined;
  757. derivedShaderProgram = undefined;
  758. derivedRenderState = undefined;
  759. }
  760. derivedCommand = DrawCommand.shallowClone(command, derivedCommand);
  761. derivedCommandsObject[derivedCommandName] = derivedCommand;
  762. const derivedUniformMapDirtyFrame = defaultValue(
  763. derivedCommand.derivedCommands.uniformMapDirtyFrame,
  764. 0
  765. );
  766. const derivedShaderProgramDirtyFrame = defaultValue(
  767. derivedCommand.derivedCommands.shaderProgramDirtyFrame,
  768. 0
  769. );
  770. const derivedRenderStateDirtyFrame = defaultValue(
  771. derivedCommand.derivedCommands.renderStateDirtyFrame,
  772. 0
  773. );
  774. const derivedUniformMapDirty =
  775. uniformMapDirty || derivedUniformMapDirtyFrame < uniformMapDirtyFrame;
  776. const derivedShaderProgramDirty =
  777. shaderProgramDirty ||
  778. derivedShaderProgramDirtyFrame < shaderProgramDirtyFrame;
  779. const derivedRenderStateDirty =
  780. renderStateDirty ||
  781. derivedRenderStateDirtyFrame < renderStateDirtyFrame;
  782. if (derivedUniformMapDirty) {
  783. derivedCommand.derivedCommands.uniformMapDirtyFrame = frameNumber;
  784. }
  785. if (derivedShaderProgramDirty) {
  786. derivedCommand.derivedCommands.shaderProgramDirtyFrame = frameNumber;
  787. }
  788. if (derivedRenderStateDirty) {
  789. derivedCommand.derivedCommands.renderStateDirtyFrame = frameNumber;
  790. }
  791. derivedCommand.derivedCommands.type = derivedCommandType;
  792. derivedCommand.pass = derivedCommandPack.pass;
  793. derivedCommand.pickOnly = derivedCommandPack.pickOnly;
  794. derivedCommand.uniformMap = getDerivedUniformMap(
  795. state,
  796. command.uniformMap,
  797. derivedUniformMap,
  798. derivedUniformMapDirty,
  799. derivedCommandPack.getUniformMapFunction
  800. );
  801. derivedCommand.shaderProgram = getDerivedShaderProgram(
  802. frameState.context,
  803. command.shaderProgram,
  804. derivedShaderProgram,
  805. derivedShaderProgramDirty,
  806. derivedCommandPack.getShaderProgramFunction,
  807. derivedCommandName
  808. );
  809. derivedCommand.renderState = getDerivedRenderState(
  810. command.renderState,
  811. derivedRenderState,
  812. derivedRenderStateDirty,
  813. derivedCommandPack.getRenderStateFunction,
  814. derivedCommandPack.renderStateCache
  815. );
  816. }
  817. }
  818. }
  819. GlobeTranslucencyState.prototype.pushDerivedCommands = function (
  820. command,
  821. isBlendCommand,
  822. frameState
  823. ) {
  824. const picking = frameState.passes.pick;
  825. if (picking && isBlendCommand) {
  826. // No need to push blend commands in the pick pass
  827. return;
  828. }
  829. let derivedCommandTypes = this._derivedCommandTypes;
  830. let derivedCommandsLength = this._derivedCommandsLength;
  831. if (picking) {
  832. derivedCommandTypes = this._derivedPickCommandTypes;
  833. derivedCommandsLength = this._derivedPickCommandsLength;
  834. } else if (isBlendCommand) {
  835. derivedCommandTypes = this._derivedBlendCommandTypes;
  836. derivedCommandsLength = this._derivedBlendCommandsLength;
  837. }
  838. if (derivedCommandsLength === 0) {
  839. // No derived commands to push so just push the globe command
  840. frameState.commandList.push(command);
  841. return;
  842. }
  843. // Push derived commands
  844. const derivedCommands = command.derivedCommands.globeTranslucency;
  845. for (let i = 0; i < derivedCommandsLength; ++i) {
  846. const derivedCommandName = DerivedCommandNames[derivedCommandTypes[i]];
  847. frameState.commandList.push(derivedCommands[derivedCommandName]);
  848. }
  849. };
  850. function executeCommandsMatchingType(
  851. commands,
  852. commandsLength,
  853. executeCommandFunction,
  854. scene,
  855. context,
  856. passState,
  857. types
  858. ) {
  859. for (let i = 0; i < commandsLength; ++i) {
  860. const command = commands[i];
  861. const type = command.derivedCommands.type;
  862. if (!defined(types) || types.indexOf(type) > -1) {
  863. executeCommandFunction(command, scene, context, passState);
  864. }
  865. }
  866. }
  867. function executeCommands(
  868. commands,
  869. commandsLength,
  870. executeCommandFunction,
  871. scene,
  872. context,
  873. passState
  874. ) {
  875. for (let i = 0; i < commandsLength; ++i) {
  876. executeCommandFunction(commands[i], scene, context, passState);
  877. }
  878. }
  879. const opaqueTypes = [
  880. DerivedCommandType.OPAQUE_FRONT_FACE,
  881. DerivedCommandType.OPAQUE_BACK_FACE,
  882. ];
  883. const depthOnlyTypes = [
  884. DerivedCommandType.DEPTH_ONLY_FRONT_FACE,
  885. DerivedCommandType.DEPTH_ONLY_BACK_FACE,
  886. DerivedCommandType.DEPTH_ONLY_FRONT_AND_BACK_FACE,
  887. ];
  888. GlobeTranslucencyState.prototype.executeGlobeCommands = function (
  889. frustumCommands,
  890. executeCommandFunction,
  891. globeTranslucencyFramebuffer,
  892. scene,
  893. passState
  894. ) {
  895. const context = scene.context;
  896. const globeCommands = frustumCommands.commands[Pass.GLOBE];
  897. const globeCommandsLength = frustumCommands.indices[Pass.GLOBE];
  898. if (globeCommandsLength === 0) {
  899. return;
  900. }
  901. this._globeTranslucencyFramebuffer = globeTranslucencyFramebuffer;
  902. globeTranslucencyFramebuffer.clearClassification(context, passState);
  903. // Render opaque commands like normal
  904. executeCommandsMatchingType(
  905. globeCommands,
  906. globeCommandsLength,
  907. executeCommandFunction,
  908. scene,
  909. context,
  910. passState,
  911. opaqueTypes
  912. );
  913. };
  914. GlobeTranslucencyState.prototype.executeGlobeClassificationCommands = function (
  915. frustumCommands,
  916. executeCommandFunction,
  917. globeTranslucencyFramebuffer,
  918. scene,
  919. passState
  920. ) {
  921. const context = scene.context;
  922. const globeCommands = frustumCommands.commands[Pass.GLOBE];
  923. const globeCommandsLength = frustumCommands.indices[Pass.GLOBE];
  924. const classificationCommands =
  925. frustumCommands.commands[Pass.TERRAIN_CLASSIFICATION];
  926. const classificationCommandsLength =
  927. frustumCommands.indices[Pass.TERRAIN_CLASSIFICATION];
  928. if (globeCommandsLength === 0 || classificationCommandsLength === 0) {
  929. return;
  930. }
  931. const frontTranslucent = this._frontFaceTranslucent;
  932. const backTranslucent = this._backFaceTranslucent;
  933. if (!frontTranslucent || !backTranslucent) {
  934. // Render classification on opaque faces like normal
  935. executeCommands(
  936. classificationCommands,
  937. classificationCommandsLength,
  938. executeCommandFunction,
  939. scene,
  940. context,
  941. passState
  942. );
  943. }
  944. if (!frontTranslucent && !backTranslucent) {
  945. // No translucent commands to render. Skip translucent classification.
  946. return;
  947. }
  948. this._globeTranslucencyFramebuffer = globeTranslucencyFramebuffer;
  949. const originalGlobeDepthTexture = context.uniformState.globeDepthTexture;
  950. const originalFramebuffer = passState.framebuffer;
  951. // Render to internal framebuffer and get the first depth peel
  952. passState.framebuffer =
  953. globeTranslucencyFramebuffer.classificationFramebuffer;
  954. executeCommandsMatchingType(
  955. globeCommands,
  956. globeCommandsLength,
  957. executeCommandFunction,
  958. scene,
  959. context,
  960. passState,
  961. depthOnlyTypes
  962. );
  963. if (context.depthTexture) {
  964. // Pack depth into separate texture for ground polylines and textured ground primitives
  965. const packedDepthTexture = globeTranslucencyFramebuffer.packDepth(
  966. context,
  967. passState
  968. );
  969. context.uniformState.globeDepthTexture = packedDepthTexture;
  970. }
  971. // Render classification on translucent faces
  972. executeCommands(
  973. classificationCommands,
  974. classificationCommandsLength,
  975. executeCommandFunction,
  976. scene,
  977. context,
  978. passState
  979. );
  980. // Unset temporary state
  981. context.uniformState.globeDepthTexture = originalGlobeDepthTexture;
  982. passState.framebuffer = originalFramebuffer;
  983. };
  984. export default GlobeTranslucencyState;