OIT.js 25 KB

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