|
@@ -25,16 +25,31 @@ export interface IEffectRendererOptions {
|
|
|
* Defines the indices.
|
|
|
*/
|
|
|
indices?: number[];
|
|
|
+ /**
|
|
|
+ * width of the textures created by the effect renderer. By default, textures are created the same size than the canvas
|
|
|
+ */
|
|
|
+ textureWidth?: number;
|
|
|
+ /**
|
|
|
+ * height of the textures created by the effect renderer. By default, textures are created the same size than the canvas
|
|
|
+ */
|
|
|
+ textureHeight?: number;
|
|
|
+ /**
|
|
|
+ * Flip between the two internal textures for input/output and does not use the outputTexture parameter of the render function
|
|
|
+ * To get the texture used for the latest rendering, read the outputTexture property
|
|
|
+ */
|
|
|
+ useInternalTexturesOnly?: boolean;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Helper class to render one or more effects
|
|
|
+ * Helper class to render one or more effects.
|
|
|
+ * You can access the previous rendering in your shader by declaring a sampler named textureSampler
|
|
|
*/
|
|
|
export class EffectRenderer {
|
|
|
// Fullscreen quad buffers by default.
|
|
|
private static _DefaultOptions: IEffectRendererOptions = {
|
|
|
positions: [1, 1, -1, 1, -1, -1, 1, -1],
|
|
|
- indices: [0, 1, 2, 0, 2, 3]
|
|
|
+ indices: [0, 1, 2, 0, 2, 3],
|
|
|
+ useInternalTexturesOnly: false,
|
|
|
};
|
|
|
|
|
|
private _vertexBuffers: {[key: string]: VertexBuffer};
|
|
@@ -44,14 +59,39 @@ export class EffectRenderer {
|
|
|
private _ringScreenBuffer: Nullable<Array<Texture>> = null;
|
|
|
private _fullscreenViewport = new Viewport(0, 0, 1, 1);
|
|
|
|
|
|
+ private _outputTexture: Nullable<Texture>;
|
|
|
+ /**
|
|
|
+ * Get the texture used for the latest rendering. If useInternalTexturesOnly is false and you passed null
|
|
|
+ * to the render function, you will get null here
|
|
|
+ */
|
|
|
+ public get outputTexture(): Nullable<Texture> {
|
|
|
+ return this._outputTexture;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * width of the textures created by the effect renderer. By default, textures are created the same size than the canvas
|
|
|
+ */
|
|
|
+ public textureWidth: number | undefined;
|
|
|
+ /**
|
|
|
+ * height of the textures created by the effect renderer. By default, textures are created the same size than the canvas
|
|
|
+ */
|
|
|
+ public textureHeight: number | undefined;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Flip between the two internal textures for input/output and does not use the outputTexture parameter of the render function
|
|
|
+ * To get the texture used for the latest rendering, use outputTexture. In this mode, you can use the previous rendering texture
|
|
|
+ * with a sampler name textureSampler in your shader
|
|
|
+ */
|
|
|
+ public useInternalTexturesOnly: boolean = false;
|
|
|
+
|
|
|
private _getNextFrameBuffer(incrementIndex = true) {
|
|
|
if (!this._ringScreenBuffer) {
|
|
|
this._ringScreenBuffer = [];
|
|
|
for (var i = 0; i < 2; i++) {
|
|
|
var internalTexture = this.engine.createRenderTargetTexture(
|
|
|
{
|
|
|
- width: this.engine.getRenderWidth(true),
|
|
|
- height: this.engine.getRenderHeight(true),
|
|
|
+ width: this.textureWidth ?? this.engine.getRenderWidth(true),
|
|
|
+ height: this.textureHeight ?? this.engine.getRenderHeight(true),
|
|
|
},
|
|
|
{
|
|
|
generateDepthBuffer: false,
|
|
@@ -83,14 +123,14 @@ export class EffectRenderer {
|
|
|
...options,
|
|
|
};
|
|
|
|
|
|
+ this.textureWidth = options.textureWidth;
|
|
|
+ this.textureHeight = options.textureHeight;
|
|
|
+ this.useInternalTexturesOnly = options.useInternalTexturesOnly ?? false;
|
|
|
+
|
|
|
this._vertexBuffers = {
|
|
|
[VertexBuffer.PositionKind]: new VertexBuffer(engine, options.positions!, VertexBuffer.PositionKind, false, false, 2),
|
|
|
};
|
|
|
this._indexBuffer = engine.createIndexBuffer(options.indices!);
|
|
|
-
|
|
|
- // No need here for full screen render.
|
|
|
- engine.depthCullingState.depthTest = false;
|
|
|
- engine.stencilState.stencilTest = false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -131,9 +171,10 @@ export class EffectRenderer {
|
|
|
/**
|
|
|
* renders one or more effects to a specified texture
|
|
|
* @param effectWrappers list of effects to renderer
|
|
|
- * @param outputTexture texture to draw to, if null it will render to the screen
|
|
|
+ * @param outputTexture texture to draw to, if null it will render to the screen. Note that this parameter is not used if useInternalTexturesOnly is true
|
|
|
+ * @returns returns the texture used for the latest rendering
|
|
|
*/
|
|
|
- public render(effectWrappers: Array<EffectWrapper> | EffectWrapper, outputTexture: Nullable<Texture> = null) {
|
|
|
+ public render(effectWrappers: Array<EffectWrapper> | EffectWrapper, outputTexture: Nullable<Texture> = null): Nullable<Texture> {
|
|
|
if (!Array.isArray(effectWrappers)) {
|
|
|
effectWrappers = [effectWrappers];
|
|
|
}
|
|
@@ -141,22 +182,28 @@ export class EffectRenderer {
|
|
|
// Ensure all effects are ready
|
|
|
for (var wrapper of effectWrappers) {
|
|
|
if (!wrapper.effect.isReady()) {
|
|
|
- return;
|
|
|
+ return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // No need here for full screen render.
|
|
|
+ this.engine.depthCullingState.depthTest = false;
|
|
|
+ this.engine.stencilState.stencilTest = false;
|
|
|
+
|
|
|
+ var renderTo = outputTexture;
|
|
|
+
|
|
|
effectWrappers.forEach((effectWrapper, i) => {
|
|
|
- var renderTo = outputTexture;
|
|
|
+ renderTo = outputTexture;
|
|
|
|
|
|
// for any next effect make it's input the output of the previous effect
|
|
|
- if (i !== 0) {
|
|
|
+ if (this.useInternalTexturesOnly || i !== 0) {
|
|
|
effectWrapper.effect.onBindObservable.addOnce(() => {
|
|
|
effectWrapper.effect.setTexture("textureSampler", this._getNextFrameBuffer(false));
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// Set the output to the next screenbuffer
|
|
|
- if ((effectWrappers as Array<EffectWrapper>).length > 1 && i != (effectWrappers as Array<EffectWrapper>).length - 1) {
|
|
|
+ if (this.useInternalTexturesOnly || (effectWrappers as Array<EffectWrapper>).length > 1 && i != (effectWrappers as Array<EffectWrapper>).length - 1) {
|
|
|
renderTo = this._getNextFrameBuffer();
|
|
|
} else {
|
|
|
renderTo = outputTexture;
|
|
@@ -177,6 +224,10 @@ export class EffectRenderer {
|
|
|
this.engine.unBindFramebuffer(renderTo.getInternalTexture()!);
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
+ this._outputTexture = renderTo;
|
|
|
+
|
|
|
+ return renderTo;
|
|
|
}
|
|
|
|
|
|
/**
|