Skip to content

Instantly share code, notes, and snippets.

@sinbad
Last active November 30, 2024 08:27
Show Gist options
  • Save sinbad/4a9ded6b00cf6063c36a4837b15df969 to your computer and use it in GitHub Desktop.
Save sinbad/4a9ded6b00cf6063c36a4837b15df969 to your computer and use it in GitHub Desktop.
Unity simple & fast light flicker script
using UnityEngine;
using System.Collections.Generic;
// Written by Steve Streeting 2017
// License: CC0 Public Domain http://creativecommons.org/publicdomain/zero/1.0/
/// <summary>
/// Component which will flicker a linked light while active by changing its
/// intensity between the min and max values given. The flickering can be
/// sharp or smoothed depending on the value of the smoothing parameter.
///
/// Just activate / deactivate this component as usual to pause / resume flicker
/// </summary>
public class LightFlickerEffect : MonoBehaviour {
[Tooltip("External light to flicker; you can leave this null if you attach script to a light")]
public new Light light;
[Tooltip("Minimum random light intensity")]
public float minIntensity = 0f;
[Tooltip("Maximum random light intensity")]
public float maxIntensity = 1f;
[Tooltip("How much to smooth out the randomness; lower values = sparks, higher = lantern")]
[Range(1, 50)]
public int smoothing = 5;
// Continuous average calculation via FIFO queue
// Saves us iterating every time we update, we just change by the delta
Queue<float> smoothQueue;
float lastSum = 0;
/// <summary>
/// Reset the randomness and start again. You usually don't need to call
/// this, deactivating/reactivating is usually fine but if you want a strict
/// restart you can do.
/// </summary>
public void Reset() {
smoothQueue.Clear();
lastSum = 0;
}
void Start() {
smoothQueue = new Queue<float>(smoothing);
// External or internal light?
if (light == null) {
light = GetComponent<Light>();
}
}
void Update() {
if (light == null)
return;
// pop off an item if too big
while (smoothQueue.Count >= smoothing) {
lastSum -= smoothQueue.Dequeue();
}
// Generate random new item, calculate new average
float newVal = Random.Range(minIntensity, maxIntensity);
smoothQueue.Enqueue(newVal);
lastSum += newVal;
// Calculate new smoothed average
light.intensity = lastSum / (float)smoothQueue.Count;
}
}
@RockyGitHub
Copy link

It's not that bad. It's straightforward and gives an idea on a dissipating light. It does cause some garbage. Time.deltaTime is not a big deal in his use because he is yield return null, which is equal to waiting for the next Update() call.
There's no reason to hate on it so much??

@Kiranix
Copy link

Kiranix commented Sep 30, 2022

Hey @stadoblech, thanks a lot for your feedback, I'll take all that into account for future scripting.

About the magic numbers, it was a short quick script, so it was just making it simple to read first sight, I usually prefer that.

About the lighting intensity, I adjusted it for my scene to look as I wanted, that's also why the Magic numbers, just change them according to your scene/pipeline, expose in editor, etc.

And regarding the delta time in coroutine, I would like you to further explain why is that a really bad idea, cause I've used that a lot and I'm really interested on knowing why is that bad. How would you increment the timer "t" inside the while of a coroutine?

Thanks!

@LWART-STUDIO
Copy link

LWART-STUDIO commented Jun 29, 2023

I diсided do like this.

 public class FlickeringLight : MonoBehaviour
    {
        [Header("References")]
        [Tooltip("Light Source")]
        [SerializeField] private Light _light;
        [Tooltip("Emission renderer")]
        [SerializeField] private Renderer _renderer;
        [Tooltip("Material index if mesh have more then 1 material")]
        [SerializeField] private int _materialIndex = 0;
        [Space(3f)]
        [Header("Options")]
        [Tooltip("How much to smooth out the randomness; lower values = sparks, higher = lantern")]
        [Range(1, 50)]
        [SerializeField] private int _smoothing = 5;
        [Range(0, 50)]
        [Tooltip("Delay between iterations")]
        [SerializeField] private int _delay = 5;
        [Tooltip("Duration of iterations")]
        [SerializeField] private float _duration = 5;
        
        
        private float _maxIntensity;
        private float _minIntensity = 0;
        private Queue<float> _smoothQueue;
        private float _lastSum = 0;
        private float _colorIntensity;
        private Color _color;
        private float _factor;
        private Coroutine _flickCoroutine;
        private WaitForSeconds _seconds;
        public void Reset()
        {
            StopCoroutine(_flickCoroutine);
            _smoothQueue.Clear();
            _lastSum = 0;
        }
        private void Start()
        {
            _seconds = new WaitForSeconds(_delay);
            _color = _renderer.materials[_materialIndex].GetColor("_EmissionColor");
            _colorIntensity = (_color.r + _color.g + _color.b) / 3f;
            _maxIntensity = _light.intensity;
            _smoothQueue = new Queue<float>(_smoothing);
            _flickCoroutine = StartCoroutine(Flick());
        }

        private void DoFlick()
        {
            if (_light == null)
                return;

            // pop off an item if too big
            while (_smoothQueue.Count >= _smoothing)
            {
                _lastSum -= _smoothQueue.Dequeue();
            }

            // Generate random new item, calculate new average
            float newVal = Random.Range(_minIntensity, _maxIntensity);
            _smoothQueue.Enqueue(newVal);
            _lastSum += newVal;

            // Calculate new smoothed average
            _light.intensity = _lastSum / (float)_smoothQueue.Count;
            _factor = _light.intensity / _colorIntensity;
            _renderer.sharedMaterials[_materialIndex].SetColor("_EmissionColor",new Color(_color.r*_factor,_color.g*_factor,_color.b*_factor));
        }

        private IEnumerator Flick()
        {
            float t = 0.0f;
            yield return _seconds;
            while (t<_duration)
            {
                DoFlick();
                t += Time.deltaTime;
                yield return null;
            }
            _flickCoroutine  = StartCoroutine(Flick());
        }
Movie.003-1.mp4

@lucasmhdev
Copy link

Forked for 2D URP :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment