Is there a way to set up two cameras such that they render the same scene just with different lighting?
Like let’s say we have a set of A-lights and a set of B-lights. I want the A-camera to render the scene only using A-lights, while I want the B-camera to render that same scene only using B-lights. I don’t want the B-lights seen by the A-camera or vice versa.
Is this possible? How would I do it? Renderer feature? Lighting layers, culling masks etc?
You might be able to use this Unity - Scripting API: Rendering.RenderPipelineManager.beginCameraRendering to disable/enable the desired lights via script, just before each camera renders.
I’ll test out a OnBegin/EndCameraRendering method, thank you for the suggestion. I previously had tried setting up a RendererFeature that would do this sort of thing but it didn’t seem to affect the rendered lighting.
Is there a way to do this with command buffers? Could you overwrite any global shader variables in order to personally set up the lighting and then call the necessary DrawRenderers step? I can’t find much documentation on the way unity sends lighting data to shaders and how to override them.
I was able to get your suggestion working
In the above image I have a standard white light being used for the default lighting. I have an absurdly bright green light being used for the alternative lighting. This alternatively lit scene is being picked up by the camera (in view right) and put onto a render texture which is being displayed on a simple plane (view left).
Default render only uses the default white light.
Alternative render only uses the alternative super saturated green light.
I have some other features like a color swatch (visible in both the view and camera render texture) which is half purely emissive and half purely diffuse so that it shows the true color vs lighting color and it is indeed working as expected in both.
Here is the simple code I have set up to do this :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
[RequireComponent(typeof(Camera))]
public class LightFilter : MonoBehaviour
{
public LayerMask lightMask;
private Camera thisCamera;
private Dictionary<Light, bool> lightSettings = new Dictionary<Light, bool>();
private void Start()
{
thisCamera = GetComponent<Camera>();
RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
}
private void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (camera != thisCamera)
return;
lightSettings = new Dictionary<Light, bool>();
foreach (Light light in FindObjectsOfType<Light>())
{
lightSettings.Add(light, light.enabled);
light.enabled = (lightMask.value & (1 << light.gameObject.layer)) != 0 ? true : false;
}
}
private void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (camera != thisCamera)
return;
foreach (Light light in FindObjectsOfType<Light>())
{
if (lightSettings.ContainsKey(light))
light.enabled = lightSettings[light];
}
}
}
Put the above monobehaviour on a camera, select the layers which contain the lights you want to exclusively use in the render, and it should work. I did have a little issues with lighting and cameras, but messing around with the priority number of each camera seemed to fix those issues.
BUT
I would love an answer to my question about doing this via render buffers. Personally modifying lighting in that sort of environment sounds like something I will definitely need to do at some point. And switching lights on and off just isn’t exactly satisfying it for me, it seems to work great but seems hacky.
feature request
It would be nice if cameras culled lights based off layers, or if there was a cull-lighting option on each camera to only render lights in certain layers. I feel like not only would this be a feature that let’s the developer have more control but is one of those rare instances that it could be more performant as each camera renders <= #total scene lights?
I don’t think our culling logic is customizable in that way. You could probably implement it in a fork of URP (?) by modifying CullingResults.visibleLights after the call to ScriptableRenderContext.Cull, but I’m not really sure tbh.
I’ll forward the question, not really an expert on culling. As for feature requests, you can submit on productboard: https://portal.productboard.com/unity/1-unity-platform-rendering-visual-effects/c/1387-didn-t-find-what-you-were-looking-for-
Hi, you should sort of be able to achieve this behaviour using the culling mask property on the camera and lights.
If the culling mask of a light and a camera don’t match, the light will be culled from the point of view of that camera.
I did briefly try this out, and found one caveat with a use-case like yours - with culling masks, if the culling mask of a light and the layer of a GameObject do not match, the shadow for that GameObject is not rendered for that light.
So if you were hoping to use shadows on the lights in question, this unfortunately wouldn’t work.
Thats good to know about the culling and layers, it does sound super useful. However sadly I definitely need shadows.
I’m thinking of potentially doing this via renderer features. I should be able to set manually the global shader variables for lighting in the command buffers correct? Do you have any insight on what global variables id have to target to manually set the lighting? It may be messy but it’s the only way I think I could get this affect going. Or perhaps in the command buffer stuff with DrawRenderers could I somehow mess with the cull/drawing settings to filter out what lights I do and dont want involved in the render?
Oh I didnt see this reply! Im on my phone at work but this seems like it might be able to work. I’ll be sure to attempt to test it when I get home.
I have seen that in a ScriptableRenderPass the cullingresults are exposed! So perhaps as long as they aren’t readonly I might be able to manually filter the visibleLights and then pass the modified culling to the cmd.DrawRenderers. Since the only thing I want to change is lighting all the rest of everything should be the same correct?
Where is the best place to execute code like this? Is a RendererFeature or RenderPass really the best? Because in my mind the cullresults are being modified before being handed off to any specific pass so is it really best to inject into a particular render event?
I’ll try and test this out when I get home
I sat down to test the idea with the visibleLights to see if that could work, sadly visibleLights is readonly, there is no way to set anything within it and I think this method is a dead end.
Hmm, I see. Disregard, then. I don’t think I have any more advice than what has already been proposed on the thread. I haven’t implemented what you are attempting before, and I’m not an expert on SRP culling. If you aren’t happy with your workaround, the feature request form is your best bet.