Forráskód Böngészése

Add the getCustomRenderList user function

Popov72 5 éve
szülő
commit
89786870b5

+ 1 - 0
dist/preview release/what's new.md

@@ -56,6 +56,7 @@
 - Added `CascadedShadowGenerator.autoCalcDepthBounds` to improve the shadow quality rendering ([Popov72](https://github.com/Popov72))
 - Improved cascade blending in CSM shadow technique ([Popov72](https://github.com/Popov72))
 - Speed optimization when cascade blending is not used in CSM shadow technique ([Popov72](https://github.com/Popov72))
+- Added `RenderTargetTexture.getCustomRenderList` to overload the render list at rendering time (and possibly for each layer (2DArray) / face (Cube)) ([Popov72](https://github.com/Popov72))
 
 ### Engine
 

+ 84 - 44
src/Materials/Textures/renderTargetTexture.ts

@@ -1,7 +1,7 @@
 import { Observer, Observable } from "../../Misc/observable";
 import { Tools } from "../../Misc/tools";
 import { SmartArray } from "../../Misc/smartArray";
-import { Nullable } from "../../types";
+import { Nullable, Immutable } from "../../types";
 import { Camera } from "../../Cameras/camera";
 import { Scene } from "../../scene";
 import { Matrix, Vector3 } from "../../Maths/math.vector";
@@ -63,6 +63,15 @@ export class RenderTargetTexture extends Texture {
         }
     }
 
+    /**
+     * Use this function to overload the renderList array at rendering time.
+     * Return null to render with the curent renderList, else return the list of meshes to use for rendering.
+     * For 2DArray RTT, layerOrFace is the index of the layer that is going to be rendered, else it is the faceIndex of
+     * the cube (if the RTT is a cube, else layerOrFace=0).
+     * The renderList passed to the function is the current render list (the one that will be used if the function returns null)
+    */
+    public getCustomRenderList: (layerOrFace: number, renderList: Nullable<Immutable<Array<AbstractMesh>>>) => Nullable<Array<AbstractMesh>>;
+
     private _hookArray(array: AbstractMesh[]): void {
         var oldPush = array.push;
         array.push = (...items: AbstractMesh[]) => {
@@ -602,6 +611,8 @@ export class RenderTargetTexture extends Texture {
         }
     }
 
+    private _defaultRenderListPrepared: boolean;
+
     /**
      * Renders all the objects from the render list into the texture.
      * @param useCameraPostProcess Define if camera post processes should be used during the rendering
@@ -677,11 +688,57 @@ export class RenderTargetTexture extends Texture {
             }
         }
 
-        // Prepare renderingManager
+        this._defaultRenderListPrepared = false;
+
+        if (this.is2DArray) {
+            for (let layer = 0; layer < this.getRenderLayers(); layer++) {
+                this.renderToTarget(0, useCameraPostProcess, dumpForDebug, layer, camera);
+                scene.incrementRenderId();
+                scene.resetCachedMaterial();
+            }
+        }
+        else if (this.isCube) {
+            for (var face = 0; face < 6; face++) {
+                this.renderToTarget(face, useCameraPostProcess, dumpForDebug, undefined, camera);
+                scene.incrementRenderId();
+                scene.resetCachedMaterial();
+            }
+        } else {
+            this.renderToTarget(0, useCameraPostProcess, dumpForDebug, undefined, camera);
+        }
+
+        this.onAfterUnbindObservable.notifyObservers(this);
+
+        if (scene.activeCamera) {
+            // Do not avoid setting uniforms when multiple scenes are active as another camera may have overwrite these
+            if (scene.getEngine().scenes.length > 1 || (this.activeCamera && this.activeCamera !== scene.activeCamera)) {
+                scene.setTransformMatrix(scene.activeCamera.getViewMatrix(), scene.activeCamera.getProjectionMatrix(true));
+            }
+            engine.setViewport(scene.activeCamera.viewport);
+        }
+
+        scene.resetCachedMaterial();
+    }
+
+    private _bestReflectionRenderTargetDimension(renderDimension: number, scale: number): number {
+        let minimum = 128;
+        let x = renderDimension * scale;
+        let curved = Engine.NearestPOT(x + (minimum * minimum / (minimum + x)));
+
+        // Ensure we don't exceed the render dimension (while staying POT)
+        return Math.min(Engine.FloorPOT(renderDimension), curved);
+    }
+
+    private _prepareRenderingManager(currentRenderList: Array<AbstractMesh>, camera: Nullable<Camera>, checkLayerMask: boolean): void {
+        var scene = this.getScene();
+
+        if (!scene) {
+            return;
+        }
+
         this._renderingManager.reset();
 
-        var currentRenderList = this.renderList ? this.renderList : scene.getActiveMeshes().data;
-        var currentRenderListLength = this.renderList ? this.renderList.length : scene.getActiveMeshes().length;
+        var currentRenderListLength = currentRenderList.length;
         var sceneRenderId = scene.getRenderId();
         for (var meshIndex = 0; meshIndex < currentRenderListLength; meshIndex++) {
             var mesh = currentRenderList[meshIndex];
@@ -695,7 +752,7 @@ export class RenderTargetTexture extends Texture {
                 mesh._preActivateForIntermediateRendering(sceneRenderId);
 
                 let isMasked;
-                if (!this.renderList && camera) {
+                if (checkLayerMask && camera) {
                     isMasked = ((mesh.layerMask & camera.layerMask) === 0);
                 } else {
                     isMasked = false;
@@ -731,44 +788,6 @@ export class RenderTargetTexture extends Texture {
                 this._renderingManager.dispatchParticles(particleSystem);
             }
         }
-
-        if (this.is2DArray) {
-            for (let layer = 0; layer < this.getRenderLayers(); layer++) {
-                this.renderToTarget(0, currentRenderList, useCameraPostProcess, dumpForDebug, layer);
-                scene.incrementRenderId();
-                scene.resetCachedMaterial();
-            }
-        }
-        else if (this.isCube) {
-            for (var face = 0; face < 6; face++) {
-                this.renderToTarget(face, currentRenderList, useCameraPostProcess, dumpForDebug);
-                scene.incrementRenderId();
-                scene.resetCachedMaterial();
-            }
-        } else {
-            this.renderToTarget(0, currentRenderList, useCameraPostProcess, dumpForDebug);
-        }
-
-        this.onAfterUnbindObservable.notifyObservers(this);
-
-        if (scene.activeCamera) {
-            // Do not avoid setting uniforms when multiple scenes are active as another camera may have overwrite these
-            if (scene.getEngine().scenes.length > 1 || (this.activeCamera && this.activeCamera !== scene.activeCamera)) {
-                scene.setTransformMatrix(scene.activeCamera.getViewMatrix(), scene.activeCamera.getProjectionMatrix(true));
-            }
-            engine.setViewport(scene.activeCamera.viewport);
-        }
-
-        scene.resetCachedMaterial();
-    }
-
-    private _bestReflectionRenderTargetDimension(renderDimension: number, scale: number): number {
-        let minimum = 128;
-        let x = renderDimension * scale;
-        let curved = Engine.NearestPOT(x + (minimum * minimum / (minimum + x)));
-
-        // Ensure we don't exceed the render dimension (while staying POT)
-        return Math.min(Engine.FloorPOT(renderDimension), curved);
     }
 
     /**
@@ -797,7 +816,7 @@ export class RenderTargetTexture extends Texture {
         });
     }
 
-    private renderToTarget(faceIndex: number, currentRenderList: AbstractMesh[], useCameraPostProcess: boolean, dumpForDebug: boolean, layer = 0): void {
+    private renderToTarget(faceIndex: number, useCameraPostProcess: boolean, dumpForDebug: boolean, layer = 0, camera: Nullable<Camera> = null): void {
         var scene = this.getScene();
 
         if (!scene) {
@@ -825,6 +844,27 @@ export class RenderTargetTexture extends Texture {
             this.onBeforeRenderObservable.notifyObservers(faceIndex);
         }
 
+        // Get the list of meshes to render
+        let currentRenderList: Nullable<Array<AbstractMesh>> = null;
+        let defaultRenderList = this.renderList ? this.renderList : scene.getActiveMeshes().data;
+
+        if (this.getCustomRenderList) {
+            currentRenderList = this.getCustomRenderList(this.is2DArray ? layer : faceIndex, defaultRenderList);
+        }
+
+        if (!currentRenderList) {
+            // No custom render list provided, we prepare the rendering for the default list, but check
+            // first if we did not already performed the preparation before so as to avoid re-doing it several times
+            if (!this._defaultRenderListPrepared) {
+                this._prepareRenderingManager(defaultRenderList, camera, !this.renderList);
+                this._defaultRenderListPrepared = true;
+            }
+            currentRenderList = defaultRenderList;
+        } else {
+            // Prepare the rendering for the custom render list provided
+            this._prepareRenderingManager(currentRenderList, camera, false);
+        }
+
         // Clear
         if (this.onClearObservable.hasObservers()) {
             this.onClearObservable.notifyObservers(engine);