Prechádzať zdrojové kódy

removing composition when not needed

Benjamin Guignabert 4 rokov pred
rodič
commit
693f5d8bcf

+ 6 - 6
src/Materials/Textures/multiRenderTarget.ts

@@ -202,9 +202,6 @@ export class MultiRenderTarget extends RenderTargetTexture {
             texture._texture = this._internalTextures[i];
         }
 
-        // Keeps references to frame buffer and stencil/depth buffer
-        this._texture = this._internalTextures[0];
-
         if (this.samples !== 1) {
             this._getEngine()!.updateMultipleRenderTargetTextureSampleCount(this._internalTextures, this.samples);
         }
@@ -212,6 +209,9 @@ export class MultiRenderTarget extends RenderTargetTexture {
 
     private _createInternalTextures(): void {
         this._internalTextures = this._getEngine()!.createMultipleRenderTarget(this._size, this._multiRenderTargetOptions);
+
+        // Keeps references to frame buffer and stencil/depth buffer
+        this._texture = this._internalTextures[0];
     }
 
     private _createTextures(): void {
@@ -221,9 +221,6 @@ export class MultiRenderTarget extends RenderTargetTexture {
             texture._texture = this._internalTextures[i];
             this._textures.push(texture);
         }
-
-        // Keeps references to frame buffer and stencil/depth buffer
-        this._texture = this._internalTextures[0];
     }
 
     /**
@@ -235,6 +232,9 @@ export class MultiRenderTarget extends RenderTargetTexture {
         if (texture._texture) {
             this._textures[index] = texture;
             this._internalTextures[index] = texture._texture;
+            if (index === 0) {
+                this._texture = this._internalTextures[index];
+            }
         }
     }
 

+ 18 - 12
src/Materials/Textures/prePassRenderTarget.ts

@@ -36,6 +36,9 @@ export class PrePassRenderTarget extends MultiRenderTarget {
     public _engine: Engine;
     public _scene: Scene;
 
+    public _outputPostProcess: Nullable<PostProcess>;
+    public _internalTextureDirty = false;
+
     /**
       * Is this render target enabled for prepass rendering
       */
@@ -63,16 +66,8 @@ export class PrePassRenderTarget extends MultiRenderTarget {
      * Checks that the size of this RT is still adapted to the desired render size.
      */
     public _checkSize() {
-        var requiredWidth;
-        var requiredHeight;
-
-        if (this.renderTargetTexture) {
-        	requiredWidth = this.renderTargetTexture.getRenderWidth();
-        	requiredHeight = this.renderTargetTexture.getRenderHeight();
-        } else {
-        	requiredWidth = this._engine.getRenderWidth(true);
-        	requiredHeight = this._engine.getRenderHeight(true);
-        }
+        var	requiredWidth = this._engine.getRenderWidth(true);
+        var	requiredHeight = this._engine.getRenderHeight(true);
         
         var width = this.getRenderWidth();
         var height = this.getRenderHeight();
@@ -80,11 +75,22 @@ export class PrePassRenderTarget extends MultiRenderTarget {
         if (width !== requiredWidth || height !== requiredHeight) {
             this.resize({ width: requiredWidth, height: requiredHeight });
 
-            // TODO : geometry buffer ?
-            // this._updateGeometryBufferLayout();
+            this._internalTextureDirty = true;
         }
     }
 
+
+    /**
+     * Changes the number of render targets in this MRT
+     * Be careful as it will recreate all the data in the new texture.
+     * @param count new texture count
+     * @param options Specifies texture types and sampling modes for new textures
+     */
+    public updateCount(count: number, options?: IMultiRenderTargetOptions) {
+        super.updateCount(count, options);
+        this._internalTextureDirty = true;
+    }
+
     /**
      * Resets the post processes chains applied to this RT.
      */

+ 22 - 0
src/Materials/Textures/renderTargetTexture.ts

@@ -501,6 +501,28 @@ export class RenderTargetTexture extends Texture {
         }
     }
 
+    public cloneCameraPostProcesses(camera?: Camera): void {
+        const scene = this.getScene();
+        const sourceCamera = camera || scene && scene.activeCamera;
+
+        if (!sourceCamera) {
+            return;
+        }
+        
+        this.clearPostProcesses(true);
+
+        for (let i = 0; i < sourceCamera._postProcesses.length; i++) {
+            const postProcess = sourceCamera._postProcesses[i]?.clone();
+            if (postProcess) {
+                this.addPostProcess(postProcess);
+            }
+        }
+
+        if (scene?._prePassRenderer) {
+            scene._prePassRenderer.markAsDirty();
+        }
+    }
+
     /** @hidden */
     public _shouldRender(): boolean {
         if (this._currentRefreshId === -1) { // At least render once

+ 2 - 2
src/PostProcesses/passPostProcess.ts

@@ -45,7 +45,7 @@ export class PassPostProcess extends PostProcess {
                 parsedPostProcess.name,
                 parsedPostProcess.options, targetCamera,
                 parsedPostProcess.renderTargetSamplingMode,
-                scene.getEngine(), parsedPostProcess.reusable);
+                parsedPostProcess._engine, parsedPostProcess.reusable);
         }, parsedPostProcess, scene, rootUrl);
     }
 }
