|
@@ -1,5 +1,6 @@
|
|
|
import { Nullable } from '../types';
|
|
|
-import { Texture } from '../Materials/Textures/texture';
|
|
|
+import { InternalTexture } from './Textures/internalTexture';
|
|
|
+import { RenderTargetTexture } from './Textures/renderTargetTexture';
|
|
|
import { ThinEngine } from '../Engines/thinEngine';
|
|
|
import { VertexBuffer } from '../Meshes/buffer';
|
|
|
import { Viewport } from '../Maths/math.viewport';
|
|
@@ -8,8 +9,6 @@ import { Observable } from '../Misc/observable';
|
|
|
import { Effect } from './effect';
|
|
|
import { DataBuffer } from '../Meshes/dataBuffer';
|
|
|
|
|
|
-import "../Engines/Extensions/engine.renderTarget";
|
|
|
-
|
|
|
// Prevents ES6 Crash if not imported.
|
|
|
import "../Shaders/postprocess.vertex";
|
|
|
|
|
@@ -28,50 +27,21 @@ export interface IEffectRendererOptions {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 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],
|
|
|
};
|
|
|
|
|
|
private _vertexBuffers: {[key: string]: VertexBuffer};
|
|
|
private _indexBuffer: DataBuffer;
|
|
|
|
|
|
- private _ringBufferIndex = 0;
|
|
|
- private _ringScreenBuffer: Nullable<Array<Texture>> = null;
|
|
|
private _fullscreenViewport = new Viewport(0, 0, 1, 1);
|
|
|
|
|
|
- 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),
|
|
|
- },
|
|
|
- {
|
|
|
- generateDepthBuffer: false,
|
|
|
- generateStencilBuffer: false,
|
|
|
- generateMipMaps: false,
|
|
|
- samplingMode: Constants.TEXTURE_NEAREST_NEAREST,
|
|
|
- },
|
|
|
- );
|
|
|
- var texture = new Texture("", null);
|
|
|
- texture._texture = internalTexture;
|
|
|
- this._ringScreenBuffer.push(texture);
|
|
|
- }
|
|
|
- }
|
|
|
- var ret = this._ringScreenBuffer[this._ringBufferIndex];
|
|
|
- if (incrementIndex) {
|
|
|
- this._ringBufferIndex = (this._ringBufferIndex + 1) % 2;
|
|
|
- }
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Creates an effect renderer
|
|
|
* @param engine the engine to use for rendering
|
|
@@ -87,10 +57,6 @@ export class EffectRenderer {
|
|
|
[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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -116,6 +82,8 @@ export class EffectRenderer {
|
|
|
* @param effectWrapper Defines the effect to draw with
|
|
|
*/
|
|
|
public applyEffectWrapper(effectWrapper: EffectWrapper): void {
|
|
|
+ this.engine.depthCullingState.depthTest = false;
|
|
|
+ this.engine.stencilState.stencilTest = false;
|
|
|
this.engine.enableEffect(effectWrapper.effect);
|
|
|
this.bindBuffers(effectWrapper.effect);
|
|
|
effectWrapper.onApplyObservable.notifyObservers({});
|
|
@@ -128,68 +96,43 @@ export class EffectRenderer {
|
|
|
this.engine.drawElementsType(Constants.MATERIAL_TriangleFillMode, 0, 6);
|
|
|
}
|
|
|
|
|
|
+ private isRenderTargetTexture(texture: InternalTexture | RenderTargetTexture): texture is RenderTargetTexture {
|
|
|
+ return (texture as RenderTargetTexture).renderList !== undefined;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 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 effectWrapper the effect to renderer
|
|
|
+ * @param outputTexture texture to draw to, if null it will render to the screen.
|
|
|
*/
|
|
|
- public render(effectWrappers: Array<EffectWrapper> | EffectWrapper, outputTexture: Nullable<Texture> = null) {
|
|
|
- if (!Array.isArray(effectWrappers)) {
|
|
|
- effectWrappers = [effectWrappers];
|
|
|
+ public render(effectWrapper: EffectWrapper, outputTexture: Nullable<InternalTexture | RenderTargetTexture> = null) {
|
|
|
+ // Ensure effect is ready
|
|
|
+ if (!effectWrapper.effect.isReady()) {
|
|
|
+ return ;
|
|
|
}
|
|
|
|
|
|
- // Ensure all effects are ready
|
|
|
- for (var wrapper of effectWrappers) {
|
|
|
- if (!wrapper.effect.isReady()) {
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
+ // Reset state
|
|
|
+ this.setViewport();
|
|
|
|
|
|
- effectWrappers.forEach((effectWrapper, i) => {
|
|
|
- var renderTo = outputTexture;
|
|
|
+ const out = outputTexture === null ? null : this.isRenderTargetTexture(outputTexture) ? outputTexture.getInternalTexture()! : outputTexture;
|
|
|
|
|
|
- // for any next effect make it's input the output of the previous effect
|
|
|
- if (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) {
|
|
|
- renderTo = this._getNextFrameBuffer();
|
|
|
- } else {
|
|
|
- renderTo = outputTexture;
|
|
|
- }
|
|
|
-
|
|
|
- // Reset state
|
|
|
- this.setViewport();
|
|
|
-
|
|
|
- if (renderTo) {
|
|
|
- this.engine.bindFramebuffer(renderTo.getInternalTexture()!);
|
|
|
- }
|
|
|
+ if (out) {
|
|
|
+ this.engine.bindFramebuffer(out);
|
|
|
+ }
|
|
|
|
|
|
- this.applyEffectWrapper(effectWrapper);
|
|
|
+ this.applyEffectWrapper(effectWrapper);
|
|
|
|
|
|
- this.draw();
|
|
|
+ this.draw();
|
|
|
|
|
|
- if (renderTo) {
|
|
|
- this.engine.unBindFramebuffer(renderTo.getInternalTexture()!);
|
|
|
- }
|
|
|
- });
|
|
|
+ if (out) {
|
|
|
+ this.engine.unBindFramebuffer(out);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Disposes of the effect renderer
|
|
|
*/
|
|
|
dispose() {
|
|
|
- if (this._ringScreenBuffer) {
|
|
|
- this._ringScreenBuffer.forEach((b) => {
|
|
|
- b.dispose();
|
|
|
- });
|
|
|
- this._ringScreenBuffer = null;
|
|
|
- }
|
|
|
-
|
|
|
var vertexBuffer = this._vertexBuffers[VertexBuffer.PositionKind];
|
|
|
if (vertexBuffer) {
|
|
|
vertexBuffer.dispose();
|