282 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using UnityEngine;
 | 
						|
 | 
						|
// Glow uses the alpha channel as a source of "extra brightness".
 | 
						|
// All builtin Unity shaders output baseTexture.alpha * color.alpha, plus
 | 
						|
// specularHighlight * specColor.alpha into that.
 | 
						|
// Usually you'd want either to make base textures to have zero alpha; or
 | 
						|
// set the color to have zero alpha (by default alpha is 0.5).
 | 
						|
 | 
						|
[ExecuteInEditMode]
 | 
						|
[RequireComponent(typeof(Camera))]
 | 
						|
[AddComponentMenu("Image Effects/Glow")]
 | 
						|
public class GlowEffect : MonoBehaviour
 | 
						|
{
 | 
						|
    /// The brightness of the glow. Values larger than one give extra "boost".
 | 
						|
    public float glowIntensity = 1.5f;
 | 
						|
 | 
						|
    /// Blur iterations - larger number means more blur.
 | 
						|
    public int blurIterations = 3;
 | 
						|
 | 
						|
    /// Blur spread for each iteration. Lower values
 | 
						|
    /// give better looking blur, but require more iterations to
 | 
						|
    /// get large blurs. Value is usually between 0.5 and 1.0.
 | 
						|
    public float blurSpread = 0.7f;
 | 
						|
 | 
						|
    /// Tint glow with this color. Alpha adds additional glow everywhere.
 | 
						|
    public Color glowTint = Color.white;
 | 
						|
 | 
						|
 | 
						|
    // --------------------------------------------------------
 | 
						|
    // The final composition shader:
 | 
						|
    //   adds (glow color * glow alpha * amount) to the original image.
 | 
						|
    // In the combiner glow amount can be only in 0..1 range; we apply extra
 | 
						|
    // amount during the blurring phase.
 | 
						|
 | 
						|
    private static string compositeMatString =
 | 
						|
@"Shader ""GlowCompose"" {
 | 
						|
	Properties {
 | 
						|
		_Color (""Glow Amount"", Color) = (1,1,1,1)
 | 
						|
		_MainTex ("""", RECT) = ""white"" {}
 | 
						|
	}
 | 
						|
	SubShader {
 | 
						|
		Pass {
 | 
						|
			ZTest Always Cull Off ZWrite Off Fog { Mode Off }
 | 
						|
			Blend One One
 | 
						|
			SetTexture [_MainTex] {constantColor [_Color] combine constant * texture DOUBLE}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	Fallback off
 | 
						|
}";
 | 
						|
 | 
						|
    static Material m_CompositeMaterial = null;
 | 
						|
    protected static Material compositeMaterial
 | 
						|
    {
 | 
						|
        get
 | 
						|
        {
 | 
						|
            if (m_CompositeMaterial == null)
 | 
						|
            {
 | 
						|
                m_CompositeMaterial = new Material(compositeMatString);
 | 
						|
                m_CompositeMaterial.hideFlags = HideFlags.HideAndDontSave;
 | 
						|
                m_CompositeMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
 | 
						|
            }
 | 
						|
            return m_CompositeMaterial;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // --------------------------------------------------------
 | 
						|
    // The blur iteration shader.
 | 
						|
    // Basically it just takes 4 texture samples and averages them.
 | 
						|
    // By applying it repeatedly and spreading out sample locations
 | 
						|
    // we get a Gaussian blur approximation.
 | 
						|
    // The alpha value in _Color would normally be 0.25 (to average 4 samples),
 | 
						|
    // however if we have glow amount larger than 1 then we increase this.
 | 
						|
 | 
						|
    private static string blurMatString =
 | 
						|
@"Shader ""GlowConeTap"" {
 | 
						|
	Properties {
 | 
						|
		_Color (""Blur Boost"", Color) = (0,0,0,0.25)
 | 
						|
		_MainTex ("""", RECT) = ""white"" {}
 | 
						|
	}
 | 
						|
	SubShader {
 | 
						|
		Pass {
 | 
						|
			ZTest Always Cull Off ZWrite Off Fog { Mode Off }
 | 
						|
			SetTexture [_MainTex] {constantColor [_Color] combine texture * constant alpha}
 | 
						|
			SetTexture [_MainTex] {constantColor [_Color] combine texture * constant + previous}
 | 
						|
			SetTexture [_MainTex] {constantColor [_Color] combine texture * constant + previous}
 | 
						|
			SetTexture [_MainTex] {constantColor [_Color] combine texture * constant + previous}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	Fallback off
 | 
						|
}";
 | 
						|
 | 
						|
    static Material m_BlurMaterial = null;
 | 
						|
    protected static Material blurMaterial
 | 
						|
    {
 | 
						|
        get
 | 
						|
        {
 | 
						|
            if (m_BlurMaterial == null)
 | 
						|
            {
 | 
						|
                m_BlurMaterial = new Material(blurMatString);
 | 
						|
                m_BlurMaterial.hideFlags = HideFlags.HideAndDontSave;
 | 
						|
                m_BlurMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
 | 
						|
            }
 | 
						|
            return m_BlurMaterial;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // --------------------------------------------------------
 | 
						|
    // The image downsample shaders for each brightness mode.
 | 
						|
    // It is in external assets as it's quite complex and uses Cg.
 | 
						|
 | 
						|
    public Shader downsampleShader;
 | 
						|
    Material m_DownsampleMaterial = null;
 | 
						|
    protected Material downsampleMaterial
 | 
						|
    {
 | 
						|
        get
 | 
						|
        {
 | 
						|
            if (m_DownsampleMaterial == null)
 | 
						|
            {
 | 
						|
                m_DownsampleMaterial = new Material(downsampleShader);
 | 
						|
                m_DownsampleMaterial.hideFlags = HideFlags.HideAndDontSave;
 | 
						|
            }
 | 
						|
            return m_DownsampleMaterial;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // --------------------------------------------------------
 | 
						|
    //  finally, the actual code
 | 
						|
 | 
						|
    protected void OnDisable()
 | 
						|
    {
 | 
						|
        if (m_CompositeMaterial)
 | 
						|
        {
 | 
						|
            DestroyImmediate(m_CompositeMaterial.shader);
 | 
						|
            DestroyImmediate(m_CompositeMaterial);
 | 
						|
        }
 | 
						|
        if (m_BlurMaterial)
 | 
						|
        {
 | 
						|
            DestroyImmediate(m_BlurMaterial.shader);
 | 
						|
            DestroyImmediate(m_BlurMaterial);
 | 
						|
        }
 | 
						|
        if (m_DownsampleMaterial)
 | 
						|
            DestroyImmediate(m_DownsampleMaterial);
 | 
						|
    }
 | 
						|
 | 
						|
    protected void Start()
 | 
						|
    {
 | 
						|
        // Disable if we don't support image effects
 | 
						|
        if (!SystemInfo.supportsImageEffects)
 | 
						|
        {
 | 
						|
            enabled = false;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Disable the effect if no downsample shader is setup
 | 
						|
        if (downsampleShader == null)
 | 
						|
        {
 | 
						|
            Debug.Log("No downsample shader assigned! Disabling glow.");
 | 
						|
            enabled = false;
 | 
						|
        }
 | 
						|
        // Disable if any of the shaders can't run on the users graphics card
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (!blurMaterial.shader.isSupported)
 | 
						|
                enabled = false;
 | 
						|
            if (!compositeMaterial.shader.isSupported)
 | 
						|
                enabled = false;
 | 
						|
            if (!downsampleMaterial.shader.isSupported)
 | 
						|
                enabled = false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Performs one blur iteration.
 | 
						|
    public void FourTapCone(RenderTexture source, RenderTexture dest, int iteration)
 | 
						|
    {
 | 
						|
        RenderTexture.active = dest;
 | 
						|
        blurMaterial.SetTexture("_MainTex", source);
 | 
						|
 | 
						|
        float offsetX = (.5F + iteration * blurSpread) / (float)source.width;
 | 
						|
        float offsetY = (.5F + iteration * blurSpread) / (float)source.height;
 | 
						|
        GL.PushMatrix();
 | 
						|
        GL.LoadOrtho();
 | 
						|
 | 
						|
        for (int i = 0; i < blurMaterial.passCount; i++)
 | 
						|
        {
 | 
						|
            blurMaterial.SetPass(i);
 | 
						|
            Render4TapQuad(dest, offsetX, offsetY);
 | 
						|
        }
 | 
						|
        GL.PopMatrix();
 | 
						|
    }
 | 
						|
 | 
						|
    // Downsamples the texture to a quarter resolution.
 | 
						|
    private void DownSample4x(RenderTexture source, RenderTexture dest)
 | 
						|
    {
 | 
						|
        downsampleMaterial.color = new Color(glowTint.r, glowTint.g, glowTint.b, glowTint.a / 4.0f);
 | 
						|
        ImageEffects.BlitWithMaterial(downsampleMaterial, source, dest);
 | 
						|
    }
 | 
						|
 | 
						|
    // Called by the camera to apply the image effect
 | 
						|
    void OnRenderImage(RenderTexture source, RenderTexture destination)
 | 
						|
    {
 | 
						|
 | 
						|
        if (!source)
 | 
						|
        {	//Sometimes occurs when entering or exiting water...
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Clamp parameters to sane values
 | 
						|
        glowIntensity = Mathf.Clamp(glowIntensity, 0.0f, 10.0f);
 | 
						|
        blurIterations = Mathf.Clamp(blurIterations, 0, 30);
 | 
						|
        blurSpread = Mathf.Clamp(blurSpread, 0.5f, 1.0f);
 | 
						|
 | 
						|
        RenderTexture buffer = RenderTexture.GetTemporary(source.width / 4, source.height / 4, 0);
 | 
						|
        RenderTexture buffer2 = RenderTexture.GetTemporary(source.width / 4, source.height / 4, 0);
 | 
						|
 | 
						|
        // Copy source to the 4x4 smaller texture.
 | 
						|
        DownSample4x(source, buffer);
 | 
						|
 | 
						|
        // Blur the small texture
 | 
						|
        float extraBlurBoost = Mathf.Clamp01((glowIntensity - 1.0f) / 4.0f);
 | 
						|
        blurMaterial.color = new Color(1F, 1F, 1F, 0.25f + extraBlurBoost);
 | 
						|
 | 
						|
        bool oddEven = true;
 | 
						|
        for (int i = 0; i < blurIterations; i++)
 | 
						|
        {
 | 
						|
            if (oddEven)
 | 
						|
                FourTapCone(buffer, buffer2, i);
 | 
						|
            else
 | 
						|
                FourTapCone(buffer2, buffer, i);
 | 
						|
            oddEven = !oddEven;
 | 
						|
        }
 | 
						|
        ImageEffects.Blit(source, destination);
 | 
						|
 | 
						|
        if (oddEven)
 | 
						|
            BlitGlow(buffer, destination);
 | 
						|
        else
 | 
						|
            BlitGlow(buffer2, destination);
 | 
						|
 | 
						|
        RenderTexture.ReleaseTemporary(buffer);
 | 
						|
        RenderTexture.ReleaseTemporary(buffer2);
 | 
						|
    }
 | 
						|
 | 
						|
    public void BlitGlow(RenderTexture source, RenderTexture dest)
 | 
						|
    {
 | 
						|
        compositeMaterial.color = new Color(1F, 1F, 1F, Mathf.Clamp01(glowIntensity));
 | 
						|
        ImageEffects.BlitWithMaterial(compositeMaterial, source, dest);
 | 
						|
    }
 | 
						|
 | 
						|
    private static void Render4TapQuad(RenderTexture dest, float offsetX, float offsetY)
 | 
						|
    {
 | 
						|
        GL.Begin(GL.QUADS);
 | 
						|
 | 
						|
        // Direct3D needs interesting texel offsets!		
 | 
						|
        Vector2 off = Vector2.zero;
 | 
						|
        if (dest != null)
 | 
						|
            off = dest.GetTexelOffset() * 0.75f;
 | 
						|
 | 
						|
        Set4TexCoords(off.x, off.y, offsetX, offsetY);
 | 
						|
        GL.Vertex3(0, 0, .1f);
 | 
						|
 | 
						|
        Set4TexCoords(1.0f + off.x, off.y, offsetX, offsetY);
 | 
						|
        GL.Vertex3(1, 0, .1f);
 | 
						|
 | 
						|
        Set4TexCoords(1.0f + off.x, 1.0f + off.y, offsetX, offsetY);
 | 
						|
        GL.Vertex3(1, 1, .1f);
 | 
						|
 | 
						|
        Set4TexCoords(off.x, 1.0f + off.y, offsetX, offsetY);
 | 
						|
        GL.Vertex3(0, 1, .1f);
 | 
						|
 | 
						|
        GL.End();
 | 
						|
    }
 | 
						|
 | 
						|
    private static void Set4TexCoords(float x, float y, float offsetX, float offsetY)
 | 
						|
    {
 | 
						|
        GL.MultiTexCoord2(0, x - offsetX, y - offsetY);
 | 
						|
        GL.MultiTexCoord2(1, x + offsetX, y - offsetY);
 | 
						|
        GL.MultiTexCoord2(2, x + offsetX, y + offsetY);
 | 
						|
        GL.MultiTexCoord2(3, x - offsetX, y + offsetY);
 | 
						|
    }
 | 
						|
} |