Simpler workflow for independent HDRI LightMix and background control?

Hello,

I’m looking for some help with an issue that’s been bothering me for a while. Maybe I’m missing something, or perhaps there’s a plugin or a simpler workflow that I’m not aware of.

When using some HDRI, I often want to fine-tune the lighting separately from the visible background. For example, in LightMix I usually increase the exposure of the HDRI light while reducing the exposure of the visible background.

To achieve this, I always end up using two Corona Ray Switchers…one for the Visibility slot and another for everything else.

Is there an easier way to do this, without having to set up this workflow every time?

Would environment overrides work in this case? You set the HDRI as your scene environment - this takes care of lighting. Then you use a different version of the same HDRI as your direct/reflect/refract enviro overrides.

Hi Maru,

Thank you for the quick reply and the suggestion.

I used to work that way, but it only really works if I’m using a single HDRI.

Most of the time I like to compare different lighting setups (for example, day and night variations). In those cases, I still have to set up two HDRI maps for each setup using a Corona Ray Switcher, one for the lighting (GI, etc.) and another for the direct/reflection/refraction visibility.

Maybe this is something that would be better suited as a feature request, such as allowing the environment lighting and visible background to be controlled independently in the LightMix LightSelect elements.

I was just hoping there might already be a plugin or script that automates this workflow.

Thanks again for the help!
Best
Luis

“I was just hoping there might already be a plugin or script that automates this workflow.”

You can ask AI to make a script to set this up;

maxscript(
    -- 1. Verify that the active renderer is Chaos Corona
    if (matchPattern ((renderers.current as string)) pattern:"*Corona*") then
    (
        -- Get the environment map assigned globally in 3ds Max (Press 8)
        local mainHDRI = environmentMap
        
        if mainHDRI != undefined then
        (
            -- 2. Decouple Environments natively using valid Corona properties
            -- Activate the Corona native environment source mode
            renderers.current.bg_source = 1
            
            -- Assign original HDRI to Global GI illumination & Reflections
            renderers.current.bg_texmap_envGIMap = mainHDRI
            renderers.current.bg_texmap_envGIMapOn = true
            
            -- Set up a Corona RaySwitch to parse out direct camera visibility
            local raySwitchMap = CoronaRaySwitch()
            raySwitchMap.directTex = mainHDRI -- Maps HDRI solely to direct rays
            
            -- Assign RaySwitch to the Direct Visibility slot
            renderers.current.bg_texmap = raySwitchMap
            renderers.current.bg_texmapOn = true
            
            -- 3. Access Render Element Manager
            local reMgr = maxOps.GetRenderElementMgr #Production
            
            -- 4. Create the main LightMix node if missing
            local hasLightMix = false
            for i = 0 to (reMgr.NumRenderElements() - 1) do
            (
                local elem = reMgr.GetRenderElement i
                if (classOf elem == CShading_LightMix) do hasLightMix = true
            )
            
            if not hasLightMix do
            (
                reMgr.AddRenderElement (CShading_LightMix elementName:"LightMix")
            )
            
            -- 5. SAFEGUARD LOOP: Remove ONLY legacy environment elements.
            -- Custom setups (e.g. "LightSelect_Ceiling", "LightSelect_Sun") remain intact.
            for i = (reMgr.NumRenderElements() - 1) downTo 0 do
            (
                local elem = reMgr.GetRenderElement i
                if (classOf elem == CShading_LightSelect) do
                (
                    -- Filter string matches targeting only environment channels
                    local isEnvLighting = matchPattern elem.elementName pattern:"LightSelect_Env_Lighting"
                    local isBgLighting = matchPattern elem.elementName pattern:"LightSelect_Background"
                    local isGenericEnv = matchPattern elem.elementName pattern:"Environment"
                    
                    if (isEnvLighting or isBgLighting or isGenericEnv) do
                    (
                        reMgr.RemoveRenderElement elem
                    )
                )
            )
            
            -- 6. Create Element 1: Scene Illumination Channel
            local lightEnv = CShading_LightSelect elementName:"LightSelect_Env_Lighting"
            -- nodeSource 1 captures everything not manually assigned to another slider (the ambient environment)
            lightEnv.nodeSource = 1 
            reMgr.AddRenderElement lightEnv
            
            -- 7. Create Element 2: Direct Camera Plate Channel
            local bgEnv = CShading_LightSelect elementName:"LightSelect_Background"
            -- nodeSource 0 is the manual inclusion mode.
            -- The RaySwitch map flags direct camera rays as separate from the environment calculation loop,
            -- isolating them onto this clean slider completely independent of scene GI.
            bgEnv.nodeSource = 0 
            reMgr.AddRenderElement bgEnv
            
            -- Open Render Setup to refresh UI changes
            max render setup
            messageBox "LightMix Pipeline generated securely!\n\nYour custom light groups were safely skipped.\n'LightSelect_Env_Lighting' -> Controls Ambient GI/Reflections\n'LightSelect_Background' -> Controls visible HDRI pixels." title:"Pipeline Success"
        )
        else
        (
            messageBox "Please assign an HDRI map to the 3ds Max Environment Slot (Press 8) first." title:"Environment Empty"
        )
    )
    else
    (
        messageBox "Please change your current renderer to Chaos Corona before executing." title:"Renderer Mismatch"
    )
)

It probably won’t work first go, but maybe by the tenth go it’ll work. Just keep feeding the Maxscript errors back into the chat.

:slight_smile: