@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
192 lines (191 loc) • 7.96 kB
JavaScript
import { VertexBuffer } from "../Buffers/buffer.js";
import { Observable } from "../Misc/observable.js";
/**
* PostProcessManager is used to manage one or more post processes or post process pipelines
* See https://doc.babylonjs.com/features/featuresDeepDive/postProcesses/usePostProcesses
*/
export class PostProcessManager {
/**
* Creates a new instance PostProcess
* @param scene The scene that the post process is associated with.
*/
constructor(scene) {
this._vertexBuffers = {};
this.onBeforeRenderObservable = new Observable();
this._scene = scene;
}
_prepareBuffers() {
if (this._vertexBuffers[VertexBuffer.PositionKind]) {
return;
}
// VBO
const vertices = [];
vertices.push(1, 1);
vertices.push(-1, 1);
vertices.push(-1, -1);
vertices.push(1, -1);
this._vertexBuffers[VertexBuffer.PositionKind] = new VertexBuffer(this._scene.getEngine(), vertices, VertexBuffer.PositionKind, false, false, 2);
this._buildIndexBuffer();
}
_buildIndexBuffer() {
// Indices
const indices = [];
indices.push(0);
indices.push(1);
indices.push(2);
indices.push(0);
indices.push(2);
indices.push(3);
this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
}
/**
* Rebuilds the vertex buffers of the manager.
* @internal
*/
_rebuild() {
const vb = this._vertexBuffers[VertexBuffer.PositionKind];
if (!vb) {
return;
}
vb._rebuild();
this._buildIndexBuffer();
}
// Methods
/**
* Prepares a frame to be run through a post process.
* @param sourceTexture The input texture to the post processes. (default: null)
* @param postProcesses An array of post processes to be run. (default: null)
* @returns True if the post processes were able to be run.
* @internal
*/
_prepareFrame(sourceTexture = null, postProcesses = null) {
const camera = this._scene.activeCamera;
if (!camera) {
return false;
}
postProcesses = postProcesses || camera._postProcesses.filter((pp) => {
return pp != null;
});
if (!postProcesses || postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
return false;
}
postProcesses[0].activate(camera, sourceTexture, postProcesses !== null && postProcesses !== undefined);
return true;
}
/**
* Manually render a set of post processes to a texture.
* Please note, the frame buffer won't be unbound after the call in case you have more render to do.
* @param postProcesses An array of post processes to be run.
* @param targetTexture The render target wrapper to render to.
* @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight
* @param faceIndex defines the face to render to if a cubemap is defined as the target
* @param lodLevel defines which lod of the texture to render to
* @param doNotBindFrambuffer If set to true, assumes that the framebuffer has been bound previously
* @param numPostsProcesses The number of post processes to render. Defaults to the length of the postProcesses array.
*/
directRender(postProcesses, targetTexture = null, forceFullscreenViewport = false, faceIndex = 0, lodLevel = 0, doNotBindFrambuffer = false, numPostsProcesses = postProcesses.length) {
const engine = this._scene.getEngine();
for (let index = 0; index < numPostsProcesses; index++) {
if (index < postProcesses.length - 1) {
postProcesses[index + 1].activate(this._scene.activeCamera || this._scene, targetTexture?.texture);
}
else {
if (targetTexture) {
engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport, lodLevel);
}
else if (!doNotBindFrambuffer) {
engine.restoreDefaultFramebuffer();
}
engine._debugInsertMarker?.(`post process ${postProcesses[index].name} output`);
}
const pp = postProcesses[index];
const effect = pp.apply();
if (effect) {
pp.onBeforeRenderObservable.notifyObservers(effect);
// VBOs
this._prepareBuffers();
engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
// Draw order
engine.drawElementsType(0, 0, 6);
pp.onAfterRenderObservable.notifyObservers(effect);
}
}
// Restore depth buffer
engine.setDepthBuffer(true);
engine.setDepthWrite(true);
}
/**
* Finalize the result of the output of the postprocesses.
* @param doNotPresent If true the result will not be displayed to the screen.
* @param targetTexture The render target wrapper to render to.
* @param faceIndex The index of the face to bind the target texture to.
* @param postProcesses The array of post processes to render.
* @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight (default: false)
* @internal
*/
_finalizeFrame(doNotPresent, targetTexture, faceIndex, postProcesses, forceFullscreenViewport = false) {
const camera = this._scene.activeCamera;
if (!camera) {
return;
}
this.onBeforeRenderObservable.notifyObservers(this);
postProcesses =
postProcesses ||
camera._postProcesses.filter((pp) => {
return pp != null;
});
if (postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
return;
}
const engine = this._scene.getEngine();
for (let index = 0, len = postProcesses.length; index < len; index++) {
const pp = postProcesses[index];
if (index < len - 1) {
pp._outputTexture = postProcesses[index + 1].activate(camera, targetTexture?.texture);
}
else {
if (targetTexture) {
engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport);
pp._outputTexture = targetTexture;
}
else {
engine.restoreDefaultFramebuffer();
pp._outputTexture = null;
}
engine._debugInsertMarker?.(`post process ${postProcesses[index].name} output`);
}
if (doNotPresent) {
break;
}
const effect = pp.apply();
if (effect) {
pp.onBeforeRenderObservable.notifyObservers(effect);
// VBOs
this._prepareBuffers();
engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
// Draw order
engine.drawElementsType(0, 0, 6);
pp.onAfterRenderObservable.notifyObservers(effect);
}
}
// Restore states
engine.setDepthBuffer(true);
engine.setDepthWrite(true);
engine.setAlphaMode(0);
}
/**
* Disposes of the post process manager.
*/
dispose() {
const buffer = this._vertexBuffers[VertexBuffer.PositionKind];
if (buffer) {
buffer.dispose();
this._vertexBuffers[VertexBuffer.PositionKind] = null;
}
if (this._indexBuffer) {
this._scene.getEngine()._releaseBuffer(this._indexBuffer);
this._indexBuffer = null;
}
}
}
//# sourceMappingURL=postProcessManager.js.map