using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(Camera))] [AddComponentMenu("Image Effects/Noise")] public class NoiseEffect : MonoBehaviour { /// Monochrome noise just adds grain. Non-monochrome noise /// more resembles VCR as it adds noise in YUV color space, /// thus introducing magenta/green colors. public bool monochrome = true; private bool rgbFallback = false; // Noise grain takes random intensity from Min to Max. public float grainIntensityMin = 0.1f; public float grainIntensityMax = 0.2f; /// The size of the noise grains (1 = one pixel). public float grainSize = 2.0f; // Scratches take random intensity from Min to Max. public float scratchIntensityMin = 0.05f; public float scratchIntensityMax = 0.25f; /// Scratches jump to another locations at this times per second. public float scratchFPS = 10.0f; /// While scratches are in the same location, they jitter a bit. public float scratchJitter = 0.01f; public Texture grainTexture; public Texture scratchTexture; public Shader shaderRGB; public Shader shaderYUV; private Material m_MaterialRGB; private Material m_MaterialYUV; private float scratchTimeLeft = 0.0f; private float scratchX, scratchY; protected void Start() { // Disable if we don't support image effects if (!SystemInfo.supportsImageEffects) { enabled = false; return; } if (shaderRGB == null || shaderYUV == null) { Debug.Log("Noise shaders are not set up! Disabling noise effect."); enabled = false; } else { if (!shaderRGB.isSupported) // disable effect if RGB shader is not supported enabled = false; else if (!shaderYUV.isSupported) // fallback to RGB if YUV is not supported rgbFallback = true; } } protected Material material { get { if (m_MaterialRGB == null) { m_MaterialRGB = new Material(shaderRGB); m_MaterialRGB.hideFlags = HideFlags.HideAndDontSave; } if (m_MaterialYUV == null && !rgbFallback) { m_MaterialYUV = new Material(shaderYUV); m_MaterialYUV.hideFlags = HideFlags.HideAndDontSave; } return (!rgbFallback && !monochrome) ? m_MaterialYUV : m_MaterialRGB; } } protected void OnDisable() { if (m_MaterialRGB) DestroyImmediate(m_MaterialRGB); if (m_MaterialYUV) DestroyImmediate(m_MaterialYUV); } private void SanitizeParameters() { grainIntensityMin = Mathf.Clamp(grainIntensityMin, 0.0f, 5.0f); grainIntensityMax = Mathf.Clamp(grainIntensityMax, 0.0f, 5.0f); scratchIntensityMin = Mathf.Clamp(scratchIntensityMin, 0.0f, 5.0f); scratchIntensityMax = Mathf.Clamp(scratchIntensityMax, 0.0f, 5.0f); scratchFPS = Mathf.Clamp(scratchFPS, 1, 30); scratchJitter = Mathf.Clamp(scratchJitter, 0.0f, 1.0f); grainSize = Mathf.Clamp(grainSize, 0.1f, 50.0f); } // Called by the camera to apply the image effect void OnRenderImage(RenderTexture source, RenderTexture destination) { SanitizeParameters(); if (scratchTimeLeft <= 0.0f) { scratchTimeLeft = Random.value * 2 / scratchFPS; // we have sanitized it earlier, won't be zero scratchX = Random.value; scratchY = Random.value; } scratchTimeLeft -= Time.deltaTime; Material mat = material; mat.SetTexture("_GrainTex", grainTexture); mat.SetTexture("_ScratchTex", scratchTexture); float grainScale = 1.0f / grainSize; // we have sanitized it earlier, won't be zero mat.SetVector("_GrainOffsetScale", new Vector4( Random.value, Random.value, (float)Screen.width / (float)grainTexture.width * grainScale, (float)Screen.height / (float)grainTexture.height * grainScale )); mat.SetVector("_ScratchOffsetScale", new Vector4( scratchX + Random.value * scratchJitter, scratchY + Random.value * scratchJitter, (float)Screen.width / (float)scratchTexture.width, (float)Screen.height / (float)scratchTexture.height )); mat.SetVector("_Intensity", new Vector4( Random.Range(grainIntensityMin, grainIntensityMax), Random.Range(scratchIntensityMin, scratchIntensityMax), 0, 0)); Graphics.Blit(source, destination, mat); } }