123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- import { Nullable } from '../types';
- import { Texture } from '../Materials/Textures/texture';
- import { ThinEngine } from '../Engines/thinEngine';
- import { VertexBuffer } from '../Meshes/buffer';
- import { Viewport } from '../Maths/math.viewport';
- import { Constants } from '../Engines/constants';
- 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";
- /**
- * Effect Render Options
- */
- export interface IEffectRendererOptions {
- /**
- * Defines the vertices positions.
- */
- positions?: number[];
- /**
- * Defines the indices.
- */
- indices?: number[];
- }
- /**
- * Helper class to render one or more effects
- */
- 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]
- };
- 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
- * @param options defines the options of the effect renderer
- */
- constructor(private engine: ThinEngine, options: IEffectRendererOptions = EffectRenderer._DefaultOptions) {
- options = {
- ...EffectRenderer._DefaultOptions,
- ...options,
- };
- 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;
- }
- /**
- * Sets the current viewport in normalized coordinates 0-1
- * @param viewport Defines the viewport to set (defaults to 0 0 1 1)
- */
- public setViewport(viewport = this._fullscreenViewport): void {
- this.engine.setViewport(viewport);
- }
- /**
- * Binds the embedded attributes buffer to the effect.
- * @param effect Defines the effect to bind the attributes for
- */
- public bindBuffers(effect: Effect): void {
- this.engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
- }
- /**
- * Sets the current effect wrapper to use during draw.
- * The effect needs to be ready before calling this api.
- * This also sets the default full screen position attribute.
- * @param effectWrapper Defines the effect to draw with
- */
- public applyEffectWrapper(effectWrapper: EffectWrapper): void {
- this.engine.enableEffect(effectWrapper.effect);
- this.bindBuffers(effectWrapper.effect);
- effectWrapper.onApplyObservable.notifyObservers({});
- }
- /**
- * Draws a full screen quad.
- */
- public draw(): void {
- this.engine.drawElementsType(Constants.MATERIAL_TriangleFillMode, 0, 6);
- }
- /**
- * 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
- */
- public render(effectWrappers: Array<EffectWrapper> | EffectWrapper, outputTexture: Nullable<Texture> = null) {
- if (!Array.isArray(effectWrappers)) {
- effectWrappers = [effectWrappers];
- }
- // Ensure all effects are ready
- for (var wrapper of effectWrappers) {
- if (!wrapper.effect.isReady()) {
- return;
- }
- }
- effectWrappers.forEach((effectWrapper, i) => {
- var renderTo = 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();
- this.applyEffectWrapper(effectWrapper);
- if (renderTo) {
- this.engine.bindFramebuffer(renderTo.getInternalTexture()!);
- }
- this.draw();
- if (renderTo) {
- this.engine.unBindFramebuffer(renderTo.getInternalTexture()!);
- }
- });
- }
- /**
- * 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();
- delete this._vertexBuffers[VertexBuffer.PositionKind];
- }
- if (this._indexBuffer) {
- this.engine._releaseBuffer(this._indexBuffer);
- }
- }
- }
- /**
- * Options to create an EffectWrapper
- */
- interface EffectWrapperCreationOptions {
- /**
- * Engine to use to create the effect
- */
- engine: ThinEngine;
- /**
- * Fragment shader for the effect
- */
- fragmentShader: string;
- /**
- * Vertex shader for the effect
- */
- vertexShader?: string;
- /**
- * Attributes to use in the shader
- */
- attributeNames?: Array<string>;
- /**
- * Uniforms to use in the shader
- */
- uniformNames?: Array<string>;
- /**
- * Texture sampler names to use in the shader
- */
- samplerNames?: Array<string>;
- /**
- * The friendly name of the effect displayed in Spector.
- */
- name?: string;
- }
- /**
- * Wraps an effect to be used for rendering
- */
- export class EffectWrapper {
- /**
- * Event that is fired right before the effect is drawn (should be used to update uniforms)
- */
- public onApplyObservable = new Observable<{}>();
- /**
- * The underlying effect
- */
- public effect: Effect;
- /**
- * Creates an effect to be renderer
- * @param creationOptions options to create the effect
- */
- constructor(creationOptions: EffectWrapperCreationOptions) {
- let effectCreationOptions: any;
- const uniformNames = creationOptions.uniformNames || [];
- if (creationOptions.vertexShader) {
- effectCreationOptions = {
- fragmentSource: creationOptions.fragmentShader,
- vertexSource: creationOptions.vertexShader,
- spectorName: creationOptions.name || "effectWrapper"
- };
- }
- else {
- // Default scale to use in post process vertex shader.
- uniformNames.push("scale");
- effectCreationOptions = {
- fragmentSource: creationOptions.fragmentShader,
- vertex: "postprocess",
- spectorName: creationOptions.name || "effectWrapper"
- };
- // Sets the default scale to identity for the post process vertex shader.
- this.onApplyObservable.add(() => {
- this.effect.setFloat2("scale", 1, 1);
- });
- }
- this.effect = new Effect(effectCreationOptions,
- creationOptions.attributeNames || ["position"],
- uniformNames,
- creationOptions.samplerNames,
- creationOptions.engine);
- }
- /**
- * Disposes of the effect wrapper
- */
- public dispose() {
- this.effect.dispose();
- }
- }
|