BMWPilote Posted August 3, 2018 Share Posted August 3, 2018 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. Quote Link to comment Share on other sites More sharing options...
BMWPilote Posted August 3, 2018 Author Share Posted August 3, 2018 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. Quote Link to comment Share on other sites More sharing options...
Guest Posted August 3, 2018 Share Posted August 3, 2018 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 Quote Link to comment Share on other sites More sharing options...
BMWPilote Posted August 4, 2018 Author Share Posted August 4, 2018 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. Quote Link to comment Share on other sites More sharing options...
Guest Posted August 6, 2018 Share Posted August 6, 2018 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) Quote Link to comment Share on other sites More sharing options...
BMWPilote Posted August 8, 2018 Author Share Posted August 8, 2018 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... Quote Link to comment Share on other sites More sharing options...
BMWPilote Posted August 8, 2018 Author Share Posted August 8, 2018 There is one thing that I am still confused which is the "reusable" flag. Although I don't use it. I am not sure how to modify the code to adapt to MRT. Quote Link to comment Share on other sites More sharing options...
Guest Posted August 8, 2018 Share Posted August 8, 2018 reusable is mostly for postprocesses that are inside a pipeline and that needs to be reuse at different stage of that pipeline Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.