Search Unity

Question How do i turn lights on/off?

Discussion in 'Global Illumination' started by Akura, Mar 21, 2023.

  1. Akura

    Akura

    Joined:
    Jun 28, 2015
    Posts:
    23
    I have a scene with a room which only uses baked lights.
    Since i develope for the Oculus Quest 2 platform, which is not very powerfull, i don't want to use realtime lighting.

    But i wan't that the player can turn on/off the lights off the room.

    How can i achieve this with baked lights?
     
  2. PenProd

    PenProd

    Joined:
    Dec 17, 2022
    Posts:
    171
    Funny, I was just about to post the exact same question.

    I have thought of a few ways to do it, one of them requires changing the materials of all objects in the room. To easily enumerate through all objects, you would need to put everything in the room (including walls, ceiling and floor) into an empty GameObject. Then in script, go through all objects, enumerate through all materials used, then set the Base Map's color to black (or if you don't want total darkness, some shade of grey) when you switch off the light. Store the original colors so you can easily restore them when you turn the light back on. Make sure you are working with MaterialPropertyBlocks otherwise you'll be changing all other objects in your scene using the same material as well.

    Another way is to simply create a clone of the room and bake it without any lights. If you turn of the light, teleport to the cloned room, to the exact same relative position. This approach would only work in closed rooms of course and not with rooms that have an (open) door to another area.

    Anyway, the reason I was going to ask the same question is because above methods seem cumbersome to implement, and I was wondering if there might be an easier way to do it.
     
    Akura likes this.
  3. Akura

    Akura

    Joined:
    Jun 28, 2015
    Posts:
    23
    Im not sure but i think the asset"
    Magic Lightmap Switcher " from the unity asset store could solve our problem. What do you think?
     
  4. PenProd

    PenProd

    Joined:
    Dec 17, 2022
    Posts:
    171
    It might. It switches between lightmaps but that's scene-wide. So if you have more than one room that can have the lights on or off, you would need to create a lightmap for each possible combination of rooms with lights on or off. Or so I think since I haven't tested it.

    Also, it's not compatible with URP.
     
  5. Pema-Malling

    Pema-Malling

    Unity Technologies

    Joined:
    Jul 3, 2020
    Posts:
    320
    There's a few ways you might achieve this, but I'm afraid I can't point to any plug-and-play solution.

    You could use the API for accessing lightmap data directly (https://docs.unity3d.com/ScriptReference/LightmapSettings-lightmaps.html) and swap out the lightmaps with some other texture, like a second set of darker lightmaps, or a black texture. As with Magic Lightmap Switcher, that affects the whole scene, though.

    You could also set properties on individual renderers in order to temporarily disable lightmapping (https://docs.unity3d.com/ScriptReference/Renderer-lightmapIndex.html). For example, setting lightmap index to -1 will cause the object to not appear lightmapped. Depending on the shader used, that may or may not look acceptable.

    You can also set properties on individual materials of individual renderers to disable lighting for them. This would likely involve either creating your own shaders for the purpose, or finding some shaders that support it - I don't believe any of the shaders we ship have that functionality.
     
  6. PenProd

    PenProd

    Joined:
    Dec 17, 2022
    Posts:
    171
    For my game, I needed to do the same so I created a script for it. And it works too. :)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3.  
    4. public class LightTools : MonoBehaviour {
    5.  
    6.   Hashtable oldBaseColors = new Hashtable();
    7.  
    8.   public void SetObjectColors( GameObject obj, Color newColor ) {
    9.     foreach( Transform transformItem in obj.transform ) {
    10.       SetColor( transformItem.gameObject, newColor );
    11.       SetObjectColors( transformItem.gameObject, newColor );
    12.     }
    13.   }
    14.  
    15.   public void RestoreObjectColors( GameObject obj ) {
    16.     foreach( Transform transformItem in obj.transform ) {
    17.       int id = transformItem.gameObject.GetInstanceID();
    18.       if( oldBaseColors.ContainsKey( id ) ) SetColor( transformItem.gameObject, (Color) oldBaseColors[ id ] );
    19.       RestoreObjectColors( transformItem.gameObject );
    20.     }
    21.   }
    22.  
    23.   void SetColor( GameObject obj, Color newColor ) {
    24.     MaterialPropertyBlock mpb = new MaterialPropertyBlock();
    25.     MeshRenderer mr = obj.GetComponent<MeshRenderer>();
    26.     if( mr ) {
    27.       if( mr.material.HasProperty("_BaseColor") ) {
    28.         mr.GetPropertyBlock( mpb );
    29.         oldBaseColors[ obj.GetInstanceID() ] = mr.material.GetColor("_BaseColor");
    30.         mpb.SetColor( "_BaseColor", newColor );
    31.         mr.SetPropertyBlock( mpb );
    32.       }
    33.     }
    34.   }
    35.  
    36. }
    37.  
    To "turn off the light" in your room, make sure that everything in your room share a parent object, then call SetObjectColors with the parent and a color as parameters. For instance, to make your room completely dark

    Code (CSharp):
    1. SetObjectColors( Room, new Color( 0.0f, 0.0f, 0.0f, 1.0f ) );
    Or perhaps you still want a little bit of light:

    Code (CSharp):
    1. SetObjectColors( Room, new Color( 0.2f, 0.2f, 0.2f, 1.0f ) );
    Then, to turn the light back on, call RestoreObjectColors:

    Code (CSharp):
    1. RestoreObjectColors( Room );
    The version I'm using myself also checks for Emissive materials and turns that off too (so lamps actually go black too).