From 7608392439e18b0bc97f892bd253ce93bfefea08 Mon Sep 17 00:00:00 2001
From: Martin Valigursky <mvaligursky@snapchat.com>
Date: Fri, 2 Feb 2024 11:33:39 +0000
Subject: [PATCH 1/2] Small refactor to ForwardRenderer.renderForwardLayer to
 allow additional options

---
 .../lightmapper/render-pass-lightmapper.js    | 18 ++---
 src/scene/renderer/forward-renderer.js        | 75 ++++++++++++-------
 src/scene/renderer/render-pass-forward.js     |  2 +-
 3 files changed, 53 insertions(+), 42 deletions(-)

diff --git a/src/framework/lightmapper/render-pass-lightmapper.js b/src/framework/lightmapper/render-pass-lightmapper.js
index 02abe4755d2..c780959c4be 100644
--- a/src/framework/lightmapper/render-pass-lightmapper.js
+++ b/src/framework/lightmapper/render-pass-lightmapper.js
@@ -34,19 +34,11 @@ class RenderPassLightmapper extends RenderPass {
 
         const { renderer, camera, receivers, renderTarget, worldClusters, lightArray } = this;
 
-        // prepare clustered lighting
-        if (worldClusters) {
-            worldClusters.activate();
-        }
-
-        renderer.setCameraUniforms(camera, renderTarget);
-        if (device.supportsUniformBuffers) {
-            renderer.setupViewUniformBuffers(this.viewBindGroups, renderer.viewUniformFormat, renderer.viewBindGroupFormat, 1);
-        }
-
-        renderer._forwardTime = 0;
-        renderer._shadowMapTime = 0;
-        renderer.renderForward(camera, receivers, lightArray, SHADER_FORWARDHDR);
+        renderer.renderForwardLayer(camera, renderTarget, null, undefined, SHADER_FORWARDHDR, this.viewBindGroups, {
+            meshInstances: receivers,
+            splitLights: lightArray,
+            lightClusters: worldClusters
+        });
 
         DebugGraphics.popGpuMarker(device);
     }