@@ -129,7 +129,7 @@ export class PassCubePostProcess extends PostProcess {
                 parsedPostProcess.name,
                 parsedPostProcess.options, targetCamera,
                 parsedPostProcess.renderTargetSamplingMode,
-                scene.getEngine(), parsedPostProcess.reusable);
+                parsedPostProcess._engine, parsedPostProcess.reusable);
         }, parsedPostProcess, scene, rootUrl);
     }
 }

+ 62 - 8
src/PostProcesses/postProcess.ts

@@ -182,6 +182,7 @@ export class PostProcess {
     private _fragmentUrl: string;
     private _vertexUrl: string;
     private _parameters: string[];
+    protected _postProcessDefines: Nullable<string>;
     private _scaleRatio = new Vector2(1, 1);
     protected _indexParameters: any;
     private _shareOutputWithPostProcess: Nullable<PostProcess>;
@@ -455,6 +456,7 @@ export class PostProcess {
      */
     public updateEffect(defines: Nullable<string> = null, uniforms: Nullable<string[]> = null, samplers: Nullable<string[]> = null, indexParameters?: any,
         onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void, vertexUrl?: string, fragmentUrl?: string) {
+        this._postProcessDefines = defines;
         this._effect = this._engine.createEffect({ vertex: vertexUrl ?? this._vertexUrl, fragment: fragmentUrl ?? this._fragmentUrl },
             ["position"],
             uniforms || this._parameters,
@@ -752,16 +754,50 @@ export class PostProcess {
      */
     public serialize(): any {
         var serializationObject = SerializationHelper.Serialize(this);
+        var camera = this.getCamera() || this._scene && this._scene.activeCamera;
         serializationObject.customType = "BABYLON." + this.getClassName();
-        serializationObject.cameraId = this.getCamera().id;
+        serializationObject.cameraId = camera ? camera.id : null;
         serializationObject.reusable = this._reusable;
-        serializationObject.options = this._options;
         serializationObject.textureType = this._textureType;
+        serializationObject.fragmentUrl = this._fragmentUrl;
+        serializationObject.parameters = this._parameters;
+        serializationObject.samplers = this._samplers;
+        serializationObject.options = this._options;
+        serializationObject.defines = this._postProcessDefines;
+        serializationObject.textureFormat = this._textureFormat;
+        serializationObject.vertexUrl = this._vertexUrl;
+        serializationObject.indexParameters = this._indexParameters;
 
         return serializationObject;
     }
 
     /**
+     * Clones this post process
+     * @returns a new post process similar to this one
+     */
+    public clone(): Nullable<PostProcess> {
+        const serializationObject = this.serialize();
+        serializationObject._engine = this._engine;
+        serializationObject.cameraId = null;
+
+        const result = PostProcess.Parse(serializationObject, this._scene, "");
+
+        if (!result) {
+            return null;
+        }
+
+        result.onActivateObservable = this.onActivateObservable.clone();
+        result.onSizeChangedObservable = this.onSizeChangedObservable.clone();
+        result.onApplyObservable = this.onApplyObservable.clone();
+        result.onBeforeRenderObservable = this.onBeforeRenderObservable.clone();
+        result.onAfterRenderObservable = this.onAfterRenderObservable.clone();
+
+        result._prePassEffectConfiguration = this._prePassEffectConfiguration;
+
+        return result;
+    }
+
+    /**
      * Creates a material from parsed material data
      * @param parsedPostProcess defines parsed post process data
      * @param scene defines the hosting scene
@@ -775,14 +811,32 @@ export class PostProcess {
             return null;
         }
 
-        var camera = scene.getCameraByID(parsedPostProcess.cameraId);
-
-        if (!camera) {
-            return null;
-        }
-
+        var camera = scene ? scene.getCameraByID(parsedPostProcess.cameraId) : null;
         return postProcessType._Parse(parsedPostProcess, camera, scene, rootUrl);
     }
+
+    /** @hidden */
+    public static _Parse(parsedPostProcess: any, targetCamera: Camera, scene: Scene, rootUrl: string) : Nullable<PostProcess> {
+        return SerializationHelper.Parse(() => {
+            return new PostProcess(
+                parsedPostProcess.name,
+                parsedPostProcess.fragmentUrl, 
+                parsedPostProcess.parameters,
+                parsedPostProcess.samplers,
+                parsedPostProcess.options,
+                targetCamera,
+                parsedPostProcess.renderTargetSamplingMode,
+                parsedPostProcess._engine, 
+                parsedPostProcess.reusable,
+                parsedPostProcess.defines,
+                parsedPostProcess.textureType,
+                parsedPostProcess.vertexUrl,
+                parsedPostProcess.indexParameters,
+                false,
+                parsedPostProcess.textureFormat
+                );
+        }, parsedPostProcess, scene, rootUrl);
+    }
 }
 
 _TypeStore.RegisteredTypes["BABYLON.PostProcess"] = PostProcess;

+ 4 - 0
src/Rendering/prePassEffectConfiguration.ts

@@ -21,6 +21,10 @@ export interface PrePassEffectConfiguration {
      */
     enabled: boolean;
     /**
+     * Does the output of this prepass need to go through imageprocessing
+     */
+    needsImageProcessing?: boolean;
+    /**
      * Disposes the effect configuration
      */
     dispose?: () => void;

+ 41 - 18
src/Rendering/prePassRenderer.ts

@@ -335,7 +335,7 @@ export class PrePassRenderer {
      * @hidden
      */
     public _beforeDraw(camera?: Camera, faceIndex?: number, layer?: number) {
-        const previousEnabled = this._enabled && this._currentTarget.enabled;
+        // const previousEnabled = this._enabled && this._currentTarget.enabled;
 
         if (this._isDirty) {
             this._update();
@@ -343,7 +343,7 @@ export class PrePassRenderer {
 
         const texture = this._currentTarget.renderTargetTexture;
 
-        if (previousEnabled && (!this._enabled || !this._currentTarget.enabled)) {
+        if (!this._enabled || !this._currentTarget.enabled) {
             // Prepass disabled, we render only on 1 color attachment
             if (texture) {
                 // this._engine.restoreSingleAttachment();
@@ -386,7 +386,6 @@ export class PrePassRenderer {
 
         // Activates and renders the chain
         if (postProcessChain.length) {
-            // Do not mess with stencil
             this._scene.postProcessManager._prepareFrame(this._currentTarget.getInternalTexture()!, postProcessChain);
             this._scene.postProcessManager.directRender(postProcessChain, outputTexture, false, faceIndex);
         }
@@ -434,10 +433,6 @@ export class PrePassRenderer {
 
     private _setRenderTargetState(prePassRenderTarget: PrePassRenderTarget, enabled: boolean) {
         prePassRenderTarget.enabled = enabled;
-
-        if (prePassRenderTarget.imageProcessingPostProcess) {
-            prePassRenderTarget.imageProcessingPostProcess.imageProcessingConfiguration.applyByPostProcess = enabled;
-        }  
     }
 
     /**
@@ -533,9 +528,10 @@ export class PrePassRenderer {
         this._postProcessesSourceForThisPass = this._getPostProcessesSource(prePassRenderTarget, camera);
         this._postProcessesSourceForThisPass = (this._postProcessesSourceForThisPass.filter((pp) => { return pp != null; }));
 
-        this._needsCompositionForThisPass = !this._hasImageProcessing(this._postProcessesSourceForThisPass) &&
+        const cameraHasImageProcessing = this._hasImageProcessing(this._postProcessesSourceForThisPass);
+        this._needsCompositionForThisPass = !cameraHasImageProcessing &&
             !this.disableGammaTransform &&
-            prePassRenderTarget._beforeCompositionPostProcesses.length > 0 && // TODO : this test should be cleaner and precisely target SSS
+            this._needsImageProcessing() &&
             !secondaryCamera;
 
         const firstCameraPP = this._getFirstPostProcess(this._postProcessesSourceForThisPass);
@@ -543,28 +539,55 @@ export class PrePassRenderer {
         let firstPP = null;
 
         // Create composition effect if needed
-        if (this._needsCompositionForThisPass && !prePassRenderTarget.imageProcessingPostProcess) {
-            prePassRenderTarget._createCompositionEffect();
+        if (this._needsCompositionForThisPass) {
+            if (!prePassRenderTarget.imageProcessingPostProcess) {
+                prePassRenderTarget._createCompositionEffect();
+            }
+            prePassRenderTarget.imageProcessingPostProcess.imageProcessingConfiguration.applyByPostProcess = true;
+        } else if (this._scene.imageProcessingConfiguration && !cameraHasImageProcessing) {
+            // in case image processing was applied before and no longer needed for this pass
+            this._scene.imageProcessingConfiguration.applyByPostProcess = false;
         }
 
         // Setting the prePassRenderTarget as input texture of the first PP
         if (firstPrePassPP) {
-            firstPrePassPP.inputTexture = prePassRenderTarget.getInternalTexture()!;
-            prePassRenderTarget.imageProcessingPostProcess.restoreDefaultInputTexture();
             firstPP = firstPrePassPP;
         } else if (this._needsCompositionForThisPass) {
-            prePassRenderTarget.imageProcessingPostProcess.inputTexture = prePassRenderTarget.getInternalTexture()!;
             firstPP = prePassRenderTarget.imageProcessingPostProcess;
         } else if (firstCameraPP) {
-            firstCameraPP.inputTexture = prePassRenderTarget.getInternalTexture()!;
             firstPP = firstCameraPP;
         }
 
-        if (firstPP) {
-            firstPP.autoClear = false;
+        this._bindFrameBuffer(prePassRenderTarget);
+        this._linkInternalTexture(prePassRenderTarget, firstPP);
+    }
+
+    private _linkInternalTexture(prePassRenderTarget: PrePassRenderTarget, postProcess: Nullable<PostProcess>) {
+        if (prePassRenderTarget._internalTextureDirty || prePassRenderTarget._outputPostProcess !== postProcess) {
+            this._updateGeometryBufferLayout();
+            if (postProcess) {
+                postProcess.autoClear = false;
+                postProcess.inputTexture = prePassRenderTarget.getInternalTexture()!;
+            }
+
+            // Restore previous texture that was forced to the prepass texture
+            if (prePassRenderTarget._outputPostProcess && prePassRenderTarget._outputPostProcess !== postProcess) {
+                prePassRenderTarget._outputPostProcess.restoreDefaultInputTexture();
+            }
+
+            prePassRenderTarget._outputPostProcess = postProcess;
+            prePassRenderTarget._internalTextureDirty = false;
+        }
+    }
+
+    private _needsImageProcessing(): boolean {
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].enabled && this._effectConfigurations[i].needsImageProcessing) {
+                return true;
+            }
         }
 
-        this._bindFrameBuffer(prePassRenderTarget);
+        return false;
     }
 
     private _hasImageProcessing(postProcesses: Nullable<PostProcess>[]): boolean {

+ 5 - 0
src/Rendering/subSurfaceConfiguration.ts

@@ -53,6 +53,11 @@ export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
     public enabled = false;
 
     /**
+     * Does the output of this prepass need to go through imageprocessing
+     */
+    public needsImageProcessing = true;
+
+    /**
      * Name of the configuration
      */
     public name = SceneComponentConstants.NAME_SUBSURFACE;