You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
8.1 KiB
245 lines
8.1 KiB
using System; |
|
using UnityEngine; |
|
|
|
namespace UnityStandardAssets.CinematicEffects |
|
{ |
|
[ExecuteInEditMode] |
|
[RequireComponent(typeof(Camera))] |
|
[AddComponentMenu("Image Effects/Cinematic/ME_Bloom")] |
|
#if UNITY_5_4_OR_NEWER |
|
[ImageEffectAllowedInSceneView] |
|
#endif |
|
public class ME_Bloom : MonoBehaviour |
|
{ |
|
[Serializable] |
|
public struct Settings |
|
{ |
|
[SerializeField] |
|
[Tooltip("Filters out pixels under this level of brightness.")] |
|
public float threshold; |
|
|
|
public float thresholdGamma |
|
{ |
|
set { threshold = value; } |
|
get { return Mathf.Max(0.0f, threshold); } |
|
} |
|
|
|
public float thresholdLinear |
|
{ |
|
set { threshold = Mathf.LinearToGammaSpace(value); } |
|
get { return Mathf.GammaToLinearSpace(thresholdGamma); } |
|
} |
|
|
|
[SerializeField, Range(0, 1)] |
|
[Tooltip("Makes transition between under/over-threshold gradual.")] |
|
public float softKnee; |
|
|
|
[SerializeField, Range(1, 7)] |
|
[Tooltip("Changes extent of veiling effects in a screen resolution-independent fashion.")] |
|
public float radius; |
|
|
|
[SerializeField] |
|
[Tooltip("Blend factor of the result image.")] |
|
public float intensity; |
|
|
|
[SerializeField] |
|
[Tooltip("Controls filter quality and buffer resolution.")] |
|
public bool highQuality; |
|
|
|
[SerializeField] |
|
[Tooltip("Reduces flashing noise with an additional filter.")] |
|
public bool antiFlicker; |
|
|
|
[Tooltip("Dirtiness texture to add smudges or dust to the lens.")] |
|
public Texture dirtTexture; |
|
|
|
[ME_MinAttribute_ME(0f), Tooltip("Amount of lens dirtiness.")] |
|
public float dirtIntensity; |
|
|
|
public static Settings defaultSettings |
|
{ |
|
get |
|
{ |
|
var settings = new Settings |
|
{ |
|
threshold = 1.1f, |
|
softKnee = 0.1f, |
|
radius = 7.0f, |
|
intensity = 0.5f, |
|
highQuality = true, |
|
antiFlicker = true, |
|
dirtTexture = null, |
|
dirtIntensity = 2.5f |
|
}; |
|
return settings; |
|
} |
|
} |
|
} |
|
|
|
#region Public Properties |
|
|
|
[SerializeField] |
|
public Settings settings = Settings.defaultSettings; |
|
|
|
#endregion |
|
|
|
[SerializeField, HideInInspector] |
|
private Shader m_Shader; |
|
|
|
public Shader shader |
|
{ |
|
get |
|
{ |
|
if (m_Shader == null) |
|
{ |
|
const string shaderName = "Hidden/Image Effects/Cinematic/ME_Bloom"; |
|
m_Shader = Shader.Find(shaderName); |
|
} |
|
|
|
return m_Shader; |
|
} |
|
} |
|
|
|
private Material m_Material; |
|
public Material material |
|
{ |
|
get |
|
{ |
|
if (m_Material == null) |
|
m_Material = ME_ImageEffectHelper_ME.CheckShaderAndCreateMaterial(shader); |
|
|
|
return m_Material; |
|
} |
|
} |
|
|
|
#region Private Members |
|
|
|
const int kMaxIterations = 16; |
|
RenderTexture[] m_blurBuffer1 = new RenderTexture[kMaxIterations]; |
|
RenderTexture[] m_blurBuffer2 = new RenderTexture[kMaxIterations]; |
|
|
|
int m_Threshold; |
|
int m_Curve; |
|
int m_PrefilterOffs; |
|
int m_SampleScale; |
|
int m_Intensity; |
|
int m_DirtTex; |
|
int m_DirtIntensity; |
|
int m_BaseTex; |
|
|
|
private void Awake() |
|
{ |
|
m_Threshold = Shader.PropertyToID("_Threshold"); |
|
m_Curve = Shader.PropertyToID("_Curve"); |
|
m_PrefilterOffs = Shader.PropertyToID("_PrefilterOffs"); |
|
m_SampleScale = Shader.PropertyToID("_SampleScale"); |
|
m_Intensity = Shader.PropertyToID("_Intensity"); |
|
m_DirtTex = Shader.PropertyToID("_DirtTex"); |
|
m_DirtIntensity = Shader.PropertyToID("_DirtIntensity"); |
|
m_BaseTex = Shader.PropertyToID("_BaseTex"); |
|
} |
|
|
|
private void OnEnable() |
|
{ |
|
if (!ME_ImageEffectHelper_ME.IsSupported(shader, true, false, this)) |
|
enabled = false; |
|
} |
|
|
|
private void OnDisable() |
|
{ |
|
if (m_Material != null) |
|
DestroyImmediate(m_Material); |
|
|
|
m_Material = null; |
|
} |
|
|
|
private void OnRenderImage(RenderTexture source, RenderTexture destination) |
|
{ |
|
var useRGBM = Application.isMobilePlatform; |
|
|
|
// source texture size |
|
var tw = source.width; |
|
var th = source.height; |
|
|
|
// halve the texture size for the low quality mode |
|
if (!settings.highQuality) |
|
{ |
|
tw /= 2; |
|
th /= 2; |
|
} |
|
|
|
// blur buffer format |
|
var rtFormat = useRGBM ? RenderTextureFormat.Default : RenderTextureFormat.DefaultHDR; |
|
|
|
// determine the iteration count |
|
var logh = Mathf.Log(th, 2) + settings.radius - 8; |
|
var logh_i = (int)logh; |
|
var iterations = Mathf.Clamp(logh_i, 1, kMaxIterations); |
|
|
|
// update the shader properties |
|
var threshold = settings.thresholdLinear; |
|
material.SetFloat(m_Threshold, threshold); |
|
|
|
var knee = threshold * settings.softKnee + 1e-5f; |
|
var curve = new Vector3(threshold - knee, knee * 2, 0.25f / knee); |
|
material.SetVector(m_Curve, curve); |
|
|
|
var pfo = !settings.highQuality && settings.antiFlicker; |
|
material.SetFloat(m_PrefilterOffs, pfo ? -0.5f : 0.0f); |
|
|
|
material.SetFloat(m_SampleScale, 0.5f + logh - logh_i); |
|
material.SetFloat(m_Intensity, Mathf.Max(0.0f, settings.intensity)); |
|
|
|
bool useDirtTexture = false; |
|
if (settings.dirtTexture != null) |
|
{ |
|
material.SetTexture(m_DirtTex, settings.dirtTexture); |
|
material.SetFloat(m_DirtIntensity, settings.dirtIntensity); |
|
useDirtTexture = true; |
|
} |
|
|
|
// prefilter pass |
|
var prefiltered = RenderTexture.GetTemporary(tw, th, 0, rtFormat); |
|
Graphics.Blit(source, prefiltered, material, settings.antiFlicker ? 1 : 0); |
|
|
|
// construct a mip pyramid |
|
var last = prefiltered; |
|
for (var level = 0; level < iterations; level++) |
|
{ |
|
m_blurBuffer1[level] = RenderTexture.GetTemporary(last.width / 2, last.height / 2, 0, rtFormat); |
|
Graphics.Blit(last, m_blurBuffer1[level], material, level == 0 ? (settings.antiFlicker ? 3 : 2) : 4); |
|
last = m_blurBuffer1[level]; |
|
} |
|
|
|
// upsample and combine loop |
|
for (var level = iterations - 2; level >= 0; level--) |
|
{ |
|
var basetex = m_blurBuffer1[level]; |
|
material.SetTexture(m_BaseTex, basetex); |
|
m_blurBuffer2[level] = RenderTexture.GetTemporary(basetex.width, basetex.height, 0, rtFormat); |
|
Graphics.Blit(last, m_blurBuffer2[level], material, settings.highQuality ? 6 : 5); |
|
last = m_blurBuffer2[level]; |
|
} |
|
|
|
// finish process |
|
int pass = useDirtTexture ? 9 : 7; |
|
pass += settings.highQuality ? 1 : 0; |
|
|
|
material.SetTexture(m_BaseTex, source); |
|
Graphics.Blit(last, destination, material, pass); |
|
|
|
// release the temporary buffers |
|
for (var i = 0; i < kMaxIterations; i++) |
|
{ |
|
if (m_blurBuffer1[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer1[i]); |
|
if (m_blurBuffer2[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer2[i]); |
|
m_blurBuffer1[i] = null; |
|
m_blurBuffer2[i] = null; |
|
} |
|
|
|
RenderTexture.ReleaseTemporary(prefiltered); |
|
} |
|
|
|
#endregion |
|
} |
|
}
|
|
|