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.
165 lines
7.0 KiB
165 lines
7.0 KiB
using UnityEngine.Rendering; |
|
|
|
namespace UnityEngine.PostProcessing |
|
{ |
|
using DebugMode = BuiltinDebugViewsModel.Mode; |
|
|
|
public sealed class DepthOfFieldComponent : PostProcessingComponentRenderTexture<DepthOfFieldModel> |
|
{ |
|
static class Uniforms |
|
{ |
|
internal static readonly int _DepthOfFieldTex = Shader.PropertyToID("_DepthOfFieldTex"); |
|
internal static readonly int _DepthOfFieldCoCTex = Shader.PropertyToID("_DepthOfFieldCoCTex"); |
|
internal static readonly int _Distance = Shader.PropertyToID("_Distance"); |
|
internal static readonly int _LensCoeff = Shader.PropertyToID("_LensCoeff"); |
|
internal static readonly int _MaxCoC = Shader.PropertyToID("_MaxCoC"); |
|
internal static readonly int _RcpMaxCoC = Shader.PropertyToID("_RcpMaxCoC"); |
|
internal static readonly int _RcpAspect = Shader.PropertyToID("_RcpAspect"); |
|
internal static readonly int _MainTex = Shader.PropertyToID("_MainTex"); |
|
internal static readonly int _CoCTex = Shader.PropertyToID("_CoCTex"); |
|
internal static readonly int _TaaParams = Shader.PropertyToID("_TaaParams"); |
|
internal static readonly int _DepthOfFieldParams = Shader.PropertyToID("_DepthOfFieldParams"); |
|
} |
|
|
|
const string k_ShaderString = "Hidden/Post FX/Depth Of Field"; |
|
|
|
public override bool active |
|
{ |
|
get |
|
{ |
|
return model.enabled |
|
&& !context.interrupted; |
|
} |
|
} |
|
|
|
public override DepthTextureMode GetCameraFlags() |
|
{ |
|
return DepthTextureMode.Depth; |
|
} |
|
|
|
RenderTexture m_CoCHistory; |
|
|
|
// Height of the 35mm full-frame format (36mm x 24mm) |
|
const float k_FilmHeight = 0.024f; |
|
|
|
float CalculateFocalLength() |
|
{ |
|
var settings = model.settings; |
|
|
|
if (!settings.useCameraFov) |
|
return settings.focalLength / 1000f; |
|
|
|
float fov = context.camera.fieldOfView * Mathf.Deg2Rad; |
|
return 0.5f * k_FilmHeight / Mathf.Tan(0.5f * fov); |
|
} |
|
|
|
float CalculateMaxCoCRadius(int screenHeight) |
|
{ |
|
// Estimate the allowable maximum radius of CoC from the kernel |
|
// size (the equation below was empirically derived). |
|
float radiusInPixels = (float)model.settings.kernelSize * 4f + 6f; |
|
|
|
// Applying a 5% limit to the CoC radius to keep the size of |
|
// TileMax/NeighborMax small enough. |
|
return Mathf.Min(0.05f, radiusInPixels / screenHeight); |
|
} |
|
|
|
bool CheckHistory(int width, int height) |
|
{ |
|
return m_CoCHistory != null && m_CoCHistory.IsCreated() && |
|
m_CoCHistory.width == width && m_CoCHistory.height == height; |
|
} |
|
|
|
RenderTextureFormat SelectFormat(RenderTextureFormat primary, RenderTextureFormat secondary) |
|
{ |
|
if (SystemInfo.SupportsRenderTextureFormat(primary)) return primary; |
|
if (SystemInfo.SupportsRenderTextureFormat(secondary)) return secondary; |
|
return RenderTextureFormat.Default; |
|
} |
|
|
|
public void Prepare(RenderTexture source, Material uberMaterial, bool antialiasCoC, Vector2 taaJitter, float taaBlending) |
|
{ |
|
var settings = model.settings; |
|
var colorFormat = RenderTextureFormat.DefaultHDR; |
|
var cocFormat = SelectFormat(RenderTextureFormat.R8, RenderTextureFormat.RHalf); |
|
|
|
// Avoid using R8 on OSX with Metal. #896121, https://goo.gl/MgKqu6 |
|
#if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX) && !UNITY_2017_1_OR_NEWER |
|
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal) |
|
cocFormat = SelectFormat(RenderTextureFormat.RHalf, RenderTextureFormat.Default); |
|
#endif |
|
|
|
// Material setup |
|
var f = CalculateFocalLength(); |
|
var s1 = Mathf.Max(settings.focusDistance, f); |
|
var aspect = (float)source.width / source.height; |
|
var coeff = f * f / (settings.aperture * (s1 - f) * k_FilmHeight * 2); |
|
var maxCoC = CalculateMaxCoCRadius(source.height); |
|
|
|
var material = context.materialFactory.Get(k_ShaderString); |
|
material.SetFloat(Uniforms._Distance, s1); |
|
material.SetFloat(Uniforms._LensCoeff, coeff); |
|
material.SetFloat(Uniforms._MaxCoC, maxCoC); |
|
material.SetFloat(Uniforms._RcpMaxCoC, 1f / maxCoC); |
|
material.SetFloat(Uniforms._RcpAspect, 1f / aspect); |
|
|
|
// CoC calculation pass |
|
var rtCoC = context.renderTextureFactory.Get(context.width, context.height, 0, cocFormat, RenderTextureReadWrite.Linear); |
|
Graphics.Blit(null, rtCoC, material, 0); |
|
|
|
if (antialiasCoC) |
|
{ |
|
// CoC temporal filter pass |
|
material.SetTexture(Uniforms._CoCTex, rtCoC); |
|
|
|
var blend = CheckHistory(context.width, context.height) ? taaBlending : 0f; |
|
material.SetVector(Uniforms._TaaParams, new Vector3(taaJitter.x, taaJitter.y, blend)); |
|
|
|
var rtFiltered = RenderTexture.GetTemporary(context.width, context.height, 0, cocFormat); |
|
Graphics.Blit(m_CoCHistory, rtFiltered, material, 1); |
|
|
|
context.renderTextureFactory.Release(rtCoC); |
|
if (m_CoCHistory != null) RenderTexture.ReleaseTemporary(m_CoCHistory); |
|
|
|
m_CoCHistory = rtCoC = rtFiltered; |
|
} |
|
|
|
// Downsampling and prefiltering pass |
|
var rt1 = context.renderTextureFactory.Get(context.width / 2, context.height / 2, 0, colorFormat); |
|
material.SetTexture(Uniforms._CoCTex, rtCoC); |
|
Graphics.Blit(source, rt1, material, 2); |
|
|
|
// Bokeh simulation pass |
|
var rt2 = context.renderTextureFactory.Get(context.width / 2, context.height / 2, 0, colorFormat); |
|
Graphics.Blit(rt1, rt2, material, 3 + (int)settings.kernelSize); |
|
|
|
// Postfilter pass |
|
Graphics.Blit(rt2, rt1, material, 7); |
|
|
|
// Give the results to the uber shader. |
|
uberMaterial.SetVector(Uniforms._DepthOfFieldParams, new Vector3(s1, coeff, maxCoC)); |
|
|
|
if (context.profile.debugViews.IsModeActive(DebugMode.FocusPlane)) |
|
{ |
|
uberMaterial.EnableKeyword("DEPTH_OF_FIELD_COC_VIEW"); |
|
context.Interrupt(); |
|
} |
|
else |
|
{ |
|
uberMaterial.SetTexture(Uniforms._DepthOfFieldTex, rt1); |
|
uberMaterial.SetTexture(Uniforms._DepthOfFieldCoCTex, rtCoC); |
|
uberMaterial.EnableKeyword("DEPTH_OF_FIELD"); |
|
} |
|
|
|
context.renderTextureFactory.Release(rt2); |
|
} |
|
|
|
public override void OnDisable() |
|
{ |
|
if (m_CoCHistory != null) |
|
RenderTexture.ReleaseTemporary(m_CoCHistory); |
|
|
|
m_CoCHistory = null; |
|
} |
|
} |
|
}
|
|
|