diff --git a/src/scene/renderer/forward-renderer.js b/src/scene/renderer/forward-renderer.js
index c9e2eab0401..987d6f8339f 100644
--- a/src/scene/renderer/forward-renderer.js
+++ b/src/scene/renderer/forward-renderer.js
@@ -676,7 +676,7 @@ class ForwardRenderer extends Renderer {
      * Forward render mesh instances on a specified layer, using a camera and a render target.
      * Shaders used are based on the shaderPass provided, with optional clustered lighting support.
      *
-     * @param {import('../../framework/components/camera/component.js').CameraComponent} camera - The
+     * @param {import('../camera.js').Camera} camera - The
      * camera.
      * @param {import('../../platform/graphics/render-target.js').RenderTarget} renderTarget - The
      * render target.
@@ -693,77 +693,96 @@ class ForwardRenderer extends Renderer {
      * @param {boolean} [options.clearStencil] - True if the stencil buffer should be cleared.
      * @param {import('../lighting/world-clusters.js').WorldClusters} [options.lightClusters] - The
      * world clusters object to be used for clustered lighting.
+     * @param {import('../mesh-instance.js').MeshInstance[]} [options.meshInstances] - The mesh
+     * instances to be rendered. Use when layer is not provided.
+     * @param {object} [options.splitLights] - The split lights to be used for clustered lighting.
+     * @param {import('../lighting/world-clusters.js').WorldClusters} [options.lightClusters] - The
+     * clustered lighting object to be used when clustered lighting is specified.
      */
     renderForwardLayer(camera, renderTarget, layer, transparent, shaderPass, viewBindGroups, options = {}) {
 
         const { scene, device } = this;
         const clusteredLightingEnabled = scene.clusteredLightingEnabled;
 
-        this.setupViewport(camera.camera, renderTarget);
+        this.setupViewport(camera, renderTarget);
 
         // clearing
         const clearColor = options.clearColors ?? false;
         const clearDepth = options.clearDepth ?? false;
         const clearStencil = options.clearStencil ?? false;
         if (clearColor || clearDepth || clearStencil) {
-            this.clear(camera.camera, clearColor, clearDepth, clearStencil);
+            this.clear(camera, clearColor, clearDepth, clearStencil);
         }
 
-        // #if _PROFILER
-        const sortTime = now();
-        // #endif
+        let visible, splitLights;
+        if (layer) {
+            // #if _PROFILER
+            const sortTime = now();
+            // #endif
 
-        layer.sortVisible(camera.camera, transparent);
+            layer.sortVisible(camera, transparent);
 
-        // #if _PROFILER
-        this._sortTime += now() - sortTime;
-        // #endif
+            // #if _PROFILER
+            this._sortTime += now() - sortTime;
+            // #endif
+
+            const culledInstances = layer.getCulledInstances(camera);
+            visible = transparent ? culledInstances.transparent : culledInstances.opaque;
 
-        const culledInstances = layer.getCulledInstances(camera.camera);
-        const visible = transparent ? culledInstances.transparent : culledInstances.opaque;
+            // add debug mesh instances to visible list
+            scene.immediate.onPreRenderLayer(layer, visible, transparent);
+
+            // set up layer uniforms
+            if (layer.requiresLightCube) {
+                this.lightCube.update(scene.ambientLight, layer._lights);
+                this.constantLightCube.setValue(this.lightCube.colors);
+            }
 
-        // add debug mesh instances to visible list
-        scene.immediate.onPreRenderLayer(layer, visible, transparent);
+            splitLights = layer.splitLights;
 
-        // set up layer uniforms
-        if (layer.requiresLightCube) {
-            this.lightCube.update(scene.ambientLight, layer._lights);
-            this.constantLightCube.setValue(this.lightCube.colors);
+        } else {
+            visible = options.meshInstances;
+            splitLights = options.splitLights;
         }
 
+        Debug.assert(visible, 'Either layer or options.meshInstances must be provided');
+
         // upload clustered lights uniforms
         const { lightClusters } = options;
         if (clusteredLightingEnabled && lightClusters) {
             lightClusters.activate();
 
             // debug rendering of clusters
-            if (!this.clustersDebugRendered && scene.lighting.debugLayer === layer.id) {
-                this.clustersDebugRendered = true;
-                WorldClustersDebug.render(lightClusters, this.scene);
+            if (layer) {
+                if (!this.clustersDebugRendered && scene.lighting.debugLayer === layer.id) {
+                    this.clustersDebugRendered = true;
+                    WorldClustersDebug.render(lightClusters, this.scene);
+                }
             }
         }
 
         // Set the not very clever global variable which is only useful when there's just one camera
-        scene._activeCamera = camera.camera;
+        scene._activeCamera = camera;
 
-        const viewCount = this.setCameraUniforms(camera.camera, renderTarget);
+        const viewCount = this.setCameraUniforms(camera, renderTarget);
         if (device.supportsUniformBuffers) {
             this.setupViewUniformBuffers(viewBindGroups, this.viewUniformFormat, this.viewBindGroupFormat, viewCount);
         }
 
         // enable flip faces if either the camera has _flipFaces enabled or the render target has flipY enabled
-        const flipFaces = !!(camera.camera._flipFaces ^ renderTarget?.flipY);
+        const flipFaces = !!(camera._flipFaces ^ renderTarget?.flipY);
 
         const forwardDrawCalls = this._forwardDrawCalls;
-        this.renderForward(camera.camera,
+        this.renderForward(camera,
                            visible,
-                           layer.splitLights,
+                           splitLights,
                            shaderPass,
-                           layer.onDrawCall,
+                           layer?.onDrawCall,
                            layer,
                            flipFaces);
 
-        layer._forwardDrawCalls += this._forwardDrawCalls - forwardDrawCalls;
+        if (layer)
+            layer._forwardDrawCalls += this._forwardDrawCalls - forwardDrawCalls;
     }
 
     setSceneConstants() {
diff --git a/src/scene/renderer/render-pass-forward.js b/src/scene/renderer/render-pass-forward.js
index e966ee9719b..7fcbdc14743 100644
--- a/src/scene/renderer/render-pass-forward.js
+++ b/src/scene/renderer/render-pass-forward.js
@@ -268,7 +268,7 @@ class RenderPassForward extends RenderPass {
                 options.clearStencil = renderAction.clearStencil;
             }
 
-            renderer.renderForwardLayer(camera, renderAction.renderTarget, layer, transparent,
+            renderer.renderForwardLayer(camera.camera, renderAction.renderTarget, layer, transparent,
                                         shaderPass, renderAction.viewBindGroups, options);
 
             // Revert temp frame stuff

From 423895de76bf6fa2f6f5134d208c550a9b814b57 Mon Sep 17 00:00:00 2001
From: Martin Valigursky <mvaligursky@snapchat.com>
Date: Fri, 2 Feb 2024 11:37:07 +0000
Subject: [PATCH 2/2] jsdocs cleanup

---
 src/scene/renderer/forward-renderer.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/scene/renderer/forward-renderer.js b/src/scene/renderer/forward-renderer.js
index 987d6f8339f..6fe80591219 100644
--- a/src/scene/renderer/forward-renderer.js
+++ b/src/scene/renderer/forward-renderer.js
@@ -696,8 +696,6 @@ class ForwardRenderer extends Renderer {
      * @param {import('../mesh-instance.js').MeshInstance[]} [options.meshInstances] - The mesh
      * instances to be rendered. Use when layer is not provided.
      * @param {object} [options.splitLights] - The split lights to be used for clustered lighting.
-     * @param {import('../lighting/world-clusters.js').WorldClusters} [options.lightClusters] - The
-     * clustered lighting object to be used when clustered lighting is specified.
      */
     renderForwardLayer(camera, renderTarget, layer, transparent, shaderPass, viewBindGroups, options = {}) {