prePassRenderer.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. import { PrePassRenderTarget } from "../Materials/Textures/prePassRenderTarget.js";
  2. import { _WarnImport } from "../Misc/devTools.js";
  3. import { Color4 } from "../Maths/math.color.js";
  4. import { Material } from "../Materials/material.js";
  5. import { GeometryBufferRenderer } from "../Rendering/geometryBufferRenderer.js";
  6. /**
  7. * Renders a pre pass of the scene
  8. * This means every mesh in the scene will be rendered to a render target texture
  9. * And then this texture will be composited to the rendering canvas with post processes
  10. * It is necessary for effects like subsurface scattering or deferred shading
  11. */
  12. export class PrePassRenderer {
  13. /**
  14. * Indicates if the prepass renderer is generating normals in world space or camera space (default: camera space)
  15. */
  16. get generateNormalsInWorldSpace() {
  17. return this._generateNormalsInWorldSpace;
  18. }
  19. set generateNormalsInWorldSpace(value) {
  20. if (this._generateNormalsInWorldSpace === value) {
  21. return;
  22. }
  23. this._generateNormalsInWorldSpace = value;
  24. this._markAllMaterialsAsPrePassDirty();
  25. }
  26. /**
  27. * Returns the index of a texture in the multi render target texture array.
  28. * @param type Texture type
  29. * @returns The index
  30. */
  31. getIndex(type) {
  32. return this._textureIndices[type];
  33. }
  34. /**
  35. * How many samples are used for MSAA of the scene render target
  36. */
  37. get samples() {
  38. return this.defaultRT.samples;
  39. }
  40. set samples(n) {
  41. this.defaultRT.samples = n;
  42. }
  43. /**
  44. * If set to true (default: false), the depth texture will be cleared with the depth value corresponding to the far plane (1 in normal mode, 0 in reverse depth buffer mode)
  45. * If set to false, the depth texture is always cleared with 0.
  46. */
  47. get useSpecificClearForDepthTexture() {
  48. return this._useSpecificClearForDepthTexture;
  49. }
  50. set useSpecificClearForDepthTexture(value) {
  51. if (this._useSpecificClearForDepthTexture === value) {
  52. return;
  53. }
  54. this._useSpecificClearForDepthTexture = value;
  55. this._isDirty = true;
  56. }
  57. /**
  58. * @returns the prepass render target for the rendering pass.
  59. * If we are currently rendering a render target, it returns the PrePassRenderTarget
  60. * associated with that render target. Otherwise, it returns the scene default PrePassRenderTarget
  61. */
  62. getRenderTarget() {
  63. return this._currentTarget;
  64. }
  65. /**
  66. * @internal
  67. * Managed by the scene component
  68. * @param prePassRenderTarget
  69. */
  70. _setRenderTarget(prePassRenderTarget) {
  71. if (prePassRenderTarget) {
  72. this._currentTarget = prePassRenderTarget;
  73. }
  74. else {
  75. this._currentTarget = this.defaultRT;
  76. this._engine.currentRenderPassId = this._scene.activeCamera?.renderPassId ?? this._currentTarget.renderPassId;
  77. }
  78. }
  79. /**
  80. * Returns true if the currently rendered prePassRenderTarget is the one
  81. * associated with the scene.
  82. */
  83. get currentRTisSceneRT() {
  84. return this._currentTarget === this.defaultRT;
  85. }
  86. _refreshGeometryBufferRendererLink() {
  87. if (!this.doNotUseGeometryRendererFallback) {
  88. this._geometryBuffer = this._scene.enableGeometryBufferRenderer();
  89. if (!this._geometryBuffer) {
  90. // Not supported
  91. this.doNotUseGeometryRendererFallback = true;
  92. return;
  93. }
  94. this._geometryBuffer._linkPrePassRenderer(this);
  95. }
  96. else {
  97. if (this._geometryBuffer) {
  98. this._geometryBuffer._unlinkPrePassRenderer();
  99. }
  100. this._geometryBuffer = null;
  101. this._scene.disableGeometryBufferRenderer();
  102. }
  103. }
  104. /**
  105. * Indicates if the prepass is enabled
  106. */
  107. get enabled() {
  108. return this._enabled;
  109. }
  110. /**
  111. * Instantiates a prepass renderer
  112. * @param scene The scene
  113. */
  114. constructor(scene) {
  115. /**
  116. * To save performance, we can excluded skinned meshes from the prepass
  117. */
  118. this.excludedSkinnedMesh = [];
  119. /**
  120. * Force material to be excluded from the prepass
  121. * Can be useful when `useGeometryBufferFallback` is set to `true`
  122. * and you don't want a material to show in the effect.
  123. */
  124. this.excludedMaterials = [];
  125. /**
  126. * Number of textures in the multi render target texture where the scene is directly rendered
  127. */
  128. this.mrtCount = 0;
  129. this._mrtTypes = [];
  130. this._mrtFormats = [];
  131. this._mrtLayout = [];
  132. this._mrtNames = [];
  133. this._textureIndices = [];
  134. this._generateNormalsInWorldSpace = false;
  135. this._useSpecificClearForDepthTexture = false;
  136. this._isDirty = true;
  137. /**
  138. * Configuration for prepass effects
  139. */
  140. this._effectConfigurations = [];
  141. /**
  142. * Prevents the PrePassRenderer from using the GeometryBufferRenderer as a fallback
  143. */
  144. this.doNotUseGeometryRendererFallback = true;
  145. /**
  146. * All the render targets generated by prepass
  147. */
  148. this.renderTargets = [];
  149. this._clearColor = new Color4(0, 0, 0, 0);
  150. this._clearDepthColor = new Color4(1e8, 0, 0, 1); // "infinity" value - depth in the depth texture is view.z, not a 0..1 value!
  151. this._enabled = false;
  152. this._needsCompositionForThisPass = false;
  153. /**
  154. * Set to true to disable gamma transform in PrePass.
  155. * Can be useful in case you already proceed to gamma transform on a material level
  156. * and your post processes don't need to be in linear color space.
  157. */
  158. this.disableGammaTransform = false;
  159. this._scene = scene;
  160. this._engine = scene.getEngine();
  161. let type = 0;
  162. if (this._engine._caps.textureFloat && this._engine._caps.textureFloatLinearFiltering) {
  163. type = 1;
  164. }
  165. else if (this._engine._caps.textureHalfFloat && this._engine._caps.textureHalfFloatLinearFiltering) {
  166. type = 2;
  167. }
  168. for (let i = 0; i < PrePassRenderer.TextureFormats.length; ++i) {
  169. const format = PrePassRenderer.TextureFormats[i].format;
  170. if (PrePassRenderer.TextureFormats[i].type === 1) {
  171. PrePassRenderer.TextureFormats[5].type = type;
  172. if ((format === 6 || format === 7 || format === 5) &&
  173. !this._engine._caps.supportFloatTexturesResolve) {
  174. // We don't know in advance if the texture will be used as a resolve target, so we revert to half_float if the extension to resolve full float textures is not supported
  175. PrePassRenderer.TextureFormats[5].type = 2;
  176. }
  177. }
  178. }
  179. PrePassRenderer._SceneComponentInitialization(this._scene);
  180. this.defaultRT = this._createRenderTarget("sceneprePassRT", null);
  181. this._currentTarget = this.defaultRT;
  182. }
  183. /**
  184. * Creates a new PrePassRenderTarget
  185. * This should be the only way to instantiate a `PrePassRenderTarget`
  186. * @param name Name of the `PrePassRenderTarget`
  187. * @param renderTargetTexture RenderTarget the `PrePassRenderTarget` will be attached to.
  188. * Can be `null` if the created `PrePassRenderTarget` is attached to the scene (default framebuffer).
  189. * @internal
  190. */
  191. _createRenderTarget(name, renderTargetTexture) {
  192. const rt = new PrePassRenderTarget(name, renderTargetTexture, { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, 0, this._scene, {
  193. generateMipMaps: false,
  194. generateStencilBuffer: this._engine.isStencilEnable,
  195. defaultType: 0,
  196. types: [],
  197. drawOnlyOnFirstAttachmentByDefault: true,
  198. });
  199. this.renderTargets.push(rt);
  200. if (this._enabled) {
  201. // The pre-pass renderer is already enabled, so make sure we create the render target with the correct number of textures
  202. this._update();
  203. }
  204. return rt;
  205. }
  206. /**
  207. * Indicates if rendering a prepass is supported
  208. */
  209. get isSupported() {
  210. return this._scene.getEngine().getCaps().drawBuffersExtension;
  211. }
  212. /**
  213. * Sets the proper output textures to draw in the engine.
  214. * @param effect The effect that is drawn. It can be or not be compatible with drawing to several output textures.
  215. * @param subMesh Submesh on which the effect is applied
  216. */
  217. bindAttachmentsForEffect(effect, subMesh) {
  218. const material = subMesh.getMaterial();
  219. const isPrePassCapable = material && material.isPrePassCapable;
  220. const excluded = material && this.excludedMaterials.indexOf(material) !== -1;
  221. if (this.enabled && this._currentTarget.enabled) {
  222. if (effect._multiTarget && isPrePassCapable && !excluded) {
  223. this._engine.bindAttachments(this._multiRenderAttachments);
  224. }
  225. else {
  226. if (this._engine._currentRenderTarget) {
  227. this._engine.bindAttachments(this._defaultAttachments);
  228. }
  229. else {
  230. this._engine.restoreSingleAttachment();
  231. }
  232. if (this._geometryBuffer && this.currentRTisSceneRT && !excluded) {
  233. this._geometryBuffer.renderList.push(subMesh.getRenderingMesh());
  234. }
  235. }
  236. }
  237. }
  238. _reinitializeAttachments() {
  239. const multiRenderLayout = [];
  240. const clearLayout = [false];
  241. const clearDepthLayout = [false];
  242. const defaultLayout = [true];
  243. for (let i = 0; i < this.mrtCount; i++) {
  244. multiRenderLayout.push(true);
  245. if (i > 0) {
  246. if (this._useSpecificClearForDepthTexture && this._mrtLayout[i] === 5) {
  247. clearLayout.push(false);
  248. clearDepthLayout.push(true);
  249. }
  250. else {
  251. clearLayout.push(true);
  252. clearDepthLayout.push(false);
  253. }
  254. defaultLayout.push(false);
  255. }
  256. }
  257. this._multiRenderAttachments = this._engine.buildTextureLayout(multiRenderLayout);
  258. this._clearAttachments = this._engine.buildTextureLayout(clearLayout);
  259. this._clearDepthAttachments = this._engine.buildTextureLayout(clearDepthLayout);
  260. this._defaultAttachments = this._engine.buildTextureLayout(defaultLayout);
  261. }
  262. _resetLayout() {
  263. for (let i = 0; i < PrePassRenderer.TextureFormats.length; i++) {
  264. this._textureIndices[PrePassRenderer.TextureFormats[i].purpose] = -1;
  265. }
  266. this._textureIndices[4] = 0;
  267. this._mrtLayout = [4];
  268. this._mrtTypes = [PrePassRenderer.TextureFormats[4].type];
  269. this._mrtFormats = [PrePassRenderer.TextureFormats[4].format];
  270. this._mrtNames = [PrePassRenderer.TextureFormats[4].name];
  271. this.mrtCount = 1;
  272. }
  273. _updateGeometryBufferLayout() {
  274. this._refreshGeometryBufferRendererLink();
  275. if (this._geometryBuffer) {
  276. this._geometryBuffer._resetLayout();
  277. const texturesActivated = [];
  278. for (let i = 0; i < this._mrtLayout.length; i++) {
  279. texturesActivated.push(false);
  280. }
  281. this._geometryBuffer._linkInternalTexture(this.defaultRT.getInternalTexture());
  282. const matches = [
  283. {
  284. prePassConstant: 5,
  285. geometryBufferConstant: GeometryBufferRenderer.DEPTH_TEXTURE_TYPE,
  286. },
  287. {
  288. prePassConstant: 6,
  289. geometryBufferConstant: GeometryBufferRenderer.NORMAL_TEXTURE_TYPE,
  290. },
  291. {
  292. prePassConstant: 1,
  293. geometryBufferConstant: GeometryBufferRenderer.POSITION_TEXTURE_TYPE,
  294. },
  295. {
  296. prePassConstant: 3,
  297. geometryBufferConstant: GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE,
  298. },
  299. {
  300. prePassConstant: 2,
  301. geometryBufferConstant: GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE,
  302. },
  303. ];
  304. // replace textures in the geometryBuffer RT
  305. for (let i = 0; i < matches.length; i++) {
  306. const index = this._mrtLayout.indexOf(matches[i].prePassConstant);
  307. if (index !== -1) {
  308. this._geometryBuffer._forceTextureType(matches[i].geometryBufferConstant, index);
  309. texturesActivated[index] = true;
  310. }
  311. }
  312. this._geometryBuffer._setAttachments(this._engine.buildTextureLayout(texturesActivated));
  313. }
  314. }
  315. /**
  316. * Restores attachments for single texture draw.
  317. */
  318. restoreAttachments() {
  319. if (this.enabled && this._currentTarget.enabled && this._defaultAttachments) {
  320. if (this._engine._currentRenderTarget) {
  321. this._engine.bindAttachments(this._defaultAttachments);
  322. }
  323. else {
  324. this._engine.restoreSingleAttachment();
  325. }
  326. }
  327. }
  328. /**
  329. * @internal
  330. */
  331. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  332. _beforeDraw(camera, faceIndex, layer) {
  333. // const previousEnabled = this._enabled && this._currentTarget.enabled;
  334. if (this._isDirty) {
  335. this._update();
  336. }
  337. if (!this._enabled || !this._currentTarget.enabled) {
  338. return;
  339. }
  340. if (this._geometryBuffer) {
  341. this._geometryBuffer.renderList = [];
  342. }
  343. this._setupOutputForThisPass(this._currentTarget, camera);
  344. }
  345. _prepareFrame(prePassRenderTarget, faceIndex, layer) {
  346. if (prePassRenderTarget.renderTargetTexture) {
  347. prePassRenderTarget.renderTargetTexture._prepareFrame(this._scene, faceIndex, layer, prePassRenderTarget.renderTargetTexture.useCameraPostProcesses);
  348. }
  349. else if (this._postProcessesSourceForThisPass.length) {
  350. this._scene.postProcessManager._prepareFrame();
  351. }
  352. else {
  353. this._engine.restoreDefaultFramebuffer();
  354. }
  355. }
  356. /**
  357. * Sets an intermediary texture between prepass and postprocesses. This texture
  358. * will be used as input for post processes
  359. * @param rt The render target texture to use
  360. * @returns true if there are postprocesses that will use this texture,
  361. * false if there is no postprocesses - and the function has no effect
  362. */
  363. setCustomOutput(rt) {
  364. const firstPP = this._postProcessesSourceForThisPass[0];
  365. if (!firstPP) {
  366. return false;
  367. }
  368. firstPP.inputTexture = rt.renderTarget;
  369. return true;
  370. }
  371. _renderPostProcesses(prePassRenderTarget, faceIndex) {
  372. const firstPP = this._postProcessesSourceForThisPass[0];
  373. const outputTexture = firstPP ? firstPP.inputTexture : prePassRenderTarget.renderTargetTexture ? prePassRenderTarget.renderTargetTexture.renderTarget : null;
  374. // Build post process chain for this prepass post draw
  375. let postProcessChain = this._currentTarget._beforeCompositionPostProcesses;
  376. if (this._needsCompositionForThisPass) {
  377. postProcessChain = postProcessChain.concat([this._currentTarget.imageProcessingPostProcess]);
  378. }
  379. // Activates and renders the chain
  380. if (postProcessChain.length) {
  381. this._scene.postProcessManager._prepareFrame(this._currentTarget.renderTarget?.texture, postProcessChain);
  382. this._scene.postProcessManager.directRender(postProcessChain, outputTexture, false, faceIndex);
  383. }
  384. }
  385. /**
  386. * @internal
  387. */
  388. _afterDraw(faceIndex, layer) {
  389. if (this._enabled && this._currentTarget.enabled) {
  390. this._prepareFrame(this._currentTarget, faceIndex, layer);
  391. this._renderPostProcesses(this._currentTarget, faceIndex);
  392. }
  393. }
  394. /**
  395. * Clears the current prepass render target (in the sense of settings pixels to the scene clear color value)
  396. * @internal
  397. */
  398. _clear() {
  399. if (this._enabled && this._currentTarget.enabled) {
  400. this._bindFrameBuffer();
  401. // Clearing other attachment with 0 on all other attachments
  402. this._engine.bindAttachments(this._clearAttachments);
  403. this._engine.clear(this._clearColor, true, false, false);
  404. if (this._useSpecificClearForDepthTexture) {
  405. this._engine.bindAttachments(this._clearDepthAttachments);
  406. this._engine.clear(this._clearDepthColor, true, false, false);
  407. }
  408. // Regular clear color with the scene clear color of the 1st attachment
  409. this._engine.bindAttachments(this._defaultAttachments);
  410. }
  411. }
  412. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  413. _bindFrameBuffer() {
  414. if (this._enabled && this._currentTarget.enabled) {
  415. this._currentTarget._checkSize();
  416. const internalTexture = this._currentTarget.renderTarget;
  417. if (internalTexture) {
  418. this._engine.bindFramebuffer(internalTexture);
  419. }
  420. }
  421. }
  422. _setEnabled(enabled) {
  423. this._enabled = enabled;
  424. }
  425. _setRenderTargetEnabled(prePassRenderTarget, enabled) {
  426. prePassRenderTarget.enabled = enabled;
  427. if (!enabled) {
  428. this._unlinkInternalTexture(prePassRenderTarget);
  429. }
  430. }
  431. /**
  432. * Adds an effect configuration to the prepass render target.
  433. * If an effect has already been added, it won't add it twice and will return the configuration
  434. * already present.
  435. * @param cfg the effect configuration
  436. * @returns the effect configuration now used by the prepass
  437. */
  438. addEffectConfiguration(cfg) {
  439. // Do not add twice
  440. for (let i = 0; i < this._effectConfigurations.length; i++) {
  441. if (this._effectConfigurations[i].name === cfg.name) {
  442. return this._effectConfigurations[i];
  443. }
  444. }
  445. this._effectConfigurations.push(cfg);
  446. return cfg;
  447. }
  448. /**
  449. * Retrieves an effect configuration by name
  450. * @param name the name of the effect configuration
  451. * @returns the effect configuration, or null if not present
  452. */
  453. getEffectConfiguration(name) {
  454. for (let i = 0; i < this._effectConfigurations.length; i++) {
  455. if (this._effectConfigurations[i].name === name) {
  456. return this._effectConfigurations[i];
  457. }
  458. }
  459. return null;
  460. }
  461. _enable() {
  462. const previousMrtCount = this.mrtCount;
  463. for (let i = 0; i < this._effectConfigurations.length; i++) {
  464. if (this._effectConfigurations[i].enabled) {
  465. this._enableTextures(this._effectConfigurations[i].texturesRequired);
  466. }
  467. }
  468. for (let i = 0; i < this.renderTargets.length; i++) {
  469. if (this.mrtCount !== previousMrtCount || this.renderTargets[i].count !== this.mrtCount) {
  470. this.renderTargets[i].updateCount(this.mrtCount, { types: this._mrtTypes, formats: this._mrtFormats }, this._mrtNames.concat("prePass_DepthBuffer"));
  471. }
  472. this.renderTargets[i]._resetPostProcessChain();
  473. for (let j = 0; j < this._effectConfigurations.length; j++) {
  474. if (this._effectConfigurations[j].enabled) {
  475. // TODO : subsurface scattering has 1 scene-wide effect configuration
  476. // solution : do not stock postProcess on effectConfiguration, but in the prepassRenderTarget (hashmap configuration => postProcess)
  477. // And call createPostProcess whenever the post process does not exist in the RT
  478. if (!this._effectConfigurations[j].postProcess && this._effectConfigurations[j].createPostProcess) {
  479. this._effectConfigurations[j].createPostProcess();
  480. }
  481. if (this._effectConfigurations[j].postProcess) {
  482. this.renderTargets[i]._beforeCompositionPostProcesses.push(this._effectConfigurations[j].postProcess);
  483. }
  484. }
  485. }
  486. }
  487. this._reinitializeAttachments();
  488. this._setEnabled(true);
  489. this._updateGeometryBufferLayout();
  490. }
  491. _disable() {
  492. this._setEnabled(false);
  493. for (let i = 0; i < this.renderTargets.length; i++) {
  494. this._setRenderTargetEnabled(this.renderTargets[i], false);
  495. }
  496. this._resetLayout();
  497. for (let i = 0; i < this._effectConfigurations.length; i++) {
  498. this._effectConfigurations[i].enabled = false;
  499. }
  500. }
  501. _getPostProcessesSource(prePassRenderTarget, camera) {
  502. if (camera) {
  503. return camera._postProcesses;
  504. }
  505. else if (prePassRenderTarget.renderTargetTexture) {
  506. if (prePassRenderTarget.renderTargetTexture.useCameraPostProcesses) {
  507. const camera = prePassRenderTarget.renderTargetTexture.activeCamera ? prePassRenderTarget.renderTargetTexture.activeCamera : this._scene.activeCamera;
  508. return camera ? camera._postProcesses : [];
  509. }
  510. else if (prePassRenderTarget.renderTargetTexture.postProcesses) {
  511. return prePassRenderTarget.renderTargetTexture.postProcesses;
  512. }
  513. else {
  514. return [];
  515. }
  516. }
  517. else {
  518. return this._scene.activeCamera ? this._scene.activeCamera._postProcesses : [];
  519. }
  520. }
  521. _setupOutputForThisPass(prePassRenderTarget, camera) {
  522. // Order is : draw ===> prePassRenderTarget._postProcesses ==> ipp ==> camera._postProcesses
  523. const secondaryCamera = camera && this._scene.activeCameras && !!this._scene.activeCameras.length && this._scene.activeCameras.indexOf(camera) !== 0;
  524. this._postProcessesSourceForThisPass = this._getPostProcessesSource(prePassRenderTarget, camera);
  525. this._postProcessesSourceForThisPass = this._postProcessesSourceForThisPass.filter((pp) => {
  526. return pp != null;
  527. });
  528. this._scene.autoClear = true;
  529. const cameraHasImageProcessing = this._hasImageProcessing(this._postProcessesSourceForThisPass);
  530. this._needsCompositionForThisPass = !cameraHasImageProcessing && !this.disableGammaTransform && this._needsImageProcessing() && !secondaryCamera;
  531. const firstCameraPP = this._getFirstPostProcess(this._postProcessesSourceForThisPass);
  532. const firstPrePassPP = prePassRenderTarget._beforeCompositionPostProcesses && prePassRenderTarget._beforeCompositionPostProcesses[0];
  533. let firstPP = null;
  534. // Setting the scene-wide post process configuration
  535. this._scene.imageProcessingConfiguration.applyByPostProcess = this._needsCompositionForThisPass || cameraHasImageProcessing;
  536. // Create composition effect if needed
  537. if (this._needsCompositionForThisPass && !prePassRenderTarget.imageProcessingPostProcess) {
  538. prePassRenderTarget._createCompositionEffect();
  539. }
  540. // Setting the prePassRenderTarget as input texture of the first PP
  541. if (firstPrePassPP) {
  542. firstPP = firstPrePassPP;
  543. }
  544. else if (this._needsCompositionForThisPass) {
  545. firstPP = prePassRenderTarget.imageProcessingPostProcess;
  546. }
  547. else if (firstCameraPP) {
  548. firstPP = firstCameraPP;
  549. }
  550. this._bindFrameBuffer();
  551. this._linkInternalTexture(prePassRenderTarget, firstPP);
  552. }
  553. _linkInternalTexture(prePassRenderTarget, postProcess) {
  554. if (postProcess) {
  555. postProcess.autoClear = false;
  556. postProcess.inputTexture = prePassRenderTarget.renderTarget;
  557. }
  558. if (prePassRenderTarget._outputPostProcess !== postProcess) {
  559. if (prePassRenderTarget._outputPostProcess) {
  560. this._unlinkInternalTexture(prePassRenderTarget);
  561. }
  562. prePassRenderTarget._outputPostProcess = postProcess;
  563. }
  564. if (prePassRenderTarget._internalTextureDirty) {
  565. this._updateGeometryBufferLayout();
  566. prePassRenderTarget._internalTextureDirty = false;
  567. }
  568. }
  569. /**
  570. * @internal
  571. */
  572. _unlinkInternalTexture(prePassRenderTarget) {
  573. if (prePassRenderTarget._outputPostProcess) {
  574. prePassRenderTarget._outputPostProcess.autoClear = true;
  575. prePassRenderTarget._outputPostProcess.restoreDefaultInputTexture();
  576. prePassRenderTarget._outputPostProcess = null;
  577. }
  578. }
  579. _needsImageProcessing() {
  580. for (let i = 0; i < this._effectConfigurations.length; i++) {
  581. if (this._effectConfigurations[i].enabled && this._effectConfigurations[i].needsImageProcessing) {
  582. return true;
  583. }
  584. }
  585. return false;
  586. }
  587. _hasImageProcessing(postProcesses) {
  588. let isIPPAlreadyPresent = false;
  589. if (postProcesses) {
  590. for (let i = 0; i < postProcesses.length; i++) {
  591. if (postProcesses[i]?.getClassName() === "ImageProcessingPostProcess") {
  592. isIPPAlreadyPresent = true;
  593. break;
  594. }
  595. }
  596. }
  597. return isIPPAlreadyPresent;
  598. }
  599. /**
  600. * Internal, gets the first post proces.
  601. * @param postProcesses
  602. * @returns the first post process to be run on this camera.
  603. */
  604. _getFirstPostProcess(postProcesses) {
  605. for (let ppIndex = 0; ppIndex < postProcesses.length; ppIndex++) {
  606. if (postProcesses[ppIndex] !== null) {
  607. return postProcesses[ppIndex];
  608. }
  609. }
  610. return null;
  611. }
  612. /**
  613. * Marks the prepass renderer as dirty, triggering a check if the prepass is necessary for the next rendering.
  614. */
  615. markAsDirty() {
  616. this._isDirty = true;
  617. }
  618. /**
  619. * Enables a texture on the MultiRenderTarget for prepass
  620. * @param types
  621. */
  622. _enableTextures(types) {
  623. // For velocity : enable storage of previous matrices for instances
  624. this._scene.needsPreviousWorldMatrices = false;
  625. for (let i = 0; i < types.length; i++) {
  626. const type = types[i];
  627. if (this._textureIndices[type] === -1) {
  628. this._textureIndices[type] = this._mrtLayout.length;
  629. this._mrtLayout.push(type);
  630. this._mrtTypes.push(PrePassRenderer.TextureFormats[type].type);
  631. this._mrtFormats.push(PrePassRenderer.TextureFormats[type].format);
  632. this._mrtNames.push(PrePassRenderer.TextureFormats[type].name);
  633. this.mrtCount++;
  634. }
  635. if (type === 2) {
  636. this._scene.needsPreviousWorldMatrices = true;
  637. }
  638. }
  639. }
  640. /**
  641. * Makes sure that the prepass renderer is up to date if it has been dirtified.
  642. */
  643. update() {
  644. if (this._isDirty) {
  645. this._update();
  646. }
  647. }
  648. _update() {
  649. this._disable();
  650. let enablePrePass = false;
  651. this._scene.imageProcessingConfiguration.applyByPostProcess = false;
  652. if (this._scene._depthPeelingRenderer && this._scene.useOrderIndependentTransparency) {
  653. this._scene._depthPeelingRenderer.setPrePassRenderer(this);
  654. enablePrePass = true;
  655. }
  656. for (let i = 0; i < this._scene.materials.length; i++) {
  657. if (this._scene.materials[i].setPrePassRenderer(this)) {
  658. enablePrePass = true;
  659. }
  660. }
  661. if (enablePrePass) {
  662. this._setRenderTargetEnabled(this.defaultRT, true);
  663. }
  664. let postProcesses;
  665. for (let i = 0; i < this.renderTargets.length; i++) {
  666. if (this.renderTargets[i].renderTargetTexture) {
  667. postProcesses = this._getPostProcessesSource(this.renderTargets[i]);
  668. }
  669. else {
  670. const camera = this._scene.activeCamera;
  671. if (!camera) {
  672. continue;
  673. }
  674. postProcesses = camera._postProcesses;
  675. }
  676. if (!postProcesses) {
  677. continue;
  678. }
  679. postProcesses = postProcesses.filter((pp) => {
  680. return pp != null;
  681. });
  682. if (postProcesses) {
  683. for (let j = 0; j < postProcesses.length; j++) {
  684. if (postProcesses[j].setPrePassRenderer(this)) {
  685. this._setRenderTargetEnabled(this.renderTargets[i], true);
  686. enablePrePass = true;
  687. }
  688. }
  689. if (this._hasImageProcessing(postProcesses)) {
  690. this._scene.imageProcessingConfiguration.applyByPostProcess = true;
  691. }
  692. }
  693. }
  694. this._markAllMaterialsAsPrePassDirty();
  695. this._isDirty = false;
  696. if (enablePrePass) {
  697. this._enable();
  698. }
  699. }
  700. _markAllMaterialsAsPrePassDirty() {
  701. const materials = this._scene.materials;
  702. for (let i = 0; i < materials.length; i++) {
  703. materials[i].markAsDirty(Material.PrePassDirtyFlag);
  704. }
  705. }
  706. /**
  707. * Disposes the prepass renderer.
  708. */
  709. dispose() {
  710. for (let i = this.renderTargets.length - 1; i >= 0; i--) {
  711. this.renderTargets[i].dispose();
  712. }
  713. for (let i = 0; i < this._effectConfigurations.length; i++) {
  714. if (this._effectConfigurations[i].dispose) {
  715. this._effectConfigurations[i].dispose();
  716. }
  717. }
  718. }
  719. }
  720. /**
  721. * @internal
  722. */
  723. PrePassRenderer._SceneComponentInitialization = (_) => {
  724. throw _WarnImport("PrePassRendererSceneComponent");
  725. };
  726. /**
  727. * Describes the types and formats of the textures used by the pre-pass renderer
  728. */
  729. PrePassRenderer.TextureFormats = [
  730. {
  731. purpose: 0,
  732. type: 2,
  733. format: 5,
  734. name: "prePass_Irradiance",
  735. },
  736. {
  737. purpose: 1,
  738. type: 2,
  739. format: 5,
  740. name: "prePass_Position",
  741. },
  742. {
  743. purpose: 2,
  744. type: 0,
  745. format: 5,
  746. name: "prePass_Velocity",
  747. },
  748. {
  749. purpose: 3,
  750. type: 0,
  751. format: 5,
  752. name: "prePass_Reflectivity",
  753. },
  754. {
  755. purpose: 4,
  756. type: 2,
  757. format: 5,
  758. name: "prePass_Color",
  759. },
  760. {
  761. purpose: 5,
  762. type: 1,
  763. format: 6,
  764. name: "prePass_Depth",
  765. },
  766. {
  767. purpose: 6,
  768. type: 2,
  769. format: 5,
  770. name: "prePass_Normal",
  771. },
  772. {
  773. purpose: 7,
  774. type: 0,
  775. format: 5,
  776. name: "prePass_Albedo",
  777. },
  778. ];
  779. //# sourceMappingURL=prePassRenderer.js.map