Initial
This commit is contained in:
commit
36a53f343e
1 changed files with 300431 additions and 0 deletions
|
|
@ -0,0 +1,470 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEngine.PostProcessing
|
||||
{
|
||||
using DebugMode = BuiltinDebugViewsModel.Mode;
|
||||
|
||||
#if UNITY_5_4_OR_NEWER
|
||||
[ImageEffectAllowedInSceneView]
|
||||
#endif
|
||||
[RequireComponent(typeof(Camera)), DisallowMultipleComponent, ExecuteInEditMode]
|
||||
[AddComponentMenu("Effects/Post-Processing Behaviour", -1)]
|
||||
public class PostProcessingBehaviour : MonoBehaviour
|
||||
{
|
||||
// Inspector fields
|
||||
public PostProcessingProfile profile;
|
||||
|
||||
public Func<Vector2, Matrix4x4> jitteredMatrixFunc;
|
||||
|
||||
// Internal helpers
|
||||
Dictionary<Type, KeyValuePair<CameraEvent, CommandBuffer>> m_CommandBuffers;
|
||||
List<PostProcessingComponentBase> m_Components;
|
||||
Dictionary<PostProcessingComponentBase, bool> m_ComponentStates;
|
||||
|
||||
MaterialFactory m_MaterialFactory;
|
||||
RenderTextureFactory m_RenderTextureFactory;
|
||||
PostProcessingContext m_Context;
|
||||
Camera m_Camera;
|
||||
PostProcessingProfile m_PreviousProfile;
|
||||
|
||||
bool m_RenderingInSceneView = false;
|
||||
|
||||
// Effect components
|
||||
BuiltinDebugViewsComponent m_DebugViews;
|
||||
AmbientOcclusionComponent m_AmbientOcclusion;
|
||||
ScreenSpaceReflectionComponent m_ScreenSpaceReflection;
|
||||
FogComponent m_FogComponent;
|
||||
MotionBlurComponent m_MotionBlur;
|
||||
TaaComponent m_Taa;
|
||||
EyeAdaptationComponent m_EyeAdaptation;
|
||||
DepthOfFieldComponent m_DepthOfField;
|
||||
BloomComponent m_Bloom;
|
||||
ChromaticAberrationComponent m_ChromaticAberration;
|
||||
ColorGradingComponent m_ColorGrading;
|
||||
UserLutComponent m_UserLut;
|
||||
GrainComponent m_Grain;
|
||||
VignetteComponent m_Vignette;
|
||||
DitheringComponent m_Dithering;
|
||||
FxaaComponent m_Fxaa;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_CommandBuffers = new Dictionary<Type, KeyValuePair<CameraEvent, CommandBuffer>>();
|
||||
m_MaterialFactory = new MaterialFactory();
|
||||
m_RenderTextureFactory = new RenderTextureFactory();
|
||||
m_Context = new PostProcessingContext();
|
||||
|
||||
// Keep a list of all post-fx for automation purposes
|
||||
m_Components = new List<PostProcessingComponentBase>();
|
||||
|
||||
// Component list
|
||||
m_DebugViews = AddComponent(new BuiltinDebugViewsComponent());
|
||||
m_AmbientOcclusion = AddComponent(new AmbientOcclusionComponent());
|
||||
m_ScreenSpaceReflection = AddComponent(new ScreenSpaceReflectionComponent());
|
||||
m_FogComponent = AddComponent(new FogComponent());
|
||||
m_MotionBlur = AddComponent(new MotionBlurComponent());
|
||||
m_Taa = AddComponent(new TaaComponent());
|
||||
m_EyeAdaptation = AddComponent(new EyeAdaptationComponent());
|
||||
m_DepthOfField = AddComponent(new DepthOfFieldComponent());
|
||||
m_Bloom = AddComponent(new BloomComponent());
|
||||
m_ChromaticAberration = AddComponent(new ChromaticAberrationComponent());
|
||||
m_ColorGrading = AddComponent(new ColorGradingComponent());
|
||||
m_UserLut = AddComponent(new UserLutComponent());
|
||||
m_Grain = AddComponent(new GrainComponent());
|
||||
m_Vignette = AddComponent(new VignetteComponent());
|
||||
m_Dithering = AddComponent(new DitheringComponent());
|
||||
m_Fxaa = AddComponent(new FxaaComponent());
|
||||
|
||||
// Prepare state observers
|
||||
m_ComponentStates = new Dictionary<PostProcessingComponentBase, bool>();
|
||||
|
||||
foreach (var component in m_Components)
|
||||
m_ComponentStates.Add(component, false);
|
||||
|
||||
useGUILayout = false;
|
||||
}
|
||||
|
||||
void OnPreCull()
|
||||
{
|
||||
// All the per-frame initialization logic has to be done in OnPreCull instead of Update
|
||||
// because [ImageEffectAllowedInSceneView] doesn't trigger Update events...
|
||||
|
||||
m_Camera = GetComponent<Camera>();
|
||||
|
||||
if (profile == null || m_Camera == null)
|
||||
return;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Track the scene view camera to disable some effects we don't want to see in the
|
||||
// scene view
|
||||
// Currently disabled effects :
|
||||
// - Temporal Antialiasing
|
||||
// - Depth of Field
|
||||
// - Motion blur
|
||||
m_RenderingInSceneView = UnityEditor.SceneView.currentDrawingSceneView != null
|
||||
&& UnityEditor.SceneView.currentDrawingSceneView.camera == m_Camera;
|
||||
#endif
|
||||
|
||||
// Prepare context
|
||||
var context = m_Context.Reset();
|
||||
context.profile = profile;
|
||||
context.renderTextureFactory = m_RenderTextureFactory;
|
||||
context.materialFactory = m_MaterialFactory;
|
||||
context.camera = m_Camera;
|
||||
|
||||
// Prepare components
|
||||
m_DebugViews.Init(context, profile.debugViews);
|
||||
m_AmbientOcclusion.Init(context, profile.ambientOcclusion);
|
||||
m_ScreenSpaceReflection.Init(context, profile.screenSpaceReflection);
|
||||
m_FogComponent.Init(context, profile.fog);
|
||||
m_MotionBlur.Init(context, profile.motionBlur);
|
||||
m_Taa.Init(context, profile.antialiasing);
|
||||
m_EyeAdaptation.Init(context, profile.eyeAdaptation);
|
||||
m_DepthOfField.Init(context, profile.depthOfField);
|
||||
m_Bloom.Init(context, profile.bloom);
|
||||
m_ChromaticAberration.Init(context, profile.chromaticAberration);
|
||||
m_ColorGrading.Init(context, profile.colorGrading);
|
||||
m_UserLut.Init(context, profile.userLut);
|
||||
m_Grain.Init(context, profile.grain);
|
||||
m_Vignette.Init(context, profile.vignette);
|
||||
m_Dithering.Init(context, profile.dithering);
|
||||
m_Fxaa.Init(context, profile.antialiasing);
|
||||
|
||||
// Handles profile change and 'enable' state observers
|
||||
if (m_PreviousProfile != profile)
|
||||
{
|
||||
DisableComponents();
|
||||
m_PreviousProfile = profile;
|
||||
}
|
||||
|
||||
CheckObservers();
|
||||
|
||||
// Find out which camera flags are needed before rendering begins
|
||||
// Note that motion vectors will only be available one frame after being enabled
|
||||
var flags = context.camera.depthTextureMode;
|
||||
foreach (var component in m_Components)
|
||||
{
|
||||
if (component.active)
|
||||
flags |= component.GetCameraFlags();
|
||||
}
|
||||
|
||||
context.camera.depthTextureMode = flags;
|
||||
|
||||
// Temporal antialiasing jittering, needs to happen before culling
|
||||
if (!m_RenderingInSceneView && m_Taa.active && !profile.debugViews.willInterrupt)
|
||||
m_Taa.SetProjectionMatrix(jitteredMatrixFunc);
|
||||
}
|
||||
|
||||
void OnPreRender()
|
||||
{
|
||||
if (profile == null)
|
||||
return;
|
||||
|
||||
// Command buffer-based effects should be set-up here
|
||||
TryExecuteCommandBuffer(m_DebugViews);
|
||||
TryExecuteCommandBuffer(m_AmbientOcclusion);
|
||||
TryExecuteCommandBuffer(m_ScreenSpaceReflection);
|
||||
TryExecuteCommandBuffer(m_FogComponent);
|
||||
|
||||
if (!m_RenderingInSceneView)
|
||||
TryExecuteCommandBuffer(m_MotionBlur);
|
||||
}
|
||||
|
||||
void OnPostRender()
|
||||
{
|
||||
if (profile == null || m_Camera == null)
|
||||
return;
|
||||
|
||||
if (!m_RenderingInSceneView && m_Taa.active && !profile.debugViews.willInterrupt)
|
||||
m_Context.camera.ResetProjectionMatrix();
|
||||
}
|
||||
|
||||
// Classic render target pipeline for RT-based effects
|
||||
void OnRenderImage(RenderTexture source, RenderTexture destination)
|
||||
{
|
||||
if (profile == null || m_Camera == null)
|
||||
{
|
||||
Graphics.Blit(source, destination);
|
||||
return;
|
||||
}
|
||||
|
||||
// Uber shader setup
|
||||
bool uberActive = false;
|
||||
bool fxaaActive = m_Fxaa.active;
|
||||
bool taaActive = m_Taa.active && !m_RenderingInSceneView;
|
||||
bool dofActive = m_DepthOfField.active && !m_RenderingInSceneView;
|
||||
|
||||
var uberMaterial = m_MaterialFactory.Get("Hidden/Post FX/Uber Shader");
|
||||
uberMaterial.shaderKeywords = null;
|
||||
|
||||
var src = source;
|
||||
var dst = destination;
|
||||
|
||||
if (taaActive)
|
||||
{
|
||||
var tempRT = m_RenderTextureFactory.Get(src);
|
||||
m_Taa.Render(src, tempRT);
|
||||
src = tempRT;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Render to a dedicated target when monitors are enabled so they can show information
|
||||
// about the final render.
|
||||
// At runtime the output will always be the backbuffer or whatever render target is
|
||||
// currently set on the camera.
|
||||
if (profile.monitors.onFrameEndEditorOnly != null)
|
||||
dst = m_RenderTextureFactory.Get(src);
|
||||
#endif
|
||||
|
||||
Texture autoExposure = GraphicsUtils.whiteTexture;
|
||||
if (m_EyeAdaptation.active)
|
||||
{
|
||||
uberActive = true;
|
||||
autoExposure = m_EyeAdaptation.Prepare(src, uberMaterial);
|
||||
}
|
||||
|
||||
uberMaterial.SetTexture("_AutoExposure", autoExposure);
|
||||
|
||||
if (dofActive)
|
||||
{
|
||||
uberActive = true;
|
||||
m_DepthOfField.Prepare(src, uberMaterial, taaActive, m_Taa.jitterVector, m_Taa.model.settings.taaSettings.motionBlending);
|
||||
}
|
||||
|
||||
if (m_Bloom.active)
|
||||
{
|
||||
uberActive = true;
|
||||
m_Bloom.Prepare(src, uberMaterial, autoExposure);
|
||||
}
|
||||
|
||||
uberActive |= TryPrepareUberImageEffect(m_ChromaticAberration, uberMaterial);
|
||||
uberActive |= TryPrepareUberImageEffect(m_ColorGrading, uberMaterial);
|
||||
uberActive |= TryPrepareUberImageEffect(m_Vignette, uberMaterial);
|
||||
uberActive |= TryPrepareUberImageEffect(m_UserLut, uberMaterial);
|
||||
|
||||
var fxaaMaterial = fxaaActive
|
||||
? m_MaterialFactory.Get("Hidden/Post FX/FXAA")
|
||||
: null;
|
||||
|
||||
if (fxaaActive)
|
||||
{
|
||||
fxaaMaterial.shaderKeywords = null;
|
||||
TryPrepareUberImageEffect(m_Grain, fxaaMaterial);
|
||||
TryPrepareUberImageEffect(m_Dithering, fxaaMaterial);
|
||||
|
||||
if (uberActive)
|
||||
{
|
||||
var output = m_RenderTextureFactory.Get(src);
|
||||
Graphics.Blit(src, output, uberMaterial, 0);
|
||||
src = output;
|
||||
}
|
||||
|
||||
m_Fxaa.Render(src, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
uberActive |= TryPrepareUberImageEffect(m_Grain, uberMaterial);
|
||||
uberActive |= TryPrepareUberImageEffect(m_Dithering, uberMaterial);
|
||||
|
||||
if (uberActive)
|
||||
{
|
||||
if (!GraphicsUtils.isLinearColorSpace)
|
||||
uberMaterial.EnableKeyword("UNITY_COLORSPACE_GAMMA");
|
||||
|
||||
Graphics.Blit(src, dst, uberMaterial, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!uberActive && !fxaaActive)
|
||||
Graphics.Blit(src, dst);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (profile.monitors.onFrameEndEditorOnly != null)
|
||||
{
|
||||
Graphics.Blit(dst, destination);
|
||||
|
||||
var oldRt = RenderTexture.active;
|
||||
profile.monitors.onFrameEndEditorOnly(dst);
|
||||
RenderTexture.active = oldRt;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_RenderTextureFactory.ReleaseAll();
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return;
|
||||
|
||||
if (profile == null || m_Camera == null)
|
||||
return;
|
||||
|
||||
if (m_EyeAdaptation.active && profile.debugViews.IsModeActive(DebugMode.EyeAdaptation))
|
||||
m_EyeAdaptation.OnGUI();
|
||||
else if (m_ColorGrading.active && profile.debugViews.IsModeActive(DebugMode.LogLut))
|
||||
m_ColorGrading.OnGUI();
|
||||
else if (m_UserLut.active && profile.debugViews.IsModeActive(DebugMode.UserLut))
|
||||
m_UserLut.OnGUI();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
// Clear command buffers
|
||||
foreach (var cb in m_CommandBuffers.Values)
|
||||
{
|
||||
m_Camera.RemoveCommandBuffer(cb.Key, cb.Value);
|
||||
cb.Value.Dispose();
|
||||
}
|
||||
|
||||
m_CommandBuffers.Clear();
|
||||
|
||||
// Clear components
|
||||
if (profile != null)
|
||||
DisableComponents();
|
||||
|
||||
m_Components.Clear();
|
||||
|
||||
// Factories
|
||||
m_MaterialFactory.Dispose();
|
||||
m_RenderTextureFactory.Dispose();
|
||||
GraphicsUtils.Dispose();
|
||||
}
|
||||
|
||||
public void ResetTemporalEffects()
|
||||
{
|
||||
m_Taa.ResetHistory();
|
||||
m_MotionBlur.ResetHistory();
|
||||
m_EyeAdaptation.ResetHistory();
|
||||
}
|
||||
|
||||
#region State management
|
||||
|
||||
List<PostProcessingComponentBase> m_ComponentsToEnable = new List<PostProcessingComponentBase>();
|
||||
List<PostProcessingComponentBase> m_ComponentsToDisable = new List<PostProcessingComponentBase>();
|
||||
|
||||
void CheckObservers()
|
||||
{
|
||||
foreach (var cs in m_ComponentStates)
|
||||
{
|
||||
var component = cs.Key;
|
||||
var state = component.GetModel().enabled;
|
||||
|
||||
if (state != cs.Value)
|
||||
{
|
||||
if (state) m_ComponentsToEnable.Add(component);
|
||||
else m_ComponentsToDisable.Add(component);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_ComponentsToDisable.Count; i++)
|
||||
{
|
||||
var c = m_ComponentsToDisable[i];
|
||||
m_ComponentStates[c] = false;
|
||||
c.OnDisable();
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_ComponentsToEnable.Count; i++)
|
||||
{
|
||||
var c = m_ComponentsToEnable[i];
|
||||
m_ComponentStates[c] = true;
|
||||
c.OnEnable();
|
||||
}
|
||||
|
||||
m_ComponentsToDisable.Clear();
|
||||
m_ComponentsToEnable.Clear();
|
||||
}
|
||||
|
||||
void DisableComponents()
|
||||
{
|
||||
foreach (var component in m_Components)
|
||||
{
|
||||
var model = component.GetModel();
|
||||
if (model != null && model.enabled)
|
||||
component.OnDisable();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command buffer handling & rendering helpers
|
||||
// Placeholders before the upcoming Scriptable Render Loop as command buffers will be
|
||||
// executed on the go so we won't need of all that stuff
|
||||
CommandBuffer AddCommandBuffer<T>(CameraEvent evt, string name)
|
||||
where T : PostProcessingModel
|
||||
{
|
||||
var cb = new CommandBuffer { name = name };
|
||||
var kvp = new KeyValuePair<CameraEvent, CommandBuffer>(evt, cb);
|
||||
m_CommandBuffers.Add(typeof(T), kvp);
|
||||
m_Camera.AddCommandBuffer(evt, kvp.Value);
|
||||
return kvp.Value;
|
||||
}
|
||||
|
||||
void RemoveCommandBuffer<T>()
|
||||
where T : PostProcessingModel
|
||||
{
|
||||
KeyValuePair<CameraEvent, CommandBuffer> kvp;
|
||||
var type = typeof(T);
|
||||
|
||||
if (!m_CommandBuffers.TryGetValue(type, out kvp))
|
||||
return;
|
||||
|
||||
m_Camera.RemoveCommandBuffer(kvp.Key, kvp.Value);
|
||||
m_CommandBuffers.Remove(type);
|
||||
kvp.Value.Dispose();
|
||||
}
|
||||
|
||||
CommandBuffer GetCommandBuffer<T>(CameraEvent evt, string name)
|
||||
where T : PostProcessingModel
|
||||
{
|
||||
CommandBuffer cb;
|
||||
KeyValuePair<CameraEvent, CommandBuffer> kvp;
|
||||
|
||||
if (!m_CommandBuffers.TryGetValue(typeof(T), out kvp))
|
||||
{
|
||||
cb = AddCommandBuffer<T>(evt, name);
|
||||
}
|
||||
else if (kvp.Key != evt)
|
||||
{
|
||||
RemoveCommandBuffer<T>();
|
||||
cb = AddCommandBuffer<T>(evt, name);
|
||||
}
|
||||
else cb = kvp.Value;
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
void TryExecuteCommandBuffer<T>(PostProcessingComponentCommandBuffer<T> component)
|
||||
where T : PostProcessingModel
|
||||
{
|
||||
if (component.active)
|
||||
{
|
||||
var cb = GetCommandBuffer<T>(component.GetCameraEvent(), component.GetName());
|
||||
cb.Clear();
|
||||
component.PopulateCommandBuffer(cb);
|
||||
}
|
||||
else RemoveCommandBuffer<T>();
|
||||
}
|
||||
|
||||
bool TryPrepareUberImageEffect<T>(PostProcessingComponentRenderTexture<T> component, Material material)
|
||||
where T : PostProcessingModel
|
||||
{
|
||||
if (!component.active)
|
||||
return false;
|
||||
|
||||
component.Prepare(material);
|
||||
return true;
|
||||
}
|
||||
|
||||
T AddComponent<T>(T component)
|
||||
where T : PostProcessingComponentBase
|
||||
{
|
||||
m_Components.Add(component);
|
||||
return component;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue