postProcessManager.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import { VertexBuffer } from "../Buffers/buffer.js";
  2. /**
  3. * PostProcessManager is used to manage one or more post processes or post process pipelines
  4. * See https://doc.babylonjs.com/features/featuresDeepDive/postProcesses/usePostProcesses
  5. */
  6. export class PostProcessManager {
  7. /**
  8. * Creates a new instance PostProcess
  9. * @param scene The scene that the post process is associated with.
  10. */
  11. constructor(scene) {
  12. this._vertexBuffers = {};
  13. this._scene = scene;
  14. }
  15. _prepareBuffers() {
  16. if (this._vertexBuffers[VertexBuffer.PositionKind]) {
  17. return;
  18. }
  19. // VBO
  20. const vertices = [];
  21. vertices.push(1, 1);
  22. vertices.push(-1, 1);
  23. vertices.push(-1, -1);
  24. vertices.push(1, -1);
  25. this._vertexBuffers[VertexBuffer.PositionKind] = new VertexBuffer(this._scene.getEngine(), vertices, VertexBuffer.PositionKind, false, false, 2);
  26. this._buildIndexBuffer();
  27. }
  28. _buildIndexBuffer() {
  29. // Indices
  30. const indices = [];
  31. indices.push(0);
  32. indices.push(1);
  33. indices.push(2);
  34. indices.push(0);
  35. indices.push(2);
  36. indices.push(3);
  37. this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
  38. }
  39. /**
  40. * Rebuilds the vertex buffers of the manager.
  41. * @internal
  42. */
  43. _rebuild() {
  44. const vb = this._vertexBuffers[VertexBuffer.PositionKind];
  45. if (!vb) {
  46. return;
  47. }
  48. vb._rebuild();
  49. this._buildIndexBuffer();
  50. }
  51. // Methods
  52. /**
  53. * Prepares a frame to be run through a post process.
  54. * @param sourceTexture The input texture to the post processes. (default: null)
  55. * @param postProcesses An array of post processes to be run. (default: null)
  56. * @returns True if the post processes were able to be run.
  57. * @internal
  58. */
  59. _prepareFrame(sourceTexture = null, postProcesses = null) {
  60. const camera = this._scene.activeCamera;
  61. if (!camera) {
  62. return false;
  63. }
  64. postProcesses = postProcesses || camera._postProcesses.filter((pp) => {
  65. return pp != null;
  66. });
  67. if (!postProcesses || postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
  68. return false;
  69. }
  70. postProcesses[0].activate(camera, sourceTexture, postProcesses !== null && postProcesses !== undefined);
  71. return true;
  72. }
  73. /**
  74. * Manually render a set of post processes to a texture.
  75. * Please note, the frame buffer won't be unbound after the call in case you have more render to do.
  76. * @param postProcesses An array of post processes to be run.
  77. * @param targetTexture The render target wrapper to render to.
  78. * @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight
  79. * @param faceIndex defines the face to render to if a cubemap is defined as the target
  80. * @param lodLevel defines which lod of the texture to render to
  81. * @param doNotBindFrambuffer If set to true, assumes that the framebuffer has been bound previously
  82. */
  83. directRender(postProcesses, targetTexture = null, forceFullscreenViewport = false, faceIndex = 0, lodLevel = 0, doNotBindFrambuffer = false) {
  84. const engine = this._scene.getEngine();
  85. for (let index = 0; index < postProcesses.length; index++) {
  86. if (index < postProcesses.length - 1) {
  87. postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture?.texture);
  88. }
  89. else {
  90. if (targetTexture) {
  91. engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport, lodLevel);
  92. }
  93. else if (!doNotBindFrambuffer) {
  94. engine.restoreDefaultFramebuffer();
  95. }
  96. engine._debugInsertMarker?.(`post process ${postProcesses[index].name} output`);
  97. }
  98. const pp = postProcesses[index];
  99. const effect = pp.apply();
  100. if (effect) {
  101. pp.onBeforeRenderObservable.notifyObservers(effect);
  102. // VBOs
  103. this._prepareBuffers();
  104. engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
  105. // Draw order
  106. engine.drawElementsType(0, 0, 6);
  107. pp.onAfterRenderObservable.notifyObservers(effect);
  108. }
  109. }
  110. // Restore depth buffer
  111. engine.setDepthBuffer(true);
  112. engine.setDepthWrite(true);
  113. }
  114. /**
  115. * Finalize the result of the output of the postprocesses.
  116. * @param doNotPresent If true the result will not be displayed to the screen.
  117. * @param targetTexture The render target wrapper to render to.
  118. * @param faceIndex The index of the face to bind the target texture to.
  119. * @param postProcesses The array of post processes to render.
  120. * @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight (default: false)
  121. * @internal
  122. */
  123. _finalizeFrame(doNotPresent, targetTexture, faceIndex, postProcesses, forceFullscreenViewport = false) {
  124. const camera = this._scene.activeCamera;
  125. if (!camera) {
  126. return;
  127. }
  128. postProcesses = postProcesses || camera._postProcesses.filter((pp) => {
  129. return pp != null;
  130. });
  131. if (postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
  132. return;
  133. }
  134. const engine = this._scene.getEngine();
  135. for (let index = 0, len = postProcesses.length; index < len; index++) {
  136. const pp = postProcesses[index];
  137. if (index < len - 1) {
  138. pp._outputTexture = postProcesses[index + 1].activate(camera, targetTexture?.texture);
  139. }
  140. else {
  141. if (targetTexture) {
  142. engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport);
  143. pp._outputTexture = targetTexture;
  144. }
  145. else {
  146. engine.restoreDefaultFramebuffer();
  147. pp._outputTexture = null;
  148. }
  149. engine._debugInsertMarker?.(`post process ${postProcesses[index].name} output`);
  150. }
  151. if (doNotPresent) {
  152. break;
  153. }
  154. const effect = pp.apply();
  155. if (effect) {
  156. pp.onBeforeRenderObservable.notifyObservers(effect);
  157. // VBOs
  158. this._prepareBuffers();
  159. engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
  160. // Draw order
  161. engine.drawElementsType(0, 0, 6);
  162. pp.onAfterRenderObservable.notifyObservers(effect);
  163. }
  164. }
  165. // Restore states
  166. engine.setDepthBuffer(true);
  167. engine.setDepthWrite(true);
  168. engine.setAlphaMode(0);
  169. }
  170. /**
  171. * Disposes of the post process manager.
  172. */
  173. dispose() {
  174. const buffer = this._vertexBuffers[VertexBuffer.PositionKind];
  175. if (buffer) {
  176. buffer.dispose();
  177. this._vertexBuffers[VertexBuffer.PositionKind] = null;
  178. }
  179. if (this._indexBuffer) {
  180. this._scene.getEngine()._releaseBuffer(this._indexBuffer);
  181. this._indexBuffer = null;
  182. }
  183. }
  184. }
  185. //# sourceMappingURL=postProcessManager.js.map