6
\$\begingroup\$

I was wondering if it was possible to create a light source in Unity, one that "sucks" light from the environment.

Negative value does not seem to work in Unity, as pointed out by many.

It is quite surprising that there is nothing that I could find that has information on this topic. All year old posts that mentioned this contained only dead links.

\$\endgroup\$
4
\$\begingroup\$

It's possible to get this effect if you programmatically set the color value of the light with negative values.

For instance, light.color = new Color(-1f,-1f,-1f); //C#

The values are clamped if you try to set them in the editor, but through code it works just fine. You can also use this to go above the 1.0 value limit if Unity's cap on light brightness is giving you trouble.

\$\endgroup\$
  • 3
    \$\begingroup\$ This sounds a lot like some kind of bug. Don't expect this to always stay that way. \$\endgroup\$ – Mario Apr 5 '16 at 5:17
  • \$\begingroup\$ It will probably stay. It only works in Deferred, however. \$\endgroup\$ – Петър Петров Oct 23 '16 at 15:11
1
\$\begingroup\$

In Deferred Lighting mode only, you can hack the light's color to be negative. Since the built-in color selector is clamped to normalized colors, you cannot use it. You can set negative colors from code, like, l.color = new Color(-0.4f, -0.4f, -0.4f, 1); or just use the following script and attach it to a light, then hack as you like.

using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(Light))]
public class HackedLight : MonoBehaviour {

    public Vector4 hackColor;
    public float multiplier = 1;

    void Update ()
    {
        var light = GetComponent<Light>();
        light.color = new Color(hackColor.x, hackColor.y, hackColor.z, hackColor.w) * multiplier;
    }
}

\$\endgroup\$
  • \$\begingroup\$ I am unable to reproduce this in Unity 5.3.5. Do you have global illumination enabled? Can you reproduce this with directional lights present in the scene? \$\endgroup\$ – eclmist Oct 24 '16 at 5:03
  • \$\begingroup\$ Must be in deferred mode to work. Be sure to check the rendering path on your camera \$\endgroup\$ – Петър Петров Oct 31 '16 at 1:30
0
\$\begingroup\$

There is an asset called Foggy Lights which "appears" to be able to do this. I haven't tested it myself but it uses custom, alpha blended lights to create dark volumes. Check it out here, there's a screenshot towards the bottom of the page: http://forum.unity3d.com/threads/foggy-lights.239062/page-2

\$\endgroup\$
0
\$\begingroup\$

I know there are other answers, but I wanted to contribute to the idea pool here with another option for future readers. Others have already stated you can simply modify the Color property of the Light object to achieve this; however, a smooth and versatile option would be to implement a DarkZone that has a falloff.


Basic Application

To apply this idea in it's basic form, you could just loop over every light in the scene, and change the Intensity of each light that is close enough to the DarkZone:

// Pseudo code.
Dictionary<Light, float> originalIntensities = new Dictionary<Light, float>();
DarkZone darkness = new DarkZone();
foreach (Light l in lights) {
    if (!originals.ContainsKey(l))
        originals.Add(l, l.Intensity);

    float length = (darkness.Position - l.Position).Length();
    if (length < darkness.Radius)
        l.Intensity = (originals[l] - darkness.Intensity) * distance;
}

Where distance is some float value between 0 and 1.


Explanation

The basic example above will have the following effects:

  • Closer lights will be completely turned off.
  • Distant lights will be minimally impacted.

The example can be (and needs to be) expanded to gradually kill light in the surrounding area. This is a nice and smooth technique for accomplishing the effect, and is more appealing than the option of strictly killing the lights within the effective radius. Achieving that is more simplistic, but more grotesque compared to the example given above.

// Pseudo code.
foreach (Light l in lights) {
    if (!originals.ContainsKey(l))
        originals.Add(l, l.Intensity);

    float length = (darkness.Position - l.Position).Length();
    l.Intensity = length < darkness.Radius ? 0 : originals[l];
}

Important Note

Storing the original intensities is a very important part of this example. Reason being, if you have a Light with an intensity of 0.5 and you move the DarkZone away from it, without the original intensity stored off, how do you know what to set it back to? Setting it to 1 may just have bad effects if that Light in particular is set to 0.5 for a reason.

\$\endgroup\$
  • \$\begingroup\$ You'll want to cache the killed light's original intensity so you don't double-diminish it on a subsequent frame, or can restore it to its original brightness when the killer is turned off / moves away \$\endgroup\$ – DMGregory Nov 13 '18 at 18:19
  • \$\begingroup\$ @DMGregory Thanks for reminding me to mention that! \$\endgroup\$ – user121635 Nov 13 '18 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.