TranslucentTileClassification.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. import BoundingRectangle from "../Core/BoundingRectangle.js";
  2. import Color from "../Core/Color.js";
  3. import defined from "../Core/defined.js";
  4. import destroyObject from "../Core/destroyObject.js";
  5. import PixelFormat from "../Core/PixelFormat.js";
  6. import ClearCommand from "../Renderer/ClearCommand.js";
  7. import DrawCommand from "../Renderer/DrawCommand.js";
  8. import FramebufferManager from "../Renderer/FramebufferManager.js";
  9. import Pass from "../Renderer/Pass.js";
  10. import PixelDatatype from "../Renderer/PixelDatatype.js";
  11. import RenderState from "../Renderer/RenderState.js";
  12. import Sampler from "../Renderer/Sampler.js";
  13. import ShaderSource from "../Renderer/ShaderSource.js";
  14. import Texture from "../Renderer/Texture.js";
  15. import CompareAndPackTranslucentDepth from "../Shaders/CompareAndPackTranslucentDepth.js";
  16. import CompositeTranslucentClassification from "../Shaders/PostProcessStages/CompositeTranslucentClassification.js";
  17. import BlendingState from "./BlendingState.js";
  18. import StencilConstants from "./StencilConstants.js";
  19. import StencilFunction from "./StencilFunction.js";
  20. const debugShowPackedDepth = false;
  21. /**
  22. * Handles buffers, drawing, and deriving commands needed for classifying translucent 3D Tiles.
  23. * Uses a depth texture, so classification on translucent 3D Tiles is not available in Internet Explorer.
  24. *
  25. * @private
  26. */
  27. function TranslucentTileClassification(context) {
  28. this._drawClassificationFBO = new FramebufferManager({
  29. createDepthAttachments: false,
  30. });
  31. this._accumulationFBO = new FramebufferManager({
  32. createDepthAttachments: false,
  33. });
  34. this._packFBO = new FramebufferManager();
  35. this._opaqueDepthStencilTexture = undefined;
  36. // Reference to either colorTexture or accumulationTexture
  37. this._textureToComposite = undefined;
  38. this._translucentDepthStencilTexture = undefined;
  39. this._packDepthCommand = undefined;
  40. this._accumulateCommand = undefined;
  41. this._compositeCommand = undefined;
  42. this._copyCommand = undefined;
  43. this._clearColorCommand = new ClearCommand({
  44. color: new Color(0.0, 0.0, 0.0, 0.0),
  45. owner: this,
  46. });
  47. this._clearDepthStencilCommand = new ClearCommand({
  48. depth: 1.0,
  49. stencil: 0,
  50. owner: this,
  51. });
  52. this._supported = context.depthTexture;
  53. this._viewport = new BoundingRectangle();
  54. this._rsDepth = undefined;
  55. this._rsAccumulate = undefined;
  56. this._rsComp = undefined;
  57. this._useScissorTest = undefined;
  58. this._scissorRectangle = undefined;
  59. this._hasTranslucentDepth = false;
  60. this._frustumsDrawn = 0;
  61. }
  62. Object.defineProperties(TranslucentTileClassification.prototype, {
  63. /**
  64. * Gets whether or not translucent depth was rendered.
  65. * @memberof TranslucentTileClassification.prototype
  66. *
  67. * @type {Boolean}
  68. * @readonly
  69. */
  70. hasTranslucentDepth: {
  71. get: function () {
  72. return this._hasTranslucentDepth;
  73. },
  74. },
  75. });
  76. function destroyTextures(transpClass) {
  77. transpClass._textureToComposite = undefined;
  78. transpClass._translucentDepthStencilTexture =
  79. transpClass._translucentDepthStencilTexture &&
  80. !transpClass._translucentDepthStencilTexture.isDestroyed() &&
  81. transpClass._translucentDepthStencilTexture.destroy();
  82. }
  83. function destroyFramebuffers(transpClass) {
  84. transpClass._drawClassificationFBO.destroy();
  85. transpClass._accumulationFBO.destroy();
  86. transpClass._packFBO.destroy();
  87. }
  88. function updateTextures(transpClass, context, width, height) {
  89. destroyTextures(transpClass);
  90. transpClass._translucentDepthStencilTexture = new Texture({
  91. context: context,
  92. width: width,
  93. height: height,
  94. pixelFormat: PixelFormat.DEPTH_STENCIL,
  95. pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
  96. sampler: Sampler.NEAREST,
  97. });
  98. }
  99. function updateFramebuffers(transpClass, context, width, height) {
  100. destroyFramebuffers(transpClass);
  101. transpClass._drawClassificationFBO.setDepthStencilTexture(
  102. transpClass._translucentDepthStencilTexture
  103. );
  104. transpClass._drawClassificationFBO.update(context, width, height);
  105. transpClass._accumulationFBO.setDepthStencilTexture(
  106. transpClass._translucentDepthStencilTexture
  107. );
  108. transpClass._accumulationFBO.update(context, width, height);
  109. transpClass._packFBO.update(context, width, height);
  110. }
  111. function updateResources(
  112. transpClass,
  113. context,
  114. passState,
  115. globeDepthStencilTexture
  116. ) {
  117. if (!transpClass.isSupported()) {
  118. return;
  119. }
  120. transpClass._opaqueDepthStencilTexture = globeDepthStencilTexture;
  121. const width = transpClass._opaqueDepthStencilTexture.width;
  122. const height = transpClass._opaqueDepthStencilTexture.height;
  123. if (transpClass._drawClassificationFBO.isDirty(width, height)) {
  124. updateTextures(transpClass, context, width, height);
  125. updateFramebuffers(transpClass, context, width, height);
  126. }
  127. let fs;
  128. let uniformMap;
  129. if (!defined(transpClass._packDepthCommand)) {
  130. fs = new ShaderSource({
  131. sources: [CompareAndPackTranslucentDepth],
  132. });
  133. uniformMap = {
  134. u_opaqueDepthTexture: function () {
  135. return transpClass._opaqueDepthStencilTexture;
  136. },
  137. u_translucentDepthTexture: function () {
  138. return transpClass._translucentDepthStencilTexture;
  139. },
  140. };
  141. transpClass._packDepthCommand = context.createViewportQuadCommand(fs, {
  142. uniformMap: uniformMap,
  143. owner: transpClass,
  144. });
  145. }
  146. if (!defined(transpClass._compositeCommand)) {
  147. fs = new ShaderSource({
  148. sources: [CompositeTranslucentClassification],
  149. });
  150. uniformMap = {
  151. colorTexture: function () {
  152. return transpClass._textureToComposite;
  153. },
  154. };
  155. if (debugShowPackedDepth) {
  156. fs.defines = ["DEBUG_SHOW_DEPTH"];
  157. uniformMap.u_packedTranslucentDepth = function () {
  158. return transpClass._packFBO.getColorTexture();
  159. };
  160. }
  161. transpClass._compositeCommand = context.createViewportQuadCommand(fs, {
  162. uniformMap: uniformMap,
  163. owner: transpClass,
  164. });
  165. const compositeCommand = transpClass._compositeCommand;
  166. const compositeProgram = compositeCommand.shaderProgram;
  167. const compositePickProgram = context.shaderCache.createDerivedShaderProgram(
  168. compositeProgram,
  169. "pick",
  170. {
  171. vertexShaderSource: compositeProgram.vertexShaderSource,
  172. fragmentShaderSource: new ShaderSource({
  173. sources: fs.sources,
  174. defines: ["PICK"],
  175. }),
  176. attributeLocations: compositeProgram._attributeLocations,
  177. }
  178. );
  179. const compositePickCommand = DrawCommand.shallowClone(compositeCommand);
  180. compositePickCommand.shaderProgram = compositePickProgram;
  181. compositeCommand.derivedCommands.pick = compositePickCommand;
  182. }
  183. if (!defined(transpClass._copyCommand)) {
  184. fs = new ShaderSource({
  185. sources: [CompositeTranslucentClassification],
  186. });
  187. uniformMap = {
  188. colorTexture: function () {
  189. return transpClass._drawClassificationFBO.getColorTexture();
  190. },
  191. };
  192. transpClass._copyCommand = context.createViewportQuadCommand(fs, {
  193. uniformMap: uniformMap,
  194. owner: transpClass,
  195. });
  196. }
  197. if (!defined(transpClass._accumulateCommand)) {
  198. fs = new ShaderSource({
  199. sources: [CompositeTranslucentClassification],
  200. });
  201. uniformMap = {
  202. colorTexture: function () {
  203. return transpClass._drawClassificationFBO.getColorTexture();
  204. },
  205. };
  206. transpClass._accumulateCommand = context.createViewportQuadCommand(fs, {
  207. uniformMap: uniformMap,
  208. owner: transpClass,
  209. });
  210. }
  211. transpClass._viewport.width = width;
  212. transpClass._viewport.height = height;
  213. const useScissorTest = !BoundingRectangle.equals(
  214. transpClass._viewport,
  215. passState.viewport
  216. );
  217. let updateScissor = useScissorTest !== transpClass._useScissorTest;
  218. transpClass._useScissorTest = useScissorTest;
  219. if (
  220. !BoundingRectangle.equals(transpClass._scissorRectangle, passState.viewport)
  221. ) {
  222. transpClass._scissorRectangle = BoundingRectangle.clone(
  223. passState.viewport,
  224. transpClass._scissorRectangle
  225. );
  226. updateScissor = true;
  227. }
  228. if (
  229. !defined(transpClass._rsDepth) ||
  230. !BoundingRectangle.equals(
  231. transpClass._viewport,
  232. transpClass._rsDepth.viewport
  233. ) ||
  234. updateScissor
  235. ) {
  236. transpClass._rsDepth = RenderState.fromCache({
  237. viewport: transpClass._viewport,
  238. scissorTest: {
  239. enabled: transpClass._useScissorTest,
  240. rectangle: transpClass._scissorRectangle,
  241. },
  242. });
  243. }
  244. if (defined(transpClass._packDepthCommand)) {
  245. transpClass._packDepthCommand.renderState = transpClass._rsDepth;
  246. }
  247. if (
  248. !defined(transpClass._rsAccumulate) ||
  249. !BoundingRectangle.equals(
  250. transpClass._viewport,
  251. transpClass._rsAccumulate.viewport
  252. ) ||
  253. updateScissor
  254. ) {
  255. transpClass._rsAccumulate = RenderState.fromCache({
  256. viewport: transpClass._viewport,
  257. scissorTest: {
  258. enabled: transpClass._useScissorTest,
  259. rectangle: transpClass._scissorRectangle,
  260. },
  261. stencilTest: {
  262. enabled: true,
  263. frontFunction: StencilFunction.EQUAL,
  264. reference: StencilConstants.CESIUM_3D_TILE_MASK,
  265. },
  266. });
  267. }
  268. if (defined(transpClass._accumulateCommand)) {
  269. transpClass._accumulateCommand.renderState = transpClass._rsAccumulate;
  270. }
  271. if (
  272. !defined(transpClass._rsComp) ||
  273. !BoundingRectangle.equals(
  274. transpClass._viewport,
  275. transpClass._rsComp.viewport
  276. ) ||
  277. updateScissor
  278. ) {
  279. transpClass._rsComp = RenderState.fromCache({
  280. viewport: transpClass._viewport,
  281. scissorTest: {
  282. enabled: transpClass._useScissorTest,
  283. rectangle: transpClass._scissorRectangle,
  284. },
  285. blending: BlendingState.ALPHA_BLEND,
  286. });
  287. }
  288. if (defined(transpClass._compositeCommand)) {
  289. transpClass._compositeCommand.renderState = transpClass._rsComp;
  290. transpClass._compositeCommand.derivedCommands.pick.renderState =
  291. transpClass._rsComp;
  292. }
  293. }
  294. TranslucentTileClassification.prototype.executeTranslucentCommands = function (
  295. scene,
  296. executeCommand,
  297. passState,
  298. commands,
  299. globeDepthStencilTexture
  300. ) {
  301. // Check for translucent commands that should be classified
  302. const length = commands.length;
  303. let command;
  304. let i;
  305. const useLogDepth = scene.frameState.useLogDepth;
  306. const context = scene.context;
  307. const framebuffer = passState.framebuffer;
  308. for (i = 0; i < length; ++i) {
  309. command = commands[i];
  310. command = useLogDepth ? command.derivedCommands.logDepth.command : command;
  311. if (command.depthForTranslucentClassification) {
  312. this._hasTranslucentDepth = true;
  313. break;
  314. }
  315. }
  316. if (!this._hasTranslucentDepth) {
  317. return;
  318. }
  319. updateResources(this, context, passState, globeDepthStencilTexture);
  320. // Get translucent depth
  321. passState.framebuffer = this._drawClassificationFBO.framebuffer;
  322. // Clear depth for multifrustum
  323. this._clearDepthStencilCommand.execute(context, passState);
  324. for (i = 0; i < length; ++i) {
  325. command = commands[i];
  326. command = useLogDepth ? command.derivedCommands.logDepth.command : command;
  327. if (!command.depthForTranslucentClassification) {
  328. continue;
  329. }
  330. // Depth-only commands are created for all translucent 3D Tiles commands
  331. const depthOnlyCommand = command.derivedCommands.depth.depthOnlyCommand;
  332. executeCommand(depthOnlyCommand, scene, context, passState);
  333. }
  334. this._frustumsDrawn += this._hasTranslucentDepth ? 1 : 0;
  335. // Pack depth if any translucent depth commands were performed
  336. if (this._hasTranslucentDepth) {
  337. passState.framebuffer = this._packFBO.framebuffer;
  338. this._packDepthCommand.execute(context, passState);
  339. }
  340. passState.framebuffer = framebuffer;
  341. };
  342. TranslucentTileClassification.prototype.executeClassificationCommands = function (
  343. scene,
  344. executeCommand,
  345. passState,
  346. frustumCommands
  347. ) {
  348. if (!this._hasTranslucentDepth) {
  349. return;
  350. }
  351. const context = scene.context;
  352. const us = context.uniformState;
  353. const framebuffer = passState.framebuffer;
  354. if (this._frustumsDrawn === 2) {
  355. // copy classification from first frustum
  356. passState.framebuffer = this._accumulationFBO.framebuffer;
  357. this._copyCommand.execute(context, passState);
  358. }
  359. passState.framebuffer = this._drawClassificationFBO.framebuffer;
  360. if (this._frustumsDrawn > 1) {
  361. this._clearColorCommand.execute(context, passState);
  362. }
  363. us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION);
  364. const swapGlobeDepth = us.globeDepthTexture;
  365. us.globeDepthTexture = this._packFBO.getColorTexture();
  366. const commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION];
  367. const length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION];
  368. for (let i = 0; i < length; ++i) {
  369. executeCommand(commands[i], scene, context, passState);
  370. }
  371. us.globeDepthTexture = swapGlobeDepth;
  372. passState.framebuffer = framebuffer;
  373. if (this._frustumsDrawn === 1) {
  374. return;
  375. }
  376. passState.framebuffer = this._accumulationFBO.framebuffer;
  377. this._accumulateCommand.execute(context, passState);
  378. passState.framebuffer = framebuffer;
  379. };
  380. TranslucentTileClassification.prototype.execute = function (scene, passState) {
  381. if (!this._hasTranslucentDepth) {
  382. return;
  383. }
  384. if (this._frustumsDrawn === 1) {
  385. this._textureToComposite = this._drawClassificationFBO.getColorTexture();
  386. } else {
  387. this._textureToComposite = this._accumulationFBO.getColorTexture();
  388. }
  389. const command = scene.frameState.passes.pick
  390. ? this._compositeCommand.derivedCommands.pick
  391. : this._compositeCommand;
  392. command.execute(scene.context, passState);
  393. clear(this, scene, passState);
  394. };
  395. function clear(translucentTileClassification, scene, passState) {
  396. if (!translucentTileClassification._hasTranslucentDepth) {
  397. return;
  398. }
  399. const framebuffer = passState.framebuffer;
  400. passState.framebuffer =
  401. translucentTileClassification._drawClassificationFBO.framebuffer;
  402. translucentTileClassification._clearColorCommand.execute(
  403. scene._context,
  404. passState
  405. );
  406. passState.framebuffer = framebuffer;
  407. if (translucentTileClassification._frustumsDrawn > 1) {
  408. passState.framebuffer =
  409. translucentTileClassification._accumulationFBO.framebuffer;
  410. translucentTileClassification._clearColorCommand.execute(
  411. scene._context,
  412. passState
  413. );
  414. }
  415. translucentTileClassification._hasTranslucentDepth = false;
  416. translucentTileClassification._frustumsDrawn = 0;
  417. }
  418. TranslucentTileClassification.prototype.isSupported = function () {
  419. return this._supported;
  420. };
  421. TranslucentTileClassification.prototype.isDestroyed = function () {
  422. return false;
  423. };
  424. TranslucentTileClassification.prototype.destroy = function () {
  425. destroyTextures(this);
  426. destroyFramebuffers(this);
  427. if (defined(this._compositeCommand)) {
  428. this._compositeCommand.shaderProgram =
  429. this._compositeCommand.shaderProgram &&
  430. this._compositeCommand.shaderProgram.destroy();
  431. }
  432. if (defined(this._packDepthCommand)) {
  433. this._packDepthCommand.shaderProgram =
  434. this._packDepthCommand.shaderProgram &&
  435. this._packDepthCommand.shaderProgram.destroy();
  436. }
  437. return destroyObject(this);
  438. };
  439. export default TranslucentTileClassification;