FiE-Game/Assets/PostProcessing/Runtime/Components/DepthOfFieldComponent.cs
2023-07-25 00:52:50 +05:00

165 lines
7 KiB
C#

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;
}
}
}