Sign in to follow this  
BMWPilote

Is there a way to set the default render target a MultiRenderTarget?

Recommended Posts

If we use post process (such as SSAO), we might want to render directly the depth and the normal when doing the main pass. Then we can avoid doing another pass by GeometryBufferRenderer. 

I know that we don't support the feature with built-in shaders. My question is if I use my own shaders. Is it feasible in the current Babylon code base? I can overwrite Babylon's built-in classes if needed.

 

Share this post


Link to post
Share on other sites

I found this (https://hacks.mozilla.org/2014/01/webgl-deferred-shading/). But it seems that this works only with WebGL1.0 + extension. How can it work with WebGL2.0?

 

Is it possible to overwrite the below function so that I can inject the "MRT stuff"? 

https://github.com/BabylonJS/Babylon.js/blob/cb2c6ebb583fabd07a03a2cbf6a95b43990f902a/src/Engine/babylon.engine.ts#L2394

 

Another way I am thinking is that if I write a class which inherit PostProcess and I override the activate function. Instead of creating a RenderTargetTexture, I can create a MultiRenderTargetTexutre. Is it feasible though?

https://github.com/BabylonJS/Babylon.js/blob/48b475ce095aa72e51eb31b89a624fcccd399950/src/PostProcess/babylon.postProcess.ts#L433

 

I really need this because performance is the first priority in my project.

 

Thanks you in advance.

Share this post


Link to post
Share on other sites

So you can have a look at how SSAO2 works: https://github.com/BabylonJS/Babylon.js/blob/master/src/PostProcess/RenderPipeline/Pipelines/babylon.ssao2RenderingPipeline.ts

It is using MRT and the GeometryBuffer to do multiple render at once.

 

If you want to create your own postprocess, this is the code you should get inspiration from

Share this post


Link to post
Share on other sites
9 hours ago, Deltakosh said:

So you can have a look at how SSAO2 works: https://github.com/BabylonJS/Babylon.js/blob/master/src/PostProcess/RenderPipeline/Pipelines/babylon.ssao2RenderingPipeline.ts

It is using MRT and the GeometryBuffer to do multiple render at once.

 

If you want to create your own postprocess, this is the code you should get inspiration from

I don’t want to create any Post process. I just want to have color depth and normal in one pass instead of two.

Share this post


Link to post
Share on other sites
On 8/6/2018 at 11:59 PM, Deltakosh said:

Yes but to do that you have to change the material shader (And thus you have to use your own one  as the Standard and PRB material won't support it)

Yes, I know.

So I modified the shader as below.

    gl_FragData[0] = finalColor;

#if defined(ID_BUFFER)
    #if defined(PACK_ID)
        gl_FragData[1] = dbId_modelId;
    #else
        gl_FragData[1] = vec4(dbId, modelId, 0.0, 1.0);
    #endif
#endif

#ifndef ALPHABLEND
    #ifdef LOGARITHMICDEPTH
        gl_FragData[DEPTH_INDEX] = vec4(vDepthMetric, log2(vFragmentDepth) * logarithmicDepthConstant * 0.5, vViewPos.z, 1.0);
    #else
        gl_FragData[DEPTH_INDEX] = vec4(vDepthMetric, gl_FragCoord.z, vViewPos.z, 1.0);
    #endif

    gl_FragData[DEPTH_INDEX + 1] = vec4(normalize(vNormalV), 1.0);
#endif

And I wrote a MRTPostProcess

import * as BABYLON from 'babylonjs';
export class MRTPostProcess extends BABYLON.PostProcess {

    private _textureCount: number;
    private _externalTextures: BABYLON.Texture[];

    constructor(name: string, textureCount: number, fragmentUrl: string, parameters: BABYLON.Nullable<string[]>, samplers: BABYLON.Nullable<string[]>, options: number | BABYLON.PostProcessOptions, camera: BABYLON.Nullable<BABYLON.Camera>,
        samplingMode: number = BABYLON.Texture.NEAREST_SAMPLINGMODE, engine?: BABYLON.Engine, reusable?: boolean, defines: BABYLON.Nullable<string> = null, textureType: number = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, vertexUrl: string = "postprocess", indexParameters?: any, blockCompilation = false) {

        super(name, fragmentUrl, parameters, samplers, options, camera, samplingMode, engine, reusable, defines, textureType, vertexUrl, indexParameters, blockCompilation);
        this._textureCount = textureCount;

        this.onAfterRenderObservable.add(() => {
            this.unbindFrameBuffer(engine);
        });
    }

    get textures(): BABYLON.SmartArray<BABYLON.InternalTexture> {
        return this._textures;
    }

    get externalTextures(): BABYLON.Texture[] {
        return this._externalTextures;
    }

    private _createExternalTextures(scene: BABYLON.Scene): void {
        this._externalTextures = [];
        for (var i = 0; i < this._textureCount; i++) {
            var texture = new BABYLON.Texture(null, scene, false, false, this.renderTargetSamplingMode);
            texture._texture = this._textures.data[i];
            this._externalTextures.push(texture);
        }
    }

    activate(camera: BABYLON.Nullable<BABYLON.Camera>, sourceTexture: BABYLON.Nullable<BABYLON.InternalTexture> = null, forceDepthStencil?: boolean): BABYLON.InternalTexture {
        camera = camera || this._camera;

        var scene = camera.getScene();
        var engine = scene.getEngine();
        var maxSize = engine.getCaps().maxTextureSize;

        var requiredWidth = ((sourceTexture ? sourceTexture.width : this._engine.getRenderWidth(true)) * <number>this._options) | 0;
        var requiredHeight = ((sourceTexture ? sourceTexture.height : this._engine.getRenderHeight(true)) * <number>this._options) | 0;

        // If rendering to a webvr camera's left or right eye only half the width should be used to avoid resize when rendered to screen
        var webVRCamera = (<BABYLON.WebVRFreeCamera>camera.parent);
        if (webVRCamera && (webVRCamera.leftCamera == camera || webVRCamera.rightCamera == camera)) {
            requiredWidth /= 2;
        }

        var desiredWidth = ((<BABYLON.PostProcessOptions>this._options).width || requiredWidth);
        var desiredHeight = (<BABYLON.PostProcessOptions>this._options).height || requiredHeight;

        if (!this._shareOutputWithPostProcess && !this._forcedOutputTexture) {

            if (this.adaptScaleToCurrentViewport) {
                let currentViewport = engine.currentViewport;

                if (currentViewport) {
                    desiredWidth *= currentViewport.width;
                    desiredHeight *= currentViewport.height;
                }
            }

            if (this.renderTargetSamplingMode === BABYLON.Texture.TRILINEAR_SAMPLINGMODE || this.alwaysForcePOT) {
                if (!(<BABYLON.PostProcessOptions>this._options).width) {
                    desiredWidth = engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(desiredWidth, maxSize, this.scaleMode) : desiredWidth;
                }

                if (!(<BABYLON.PostProcessOptions>this._options).height) {
                    desiredHeight = engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(desiredHeight, maxSize, this.scaleMode) : desiredHeight;
                }
            }

            if (this.width !== desiredWidth || this.height !== desiredHeight) {
                if (this._textures.length > 0) {
                    for (var i = 0; i < this._textures.length; i++) {
                        this._engine._releaseTexture(this._textures.data[i]);
                    }
                    this._textures.reset();
                }
                this.width = desiredWidth;
                this.height = desiredHeight;

                let textureSize = { width: this.width, height: this.height };
                var types = [];
                var samplingModes = [];
                for (var i = 0; i < this._textureCount; i++) {
                    types.push(this._textureType);
                    samplingModes.push(this.renderTargetSamplingMode);
                }
                let textureOptions = {
                    generateMipMaps: false,
                    generateDepthBuffer: forceDepthStencil || camera._postProcesses.indexOf(this) === 0,
                    generateStencilBuffer: (forceDepthStencil || camera._postProcesses.indexOf(this) === 0) && this._engine.isStencilEnable,
                    samplingModes: samplingModes,
                    types: types,
                    textureCount: this._textureCount
                };

                this._textures.concat(this._engine.createMultipleRenderTarget(textureSize, textureOptions));
                this._createExternalTextures(scene);

                if (this._reusable) {
                    this._textures.concat(this._engine.createMultipleRenderTarget(textureSize, textureOptions));
                }

                this._texelSize.copyFromFloats(1.0 / this.width, 1.0 / this.height);

                this.onSizeChangedObservable.notifyObservers(this);
            }

            this._textures.forEach(texture => {
                if (texture.samples !== this.samples) {
                    this._engine.updateRenderTargetTextureSampleCount(texture, this.samples);
                }
            });
        }

        var target: BABYLON.InternalTexture;

        if (this._shareOutputWithPostProcess) {
            target = this._shareOutputWithPostProcess.inputTexture;
        } else if (this._forcedOutputTexture) {
            target = this._forcedOutputTexture;

            this.width = this._forcedOutputTexture.width;
            this.height = this._forcedOutputTexture.height;
        } else {
            target = this.inputTexture;
        }

        // Bind the input of this post process to be used as the output of the previous post process.
        if (this.enablePixelPerfectMode) {
            this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
            this._engine.bindFramebuffer(target, 0, requiredWidth, requiredHeight, true);
        }
        else {
            this._scaleRatio.copyFromFloats(1, 1);
            this._engine.bindFramebuffer(target, 0, undefined, undefined, true);
        }

        this.onActivateObservable.notifyObservers(camera);

        // Clear
        if (this.autoClear && this.alphaMode === BABYLON.Engine.ALPHA_DISABLE) {
            this._engine.clear(this.clearColor ? this.clearColor : scene.clearColor, true, true, true);
        }

        if (this._reusable) {
            this._currentRenderTextureInd = (this._currentRenderTextureInd + this._textureCount) % (this._textureCount + 1);
        }
        return target;
    }


    unbindFrameBuffer(engine: BABYLON.Engine): void {
        let internalTextures: BABYLON.InternalTexture[] = [];
        for (var i = 0; i < this._textureCount; i++) {
            internalTextures.push(this._textures.data[i]);
        }
        engine.unBindMultiColorAttachmentFramebuffer(internalTextures, false, () => { });
    }
}

 

It seems to work so far...

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.