Files

79 lines
2.8 KiB
C#

using UnityEngine;
/// <summary>
/// Old film projector feel for the credits projected on the theatre screen: the projector light,
/// the projected image and the light rays share the same subtle brightness flicker, with rare
/// short dips like a skipping film.
/// </summary>
public class CreditsProjector : MonoBehaviour
{
[SerializeField] private Light _light;
[SerializeField] private CanvasGroup _image;
[SerializeField] private Renderer[] _rays;
[Tooltip("Continuous brightness variation (0 = steady)")]
[SerializeField, Range(0f, 1f)] private float _flickerAmount = .08f;
[SerializeField, Min(0f)] private float _flickerSpeed = 7f;
[Tooltip("Average number of short brightness dips per second")]
[SerializeField, Min(0f)] private float _dipsPerSecond = .3f;
[SerializeField, Range(0f, 1f)] private float _dipAmount = .25f;
[SerializeField, Min(0f)] private float _dipDuration = .06f;
[Tooltip("How much of the flicker reaches the projected image (the light and rays get all of it)")]
[SerializeField, Range(0f, 1f)] private float _imageFlicker = .5f;
private static readonly int ColorId = Shader.PropertyToID("_Color");
private float _baseIntensity;
private float _baseAlpha;
private Color[] _baseRayColors;
private MaterialPropertyBlock _block;
private float _dipTimer;
private float _seed;
private void Awake()
{
_seed = Random.Range(0f, 100f);
_block = new MaterialPropertyBlock();
if (_light) _baseIntensity = _light.intensity;
if (_image) _baseAlpha = _image.alpha;
_baseRayColors = new Color[_rays.Length];
for (int i = 0; i < _rays.Length; i++)
_baseRayColors[i] = _rays[i] && _rays[i].sharedMaterial ? _rays[i].sharedMaterial.GetColor(ColorId) : Color.white;
}
private void Update()
{
float noise = Mathf.PerlinNoise(Time.time * _flickerSpeed, _seed);
float brightness = 1f - _flickerAmount * noise;
if (_dipTimer > 0f)
_dipTimer -= Time.deltaTime;
else if (Random.value < _dipsPerSecond * Time.deltaTime)
_dipTimer = _dipDuration;
if (_dipTimer > 0f)
brightness *= 1f - _dipAmount;
if (_light)
_light.intensity = _baseIntensity * brightness;
if (_image)
_image.alpha = _baseAlpha * Mathf.Lerp(1f, brightness, _imageFlicker);
for (int i = 0; i < _rays.Length; i++)
{
if (!_rays[i])
continue;
_rays[i].GetPropertyBlock(_block);
Color color = _baseRayColors[i];
_block.SetColor(ColorId, new Color(color.r * brightness, color.g * brightness, color.b * brightness, color.a));
_rays[i].SetPropertyBlock(_block);
}
}
}