OIT.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  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 WebGLConstants from "../Core/WebGLConstants.js";
  7. import ClearCommand from "../Renderer/ClearCommand.js";
  8. import DrawCommand from "../Renderer/DrawCommand.js";
  9. import FramebufferManager from "../Renderer/FramebufferManager.js";
  10. import PixelDatatype from "../Renderer/PixelDatatype.js";
  11. import RenderState from "../Renderer/RenderState.js";
  12. import ShaderSource from "../Renderer/ShaderSource.js";
  13. import Texture from "../Renderer/Texture.js";
  14. import AdjustTranslucentFS from "../Shaders/AdjustTranslucentFS.js";
  15. import CompositeOITFS from "../Shaders/CompositeOITFS.js";
  16. import BlendEquation from "./BlendEquation.js";
  17. import BlendFunction from "./BlendFunction.js";
  18. /**
  19. * @private
  20. * @constructor
  21. * @param {Context} context
  22. */
  23. function OIT(context) {
  24. this._numSamples = 1;
  25. // We support multipass for the Chrome D3D9 backend and ES 2.0 on mobile.
  26. this._translucentMultipassSupport = false;
  27. this._translucentMRTSupport = false;
  28. const extensionsSupported =
  29. context.colorBufferFloat && context.depthTexture && context.floatBlend;
  30. this._translucentMRTSupport = context.drawBuffers && extensionsSupported;
  31. this._translucentMultipassSupport =
  32. !this._translucentMRTSupport && extensionsSupported;
  33. this._opaqueFBO = undefined;
  34. this._opaqueTexture = undefined;
  35. this._depthStencilTexture = undefined;
  36. this._accumulationTexture = undefined;
  37. this._translucentFBO = new FramebufferManager({
  38. colorAttachmentsLength: this._translucentMRTSupport ? 2 : 1,
  39. createColorAttachments: false,
  40. createDepthAttachments: false,
  41. depth: true,
  42. });
  43. this._alphaFBO = new FramebufferManager({
  44. createColorAttachments: false,
  45. createDepthAttachments: false,
  46. depth: true,
  47. });
  48. this._adjustTranslucentFBO = new FramebufferManager({
  49. colorAttachmentsLength: this._translucentMRTSupport ? 2 : 1,
  50. createColorAttachments: false,
  51. });
  52. this._adjustAlphaFBO = new FramebufferManager({
  53. createColorAttachments: false,
  54. });
  55. this._opaqueClearCommand = new ClearCommand({
  56. color: new Color(0.0, 0.0, 0.0, 0.0),
  57. owner: this,
  58. });
  59. this._translucentMRTClearCommand = new ClearCommand({
  60. color: new Color(0.0, 0.0, 0.0, 1.0),
  61. owner: this,
  62. });
  63. this._translucentMultipassClearCommand = new ClearCommand({
  64. color: new Color(0.0, 0.0, 0.0, 0.0),
  65. owner: this,
  66. });
  67. this._alphaClearCommand = new ClearCommand({
  68. color: new Color(1.0, 1.0, 1.0, 1.0),
  69. owner: this,
  70. });
  71. this._translucentRenderStateCache = {};
  72. this._alphaRenderStateCache = {};
  73. this._compositeCommand = undefined;
  74. this._adjustTranslucentCommand = undefined;
  75. this._adjustAlphaCommand = undefined;
  76. this._viewport = new BoundingRectangle();
  77. this._rs = undefined;
  78. this._useScissorTest = false;
  79. this._scissorRectangle = undefined;
  80. this._useHDR = false;
  81. }
  82. /**
  83. * @private
  84. * @param {OIT} oit
  85. */
  86. function destroyTextures(oit) {
  87. oit._accumulationTexture =
  88. oit._accumulationTexture &&
  89. !oit._accumulationTexture.isDestroyed() &&
  90. oit._accumulationTexture.destroy();
  91. oit._revealageTexture =
  92. oit._revealageTexture &&
  93. !oit._revealageTexture.isDestroyed() &&
  94. oit._revealageTexture.destroy();
  95. }
  96. /**
  97. * @private
  98. * @param {OIT} oit
  99. */
  100. function destroyFramebuffers(oit) {
  101. oit._translucentFBO.destroy();
  102. oit._alphaFBO.destroy();
  103. oit._adjustTranslucentFBO.destroy();
  104. oit._adjustAlphaFBO.destroy();
  105. }
  106. /**
  107. * @private
  108. * @param {OIT} oit
  109. */
  110. function destroyResources(oit) {
  111. destroyTextures(oit);
  112. destroyFramebuffers(oit);
  113. }
  114. /**
  115. * @private
  116. * @param {OIT} oit
  117. * @param {Context} context
  118. * @param {number} width
  119. * @param {number} height
  120. */
  121. function updateTextures(oit, context, width, height) {
  122. destroyTextures(oit);
  123. oit._accumulationTexture = new Texture({
  124. context: context,
  125. width: width,
  126. height: height,
  127. pixelFormat: PixelFormat.RGBA,
  128. pixelDatatype: PixelDatatype.FLOAT,
  129. });
  130. // Use zeroed arraybuffer instead of null to initialize texture
  131. // to workaround Firefox. Only needed for the second color attachment.
  132. const source = new Float32Array(width * height * 4);
  133. oit._revealageTexture = new Texture({
  134. context: context,
  135. pixelFormat: PixelFormat.RGBA,
  136. pixelDatatype: PixelDatatype.FLOAT,
  137. source: {
  138. arrayBufferView: source,
  139. width: width,
  140. height: height,
  141. },
  142. flipY: false,
  143. });
  144. }
  145. /**
  146. * @private
  147. * @param {OIT} oit
  148. * @param {Context} context
  149. * @returns {boolean}
  150. */
  151. function updateFramebuffers(oit, context) {
  152. destroyFramebuffers(oit);
  153. const completeFBO = WebGLConstants.FRAMEBUFFER_COMPLETE;
  154. let supported = true;
  155. const { width, height } = oit._accumulationTexture;
  156. // if MRT is supported, attempt to make an FBO with multiple color attachments
  157. if (oit._translucentMRTSupport) {
  158. oit._translucentFBO.setColorTexture(oit._accumulationTexture, 0);
  159. oit._translucentFBO.setColorTexture(oit._revealageTexture, 1);
  160. oit._translucentFBO.setDepthStencilTexture(oit._depthStencilTexture);
  161. oit._translucentFBO.update(context, width, height);
  162. oit._adjustTranslucentFBO.setColorTexture(oit._accumulationTexture, 0);
  163. oit._adjustTranslucentFBO.setColorTexture(oit._revealageTexture, 1);
  164. oit._adjustTranslucentFBO.update(context, width, height);
  165. if (
  166. oit._translucentFBO.status !== completeFBO ||
  167. oit._adjustTranslucentFBO.status !== completeFBO
  168. ) {
  169. destroyFramebuffers(oit);
  170. oit._translucentMRTSupport = false;
  171. }
  172. }
  173. // either MRT isn't supported or FBO creation failed, attempt multipass
  174. if (!oit._translucentMRTSupport) {
  175. oit._translucentFBO.setColorTexture(oit._accumulationTexture);
  176. oit._translucentFBO.setDepthStencilTexture(oit._depthStencilTexture);
  177. oit._translucentFBO.update(context, width, height);
  178. oit._alphaFBO.setColorTexture(oit._revealageTexture);
  179. oit._alphaFBO.setDepthStencilTexture(oit._depthStencilTexture);
  180. oit._alphaFBO.update(context, width, height);
  181. oit._adjustTranslucentFBO.setColorTexture(oit._accumulationTexture);
  182. oit._adjustTranslucentFBO.update(context, width, height);
  183. oit._adjustAlphaFBO.setColorTexture(oit._revealageTexture);
  184. oit._adjustAlphaFBO.update(context, width, height);
  185. const translucentComplete = oit._translucentFBO.status === completeFBO;
  186. const alphaComplete = oit._alphaFBO.status === completeFBO;
  187. const adjustTranslucentComplete =
  188. oit._adjustTranslucentFBO.status === completeFBO;
  189. const adjustAlphaComplete = oit._adjustAlphaFBO.status === completeFBO;
  190. if (
  191. !translucentComplete ||
  192. !alphaComplete ||
  193. !adjustTranslucentComplete ||
  194. !adjustAlphaComplete
  195. ) {
  196. destroyResources(oit);
  197. oit._translucentMultipassSupport = false;
  198. supported = false;
  199. }
  200. }
  201. return supported;
  202. }
  203. /**
  204. * @private
  205. * @param {Context} context
  206. * @param {PassState} passState
  207. * @param {Framebuffer} framebuffer
  208. * @param {boolean} useHDR
  209. * @param {number} numSamples
  210. */
  211. OIT.prototype.update = function (
  212. context,
  213. passState,
  214. framebuffer,
  215. useHDR,
  216. numSamples
  217. ) {
  218. if (!this.isSupported()) {
  219. return;
  220. }
  221. this._opaqueFBO = framebuffer;
  222. this._opaqueTexture = framebuffer.getColorTexture(0);
  223. this._depthStencilTexture = framebuffer.getDepthStencilTexture();
  224. const { width, height } = this._opaqueTexture;
  225. const accumulationTexture = this._accumulationTexture;
  226. const textureChanged =
  227. !defined(accumulationTexture) ||
  228. accumulationTexture.width !== width ||
  229. accumulationTexture.height !== height ||
  230. useHDR !== this._useHDR;
  231. const samplesChanged = this._numSamples !== numSamples;
  232. if (textureChanged || samplesChanged) {
  233. this._numSamples = numSamples;
  234. updateTextures(this, context, width, height);
  235. }
  236. if (
  237. !defined(this._translucentFBO.framebuffer) ||
  238. textureChanged ||
  239. samplesChanged
  240. ) {
  241. if (!updateFramebuffers(this, context)) {
  242. // framebuffer creation failed
  243. return;
  244. }
  245. }
  246. this._useHDR = useHDR;
  247. const that = this;
  248. let fs;
  249. let uniformMap;
  250. if (!defined(this._compositeCommand)) {
  251. fs = new ShaderSource({
  252. sources: [CompositeOITFS],
  253. });
  254. if (this._translucentMRTSupport) {
  255. fs.defines.push("MRT");
  256. }
  257. uniformMap = {
  258. u_opaque: function () {
  259. return that._opaqueTexture;
  260. },
  261. u_accumulation: function () {
  262. return that._accumulationTexture;
  263. },
  264. u_revealage: function () {
  265. return that._revealageTexture;
  266. },
  267. };
  268. this._compositeCommand = context.createViewportQuadCommand(fs, {
  269. uniformMap: uniformMap,
  270. owner: this,
  271. });
  272. }
  273. if (!defined(this._adjustTranslucentCommand)) {
  274. if (this._translucentMRTSupport) {
  275. fs = new ShaderSource({
  276. defines: ["MRT"],
  277. sources: [AdjustTranslucentFS],
  278. });
  279. uniformMap = {
  280. u_bgColor: function () {
  281. return that._translucentMRTClearCommand.color;
  282. },
  283. u_depthTexture: function () {
  284. return that._depthStencilTexture;
  285. },
  286. };
  287. this._adjustTranslucentCommand = context.createViewportQuadCommand(fs, {
  288. uniformMap: uniformMap,
  289. owner: this,
  290. });
  291. } else if (this._translucentMultipassSupport) {
  292. fs = new ShaderSource({
  293. sources: [AdjustTranslucentFS],
  294. });
  295. uniformMap = {
  296. u_bgColor: function () {
  297. return that._translucentMultipassClearCommand.color;
  298. },
  299. u_depthTexture: function () {
  300. return that._depthStencilTexture;
  301. },
  302. };
  303. this._adjustTranslucentCommand = context.createViewportQuadCommand(fs, {
  304. uniformMap: uniformMap,
  305. owner: this,
  306. });
  307. uniformMap = {
  308. u_bgColor: function () {
  309. return that._alphaClearCommand.color;
  310. },
  311. u_depthTexture: function () {
  312. return that._depthStencilTexture;
  313. },
  314. };
  315. this._adjustAlphaCommand = context.createViewportQuadCommand(fs, {
  316. uniformMap: uniformMap,
  317. owner: this,
  318. });
  319. }
  320. }
  321. this._viewport.width = width;
  322. this._viewport.height = height;
  323. const useScissorTest = !BoundingRectangle.equals(
  324. this._viewport,
  325. passState.viewport
  326. );
  327. let updateScissor = useScissorTest !== this._useScissorTest;
  328. this._useScissorTest = useScissorTest;
  329. if (!BoundingRectangle.equals(this._scissorRectangle, passState.viewport)) {
  330. this._scissorRectangle = BoundingRectangle.clone(
  331. passState.viewport,
  332. this._scissorRectangle
  333. );
  334. updateScissor = true;
  335. }
  336. if (
  337. !defined(this._rs) ||
  338. !BoundingRectangle.equals(this._viewport, this._rs.viewport) ||
  339. updateScissor
  340. ) {
  341. this._rs = RenderState.fromCache({
  342. viewport: this._viewport,
  343. scissorTest: {
  344. enabled: this._useScissorTest,
  345. rectangle: this._scissorRectangle,
  346. },
  347. });
  348. }
  349. if (defined(this._compositeCommand)) {
  350. this._compositeCommand.renderState = this._rs;
  351. }
  352. if (this._adjustTranslucentCommand) {
  353. this._adjustTranslucentCommand.renderState = this._rs;
  354. }
  355. if (defined(this._adjustAlphaCommand)) {
  356. this._adjustAlphaCommand.renderState = this._rs;
  357. }
  358. };
  359. const translucentMRTBlend = {
  360. enabled: true,
  361. color: new Color(0.0, 0.0, 0.0, 0.0),
  362. equationRgb: BlendEquation.ADD,
  363. equationAlpha: BlendEquation.ADD,
  364. functionSourceRgb: BlendFunction.ONE,
  365. functionDestinationRgb: BlendFunction.ONE,
  366. functionSourceAlpha: BlendFunction.ZERO,
  367. functionDestinationAlpha: BlendFunction.ONE_MINUS_SOURCE_ALPHA,
  368. };
  369. const translucentColorBlend = {
  370. enabled: true,
  371. color: new Color(0.0, 0.0, 0.0, 0.0),
  372. equationRgb: BlendEquation.ADD,
  373. equationAlpha: BlendEquation.ADD,
  374. functionSourceRgb: BlendFunction.ONE,
  375. functionDestinationRgb: BlendFunction.ONE,
  376. functionSourceAlpha: BlendFunction.ONE,
  377. functionDestinationAlpha: BlendFunction.ONE,
  378. };
  379. const translucentAlphaBlend = {
  380. enabled: true,
  381. color: new Color(0.0, 0.0, 0.0, 0.0),
  382. equationRgb: BlendEquation.ADD,
  383. equationAlpha: BlendEquation.ADD,
  384. functionSourceRgb: BlendFunction.ZERO,
  385. functionDestinationRgb: BlendFunction.ONE_MINUS_SOURCE_ALPHA,
  386. functionSourceAlpha: BlendFunction.ZERO,
  387. functionDestinationAlpha: BlendFunction.ONE_MINUS_SOURCE_ALPHA,
  388. };
  389. function getTranslucentRenderState(
  390. context,
  391. translucentBlending,
  392. cache,
  393. renderState
  394. ) {
  395. let translucentState = cache[renderState.id];
  396. if (!defined(translucentState)) {
  397. const rs = RenderState.getState(renderState);
  398. rs.depthMask = false;
  399. rs.blending = translucentBlending;
  400. translucentState = RenderState.fromCache(rs);
  401. cache[renderState.id] = translucentState;
  402. }
  403. return translucentState;
  404. }
  405. function getTranslucentMRTRenderState(oit, context, renderState) {
  406. return getTranslucentRenderState(
  407. context,
  408. translucentMRTBlend,
  409. oit._translucentRenderStateCache,
  410. renderState
  411. );
  412. }
  413. function getTranslucentColorRenderState(oit, context, renderState) {
  414. return getTranslucentRenderState(
  415. context,
  416. translucentColorBlend,
  417. oit._translucentRenderStateCache,
  418. renderState
  419. );
  420. }
  421. function getTranslucentAlphaRenderState(oit, context, renderState) {
  422. return getTranslucentRenderState(
  423. context,
  424. translucentAlphaBlend,
  425. oit._alphaRenderStateCache,
  426. renderState
  427. );
  428. }
  429. const mrtShaderSource =
  430. " vec3 Ci = czm_out_FragColor.rgb * czm_out_FragColor.a;\n" +
  431. " float ai = czm_out_FragColor.a;\n" +
  432. " float wzi = czm_alphaWeight(ai);\n" +
  433. " out_FragData_0 = vec4(Ci * wzi, ai);\n" +
  434. " out_FragData_1 = vec4(ai * wzi);\n";
  435. const colorShaderSource =
  436. " vec3 Ci = czm_out_FragColor.rgb * czm_out_FragColor.a;\n" +
  437. " float ai = czm_out_FragColor.a;\n" +
  438. " float wzi = czm_alphaWeight(ai);\n" +
  439. " out_FragColor = vec4(Ci, ai) * wzi;\n";
  440. const alphaShaderSource =
  441. " float ai = czm_out_FragColor.a;\n" + " out_FragColor = vec4(ai);\n";
  442. /**
  443. * @private
  444. * @param {Context} context
  445. * @param {ShaderProgram} shaderProgram
  446. * @param {string} keyword
  447. * @param {string} source
  448. * @returns {ShaderProgram}
  449. */
  450. function getTranslucentShaderProgram(context, shaderProgram, keyword, source) {
  451. const { shaderCache } = context;
  452. const shader = shaderCache.getDerivedShaderProgram(shaderProgram, keyword);
  453. if (defined(shader)) {
  454. return shader;
  455. }
  456. const attributeLocations = shaderProgram._attributeLocations;
  457. const fs = shaderProgram.fragmentShaderSource.clone();
  458. fs.sources = fs.sources.map(function (fsSource) {
  459. return ShaderSource.replaceMain(fsSource, "czm_translucent_main")
  460. .replace(/out_FragColor/g, "czm_out_FragColor")
  461. .replace(
  462. /layout\s*\(location\s*=\s*0\)\s*out\s+vec4\s+out_FragColor;/g,
  463. ""
  464. )
  465. .replace(/\bdiscard\b/g, "czm_discard = true")
  466. .replace(/czm_phong/g, "czm_translucentPhong");
  467. });
  468. // Discarding the fragment in main is a workaround for ANGLE D3D9
  469. // shader compilation errors.
  470. fs.sources.splice(
  471. 0,
  472. 0,
  473. `vec4 czm_out_FragColor;\n` + `bool czm_discard = false;\n`
  474. );
  475. const fragDataMatches = [...source.matchAll(/out_FragData_(\d+)/g)];
  476. let fragDataDeclarations = ``;
  477. for (let i = 0; i < fragDataMatches.length; i++) {
  478. const fragDataMatch = fragDataMatches[i];
  479. fragDataDeclarations = `layout (location = ${fragDataMatch[1]}) out vec4 ${fragDataMatch[0]};\n${fragDataDeclarations}`;
  480. }
  481. fs.sources.push(fragDataDeclarations);
  482. fs.sources.push(
  483. `${
  484. "void main()\n" +
  485. "{\n" +
  486. " czm_translucent_main();\n" +
  487. " if (czm_discard)\n" +
  488. " {\n" +
  489. " discard;\n" +
  490. " }\n"
  491. }${source}}\n`
  492. );
  493. return shaderCache.createDerivedShaderProgram(shaderProgram, keyword, {
  494. vertexShaderSource: shaderProgram.vertexShaderSource,
  495. fragmentShaderSource: fs,
  496. attributeLocations: attributeLocations,
  497. });
  498. }
  499. function getTranslucentMRTShaderProgram(context, shaderProgram) {
  500. return getTranslucentShaderProgram(
  501. context,
  502. shaderProgram,
  503. "translucentMRT",
  504. mrtShaderSource
  505. );
  506. }
  507. function getTranslucentColorShaderProgram(context, shaderProgram) {
  508. return getTranslucentShaderProgram(
  509. context,
  510. shaderProgram,
  511. "translucentMultipass",
  512. colorShaderSource
  513. );
  514. }
  515. function getTranslucentAlphaShaderProgram(context, shaderProgram) {
  516. return getTranslucentShaderProgram(
  517. context,
  518. shaderProgram,
  519. "alphaMultipass",
  520. alphaShaderSource
  521. );
  522. }
  523. /**
  524. * @private
  525. * @param {DrawCommand} command
  526. * @param {Context} context
  527. * @param {*} result
  528. * @returns {*}
  529. */
  530. OIT.prototype.createDerivedCommands = function (command, context, result) {
  531. if (!defined(result)) {
  532. result = {};
  533. }
  534. if (this._translucentMRTSupport) {
  535. let translucentShader;
  536. let translucentRenderState;
  537. if (defined(result.translucentCommand)) {
  538. translucentShader = result.translucentCommand.shaderProgram;
  539. translucentRenderState = result.translucentCommand.renderState;
  540. }
  541. result.translucentCommand = DrawCommand.shallowClone(
  542. command,
  543. result.translucentCommand
  544. );
  545. if (
  546. !defined(translucentShader) ||
  547. result.shaderProgramId !== command.shaderProgram.id
  548. ) {
  549. result.translucentCommand.shaderProgram = getTranslucentMRTShaderProgram(
  550. context,
  551. command.shaderProgram
  552. );
  553. result.translucentCommand.renderState = getTranslucentMRTRenderState(
  554. this,
  555. context,
  556. command.renderState
  557. );
  558. result.shaderProgramId = command.shaderProgram.id;
  559. } else {
  560. result.translucentCommand.shaderProgram = translucentShader;
  561. result.translucentCommand.renderState = translucentRenderState;
  562. }
  563. return result;
  564. }
  565. let colorShader;
  566. let colorRenderState;
  567. let alphaShader;
  568. let alphaRenderState;
  569. if (defined(result.translucentCommand)) {
  570. colorShader = result.translucentCommand.shaderProgram;
  571. colorRenderState = result.translucentCommand.renderState;
  572. alphaShader = result.alphaCommand.shaderProgram;
  573. alphaRenderState = result.alphaCommand.renderState;
  574. }
  575. result.translucentCommand = DrawCommand.shallowClone(
  576. command,
  577. result.translucentCommand
  578. );
  579. result.alphaCommand = DrawCommand.shallowClone(command, result.alphaCommand);
  580. if (
  581. !defined(colorShader) ||
  582. result.shaderProgramId !== command.shaderProgram.id
  583. ) {
  584. result.translucentCommand.shaderProgram = getTranslucentColorShaderProgram(
  585. context,
  586. command.shaderProgram
  587. );
  588. result.translucentCommand.renderState = getTranslucentColorRenderState(
  589. this,
  590. context,
  591. command.renderState
  592. );
  593. result.alphaCommand.shaderProgram = getTranslucentAlphaShaderProgram(
  594. context,
  595. command.shaderProgram
  596. );
  597. result.alphaCommand.renderState = getTranslucentAlphaRenderState(
  598. this,
  599. context,
  600. command.renderState
  601. );
  602. result.shaderProgramId = command.shaderProgram.id;
  603. } else {
  604. result.translucentCommand.shaderProgram = colorShader;
  605. result.translucentCommand.renderState = colorRenderState;
  606. result.alphaCommand.shaderProgram = alphaShader;
  607. result.alphaCommand.renderState = alphaRenderState;
  608. }
  609. return result;
  610. };
  611. /**
  612. * @private
  613. * @param {OIT} oit
  614. * @param {Scene} scene
  615. * @param {Function} executeFunction
  616. * @param {PassState} passState
  617. * @param {DrawCommand[]} commands
  618. * @param {InvertClassification} invertClassification
  619. */
  620. function executeTranslucentCommandsSortedMultipass(
  621. oit,
  622. scene,
  623. executeFunction,
  624. passState,
  625. commands,
  626. invertClassification
  627. ) {
  628. let command;
  629. let derivedCommand;
  630. let j;
  631. const { context, frameState } = scene;
  632. const { useLogDepth, shadowState } = frameState;
  633. const useHdr = scene._hdr;
  634. const framebuffer = passState.framebuffer;
  635. const lightShadowsEnabled = shadowState.lightShadowsEnabled;
  636. passState.framebuffer = oit._adjustTranslucentFBO.framebuffer;
  637. oit._adjustTranslucentCommand.execute(context, passState);
  638. passState.framebuffer = oit._adjustAlphaFBO.framebuffer;
  639. oit._adjustAlphaCommand.execute(context, passState);
  640. const debugFramebuffer = oit._opaqueFBO.framebuffer;
  641. passState.framebuffer = oit._translucentFBO.framebuffer;
  642. for (j = 0; j < commands.length; ++j) {
  643. command = commands[j];
  644. command = useLogDepth ? command.derivedCommands.logDepth.command : command;
  645. command = useHdr ? command.derivedCommands.hdr.command : command;
  646. derivedCommand =
  647. lightShadowsEnabled && command.receiveShadows
  648. ? command.derivedCommands.oit.shadows.translucentCommand
  649. : command.derivedCommands.oit.translucentCommand;
  650. executeFunction(
  651. derivedCommand,
  652. scene,
  653. context,
  654. passState,
  655. debugFramebuffer
  656. );
  657. }
  658. if (defined(invertClassification)) {
  659. command = invertClassification.unclassifiedCommand;
  660. derivedCommand =
  661. lightShadowsEnabled && command.receiveShadows
  662. ? command.derivedCommands.oit.shadows.translucentCommand
  663. : command.derivedCommands.oit.translucentCommand;
  664. executeFunction(
  665. derivedCommand,
  666. scene,
  667. context,
  668. passState,
  669. debugFramebuffer
  670. );
  671. }
  672. passState.framebuffer = oit._alphaFBO.framebuffer;
  673. for (j = 0; j < commands.length; ++j) {
  674. command = commands[j];
  675. command = useLogDepth ? command.derivedCommands.logDepth.command : command;
  676. command = useHdr ? command.derivedCommands.hdr.command : command;
  677. derivedCommand =
  678. lightShadowsEnabled && command.receiveShadows
  679. ? command.derivedCommands.oit.shadows.alphaCommand
  680. : command.derivedCommands.oit.alphaCommand;
  681. executeFunction(
  682. derivedCommand,
  683. scene,
  684. context,
  685. passState,
  686. debugFramebuffer
  687. );
  688. }
  689. if (defined(invertClassification)) {
  690. command = invertClassification.unclassifiedCommand;
  691. derivedCommand =
  692. lightShadowsEnabled && command.receiveShadows
  693. ? command.derivedCommands.oit.shadows.alphaCommand
  694. : command.derivedCommands.oit.alphaCommand;
  695. executeFunction(
  696. derivedCommand,
  697. scene,
  698. context,
  699. passState,
  700. debugFramebuffer
  701. );
  702. }
  703. passState.framebuffer = framebuffer;
  704. }
  705. /**
  706. * @private
  707. * @param {OIT} oit
  708. * @param {Scene} scene
  709. * @param {Function} executeFunction
  710. * @param {PassState} passState
  711. * @param {DrawCommand[]} commands
  712. * @param {InvertClassification} invertClassification
  713. */
  714. function executeTranslucentCommandsSortedMRT(
  715. oit,
  716. scene,
  717. executeFunction,
  718. passState,
  719. commands,
  720. invertClassification
  721. ) {
  722. const { context, frameState } = scene;
  723. const { useLogDepth, shadowState } = frameState;
  724. const useHdr = scene._hdr;
  725. const framebuffer = passState.framebuffer;
  726. const lightShadowsEnabled = shadowState.lightShadowsEnabled;
  727. passState.framebuffer = oit._adjustTranslucentFBO.framebuffer;
  728. oit._adjustTranslucentCommand.execute(context, passState);
  729. const debugFramebuffer = oit._opaqueFBO.framebuffer;
  730. passState.framebuffer = oit._translucentFBO.framebuffer;
  731. let command;
  732. let derivedCommand;
  733. for (let j = 0; j < commands.length; ++j) {
  734. command = commands[j];
  735. command = useLogDepth ? command.derivedCommands.logDepth.command : command;
  736. command = useHdr ? command.derivedCommands.hdr.command : command;
  737. derivedCommand =
  738. lightShadowsEnabled && command.receiveShadows
  739. ? command.derivedCommands.oit.shadows.translucentCommand
  740. : command.derivedCommands.oit.translucentCommand;
  741. executeFunction(
  742. derivedCommand,
  743. scene,
  744. context,
  745. passState,
  746. debugFramebuffer
  747. );
  748. }
  749. if (defined(invertClassification)) {
  750. command = invertClassification.unclassifiedCommand;
  751. derivedCommand =
  752. lightShadowsEnabled && command.receiveShadows
  753. ? command.derivedCommands.oit.shadows.translucentCommand
  754. : command.derivedCommands.oit.translucentCommand;
  755. executeFunction(
  756. derivedCommand,
  757. scene,
  758. context,
  759. passState,
  760. debugFramebuffer
  761. );
  762. }
  763. passState.framebuffer = framebuffer;
  764. }
  765. /**
  766. * @private
  767. * @param {Scene} scene
  768. * @param {Function} executeFunction
  769. * @param {PassState} passState
  770. * @param {DrawCommand[]} commands
  771. * @param {InvertClassification} invertClassification
  772. */
  773. OIT.prototype.executeCommands = function (
  774. scene,
  775. executeFunction,
  776. passState,
  777. commands,
  778. invertClassification
  779. ) {
  780. if (this._translucentMRTSupport) {
  781. executeTranslucentCommandsSortedMRT(
  782. this,
  783. scene,
  784. executeFunction,
  785. passState,
  786. commands,
  787. invertClassification
  788. );
  789. return;
  790. }
  791. executeTranslucentCommandsSortedMultipass(
  792. this,
  793. scene,
  794. executeFunction,
  795. passState,
  796. commands,
  797. invertClassification
  798. );
  799. };
  800. /**
  801. * @private
  802. * @param {Context} context
  803. * @param {PassState} passState
  804. */
  805. OIT.prototype.execute = function (context, passState) {
  806. this._compositeCommand.execute(context, passState);
  807. };
  808. /**
  809. * @private
  810. * @param {Context} context
  811. * @param {PassState} passState
  812. * @param {Color} clearColor
  813. */
  814. OIT.prototype.clear = function (context, passState, clearColor) {
  815. const framebuffer = passState.framebuffer;
  816. passState.framebuffer = this._opaqueFBO.framebuffer;
  817. Color.clone(clearColor, this._opaqueClearCommand.color);
  818. this._opaqueClearCommand.execute(context, passState);
  819. passState.framebuffer = this._translucentFBO.framebuffer;
  820. const translucentClearCommand = this._translucentMRTSupport
  821. ? this._translucentMRTClearCommand
  822. : this._translucentMultipassClearCommand;
  823. translucentClearCommand.execute(context, passState);
  824. if (this._translucentMultipassSupport) {
  825. passState.framebuffer = this._alphaFBO.framebuffer;
  826. this._alphaClearCommand.execute(context, passState);
  827. }
  828. passState.framebuffer = framebuffer;
  829. };
  830. /**
  831. * @private
  832. * @returns {boolean}
  833. */
  834. OIT.prototype.isSupported = function () {
  835. return this._translucentMRTSupport || this._translucentMultipassSupport;
  836. };
  837. /**
  838. * @private
  839. * @returns {boolean}
  840. */
  841. OIT.prototype.isDestroyed = function () {
  842. return false;
  843. };
  844. /**
  845. * @private
  846. */
  847. OIT.prototype.destroy = function () {
  848. destroyResources(this);
  849. if (defined(this._compositeCommand)) {
  850. this._compositeCommand.shaderProgram =
  851. this._compositeCommand.shaderProgram &&
  852. this._compositeCommand.shaderProgram.destroy();
  853. }
  854. if (defined(this._adjustTranslucentCommand)) {
  855. this._adjustTranslucentCommand.shaderProgram =
  856. this._adjustTranslucentCommand.shaderProgram &&
  857. this._adjustTranslucentCommand.shaderProgram.destroy();
  858. }
  859. if (defined(this._adjustAlphaCommand)) {
  860. this._adjustAlphaCommand.shaderProgram =
  861. this._adjustAlphaCommand.shaderProgram &&
  862. this._adjustAlphaCommand.shaderProgram.destroy();
  863. }
  864. return destroyObject(this);
  865. };
  866. export default OIT;