diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs index 396107ce3cd..0bba60a792b 100644 --- a/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs +++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs @@ -89,11 +89,12 @@ enum Pass { CoCCalculation, CoCTemporalFilter, + downsampleInitialMaxCoC, + downsampleMaxCoC, + neighborMaxCoC, DownsampleAndPrefilter, BokehSmallKernel, - BokehMediumKernel, - BokehLargeKernel, - BokehVeryLargeKernel, + BokehDynamic, PostFilter, Combine, DebugOverlay @@ -106,6 +107,15 @@ enum Pass readonly RenderTexture[][] m_CoCHistoryTextures = new RenderTexture[k_NumEyes][]; int[] m_HistoryPingPong = new int[k_NumEyes]; + // The samples coordinates for kDiskAllKernels in DiskKernels.hlsl are normalized to 4 rings (coordinates with length 1 lie on the 4th ring). + // The ring placement are not evenly-spaced but: + // 1st ring: 8/29 + // 2nd ring: 15/29 + // 3rd ring: 22/29 + // 4th ring: 29/29 + static readonly float[] k_DisAllKernelRingOffsets = { 8f/29, 15f/29, 22f/29, 29f/29 }; + static readonly int[] k_DiskAllKernelSizes = { 1, 8, 22, 43, 71 }; + // Height of the 35mm full-frame format (36mm x 24mm) // TODO: Should be set by a physical camera const float k_FilmHeight = 0.024f; @@ -135,17 +145,46 @@ RenderTextureFormat SelectFormat(RenderTextureFormat primary, RenderTextureForma return RenderTextureFormat.Default; } - float CalculateMaxCoCRadius(int screenHeight) + float CalculateMaxCoCRadius(int screenHeight, out int mipLevel) { // Estimate the allowable maximum radius of CoC from the kernel // size (the equation below was empirically derived). float radiusInPixels = (float)settings.kernelSize.value * 4f + 6f; - + // Find the miplevel encasing the bokeh radius. + mipLevel = (int)(Mathf.Log(radiusInPixels * 2 - 1) / Mathf.Log(2)); + // Applying a 5% limit to the CoC radius to keep the size of // TileMax/NeighborMax small enough. return Mathf.Min(0.05f, radiusInPixels / screenHeight); } + void CalculateCoCKernelLimits(int screenHeight, out Vector4 cocKernelLimits) + { + // The sample points are grouped in 4 rings, but the distance between + // each ring is not even. + // Depending on a max CoC "distance", we can conservatively garantie + // only some rings need to be sampled. + // For instance, for a pixel C being processed, if the max CoC distance + // in the neighbouring pixels is less than ~14 pixels (at source image resolution), + // then the 4th ring does not need to be sampled. + // When sampling the half-resolution color texture, we sample the equivalent of + // 2 pixels radius from the full-resolution source image, thus the "spread" of + // each ring is 2 pixels wide in this diagram. + // + // Center pixel 1st ring 2nd ring 3rd ring 4th ring + // at 0 spread spread spread spread + // <-------> <-------> <-------> <-------> <-------> + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---> pixel offset at full-resolution + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + // ~a ~b ~c ~d + + float a = k_DisAllKernelRingOffsets[0] * 16 + 2; + float b = k_DisAllKernelRingOffsets[1] * 16 + 2; + float c = k_DisAllKernelRingOffsets[2] * 16 + 2; + //float d = k_DisAllKernelRingOffsets[3] * 16 + 2; + cocKernelLimits = new Vector4(2 - 0.5f, a - 0.5f, b - 0.5f, c - 0.5f) / screenHeight; + } + RenderTexture CheckHistory(int eye, int id, PostProcessRenderContext context, RenderTextureFormat format) { var rt = m_CoCHistoryTextures[eye][id]; @@ -166,6 +205,9 @@ RenderTexture CheckHistory(int eye, int id, PostProcessRenderContext context, Re public override void Render(PostProcessRenderContext context) { + // Legacy: if KERNEL_SMALL is selected, then run a coarser fixed sample pattern (no dynamic branching). + bool useDynamicBokeh = settings.kernelSize.value != KernelSize.Small; + // The coc is stored in alpha so we need a 4 channels target. Note that using ARGB32 // will result in a very weak near-blur. var colorFormat = context.camera.allowHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; @@ -177,15 +219,56 @@ public override void Render(PostProcessRenderContext context) var s1 = Mathf.Max(settings.focusDistance.value, f); var aspect = (float)context.screenWidth / (float)context.screenHeight; var coeff = f * f / (settings.aperture.value * (s1 - f) * scaledFilmHeight * 2f); - var maxCoC = CalculateMaxCoCRadius(context.screenHeight); + int maxCoCMipLevel; + var maxCoC = CalculateMaxCoCRadius(context.screenHeight, out maxCoCMipLevel); + + // pad full-resolution screen so that the number of mips required by maxCoCMipLevel does not cause the downsampling chain to skip row or colums of pixels. + int tileSize = 1 << maxCoCMipLevel; + int paddedWidth = ((context.width + tileSize - 1) >> maxCoCMipLevel) << maxCoCMipLevel; + int paddedHeight = ((context.height + tileSize - 1) >> maxCoCMipLevel) << maxCoCMipLevel; + + Vector4 cocKernelLimits; + CalculateCoCKernelLimits(context.screenHeight, out cocKernelLimits); + cocKernelLimits /= maxCoC; + + // When the user clamps the bokeh size, the sample coordinates must be renormalized to the number of rings requested. + float kernelScaleReNormalization = 1f; + float fgAlphaFactor = 0f; + + if (settings.kernelSize.value == KernelSize.Small) + { + kernelScaleReNormalization = 1f; // custom sampling pattern, does not use kDiskAllKernels array. + fgAlphaFactor = 0; // unused by shader + } + else if (settings.kernelSize.value == KernelSize.Medium) + { + kernelScaleReNormalization = 1f / k_DisAllKernelRingOffsets[1]; + fgAlphaFactor = 1f / k_DiskAllKernelSizes[1]; + } + else if (settings.kernelSize.value == KernelSize.Large) + { + kernelScaleReNormalization = 1f / k_DisAllKernelRingOffsets[2]; + fgAlphaFactor = 1f / ((k_DiskAllKernelSizes[1] + k_DiskAllKernelSizes[2]) * 0.5f); + } + else if (settings.kernelSize.value == KernelSize.VeryLarge) + { + kernelScaleReNormalization = 1f / k_DisAllKernelRingOffsets[3]; + fgAlphaFactor = 1f / k_DiskAllKernelSizes[2]; + } var sheet = context.propertySheets.Get(context.resources.shaders.depthOfField); sheet.properties.Clear(); sheet.properties.SetFloat(ShaderIDs.Distance, s1); sheet.properties.SetFloat(ShaderIDs.LensCoeff, coeff); + sheet.properties.SetVector(ShaderIDs.CoCKernelLimits, cocKernelLimits); + sheet.properties.SetVector(ShaderIDs.MaxCoCTexScale, new Vector4(paddedWidth / (float)context.width, paddedHeight / (float)context.height, context.width / (float)paddedWidth, context.height / (float)paddedHeight)); + sheet.properties.SetVector(ShaderIDs.KernelScale, new Vector4(maxCoC * kernelScaleReNormalization / aspect, maxCoC * kernelScaleReNormalization, maxCoC * kernelScaleReNormalization, 0f)); + sheet.properties.SetVector(ShaderIDs.MarginFactors, new Vector4(2f / (context.height >> 1), (context.height >> 1) / 2f, 0f, 0f)); sheet.properties.SetFloat(ShaderIDs.MaxCoC, maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpMaxCoC, 1f / maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpAspect, 1f / aspect); + sheet.properties.SetFloat(ShaderIDs.FgAlphaFactor, fgAlphaFactor); + sheet.properties.SetInteger(ShaderIDs.MaxRingIndex, (int)settings.kernelSize.value + 1); var cmd = context.command; cmd.BeginSample("DepthOfField"); @@ -213,13 +296,36 @@ public override void Render(PostProcessRenderContext context) cmd.SetGlobalTexture(ShaderIDs.CoCTex, historyWrite); } + // Generate a low-res maxCoC texture later used to infer how many samples are needed around any pixels to generate the bokeh effect. + if (useDynamicBokeh) + { + // Downsample MaxCoC. + context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.MaxCoCMips[1], 0, cocFormat, RenderTextureReadWrite.Linear, FilterMode.Point, paddedWidth >> 1, paddedHeight >> 1); + cmd.BlitFullscreenTriangle(ShaderIDs.CoCTex, ShaderIDs.MaxCoCMips[1], sheet, (int)Pass.downsampleInitialMaxCoC); + + // Downsample until tile-size reaches CoC max radius. + for (int i = 2; i <= maxCoCMipLevel; ++i) + { + context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.MaxCoCMips[i], 0, cocFormat, RenderTextureReadWrite.Linear, FilterMode.Point, paddedWidth >> i, paddedHeight >> i); + cmd.BlitFullscreenTriangle(ShaderIDs.MaxCoCMips[i - 1], ShaderIDs.MaxCoCMips[i], sheet, (int)Pass.downsampleMaxCoC); + } + + // Neighbor MaxCoC. + // We can then sample it during Bokeh simulation pass and dynamically adjust the number of samples (== number of rings) to generate the bokeh. + context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.MaxCoCTex, 0, cocFormat, RenderTextureReadWrite.Linear, FilterMode.Point, paddedWidth >> maxCoCMipLevel, paddedHeight >> maxCoCMipLevel); + cmd.BlitFullscreenTriangle(ShaderIDs.MaxCoCMips[maxCoCMipLevel], ShaderIDs.MaxCoCTex, sheet, (int)Pass.neighborMaxCoC); + } + // Downsampling and prefiltering pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTex, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(context.source, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter); // Bokeh simulation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTemp, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); - cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel + (int)settings.kernelSize.value); + if (useDynamicBokeh) + cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehDynamic); + else + cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel); // Postfilter pass cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTemp, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.PostFilter); diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs index f555f7b8560..d855da297fc 100644 --- a/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs +++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs @@ -67,11 +67,23 @@ static class ShaderIDs internal static readonly int DepthOfFieldTemp = Shader.PropertyToID("_DepthOfFieldTemp"); internal static readonly int DepthOfFieldTex = Shader.PropertyToID("_DepthOfFieldTex"); + internal static readonly int[] MaxCoCMips = new int[] { + Shader.PropertyToID("_CoCMip0"), Shader.PropertyToID("_CoCMip1"), Shader.PropertyToID("_CoCMip2"), Shader.PropertyToID("_CoCMip3"), + Shader.PropertyToID("_CoCMip4"), Shader.PropertyToID("_CoCMip5"), Shader.PropertyToID("_CoCMip6"), Shader.PropertyToID("_CoCMip7"), + Shader.PropertyToID("_CoCMip8"), Shader.PropertyToID("_CoCMip9"), Shader.PropertyToID("_CoCMip10"), Shader.PropertyToID("_CoCMip11") + }; + internal static readonly int MaxCoCTex = Shader.PropertyToID("_MaxCoCTex"); internal static readonly int Distance = Shader.PropertyToID("_Distance"); internal static readonly int LensCoeff = Shader.PropertyToID("_LensCoeff"); + internal static readonly int CoCKernelLimits = Shader.PropertyToID("_CoCKernelLimits"); + internal static readonly int MaxCoCTexScale = Shader.PropertyToID("_MaxCoCTexScale"); + internal static readonly int KernelScale = Shader.PropertyToID("_KernelScale"); + internal static readonly int MarginFactors = Shader.PropertyToID("_MarginFactors"); 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 FgAlphaFactor = Shader.PropertyToID("_FgAlphaFactor"); + internal static readonly int MaxRingIndex = Shader.PropertyToID("_MaxRingIndex"); internal static readonly int CoCTex = Shader.PropertyToID("_CoCTex"); internal static readonly int TaaParams = Shader.PropertyToID("_TaaParams"); diff --git a/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl b/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl index 693304ae0f0..6fb89426f1c 100644 --- a/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl +++ b/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl @@ -12,6 +12,7 @@ TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture); TEXTURE2D_SAMPLER2D(_CameraMotionVectorsTexture, sampler_CameraMotionVectorsTexture); TEXTURE2D_SAMPLER2D(_CoCTex, sampler_CoCTex); +TEXTURE2D_SAMPLER2D(_MaxCoCTex, sampler_MaxCoCTex); TEXTURE2D_SAMPLER2D(_DepthOfFieldTex, sampler_DepthOfFieldTex); float4 _DepthOfFieldTex_TexelSize; @@ -19,9 +20,16 @@ float4 _DepthOfFieldTex_TexelSize; // Camera parameters float _Distance; float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2) +half4 _CoCKernelLimits; +// MaxCoC texture is padded with a bit of empty space for alignment reasons (right&bottom sides) so we need some uv scale to sample it +float4 _MaxCoCTexScale; +half3 _KernelScale; +half2 _MarginFactors; float _MaxCoC; float _RcpMaxCoC; float _RcpAspect; +float _FgAlphaFactor; // 1 / sampleCount of either the first and/or second ring +int _MaxRingIndex; half3 _TaaParams; // Jitter.x, Jitter.y, Blending // CoC calculation @@ -147,52 +155,304 @@ half4 FragPrefilter(VaryingsDefault i) : SV_Target return half4(avg, coc); } -// Bokeh filter with disk-shaped kernels -half4 FragBlur(VaryingsDefault i) : SV_Target +VaryingsDefault VertDownsampleMaxCoC(AttributesDefault v) +{ + VaryingsDefault o; + o.vertex = float4(v.vertex.xy, 0.0, 1.0); + o.texcoord = TransformTriangleVertexToUV(v.vertex.xy); +#if defined(INITIAL_COC) + o.texcoord *= _MaxCoCTexScale.xy; +#endif + +#if UNITY_UV_STARTS_AT_TOP + o.texcoord = o.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0); +#endif + + o.texcoordStereo = TransformStereoScreenSpaceTex(o.texcoord, 1.0); + + return o; +} + +half4 FragDownsampleMaxCoC(VaryingsDefault i) : SV_Target +{ +#if UNITY_GATHER_SUPPORTED + // Sample source colors + half4 cocs = GATHER_RED_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo); +#else + // TODO implement gather version + + float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5); + float2 uv0 = UnityStereoTransformScreenSpaceTex(i.texcoord - duv.xy); + float2 uv1 = UnityStereoTransformScreenSpaceTex(i.texcoord - duv.zy); + float2 uv2 = UnityStereoTransformScreenSpaceTex(i.texcoord + duv.zy); + float2 uv3 = UnityStereoTransformScreenSpaceTex(i.texcoord + duv.xy); + + // Sample CoCs + half4 cocs; + cocs.x = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv0).r; + cocs.y = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv1).r; + cocs.z = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv2).r; + cocs.w = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv3).r; +#endif + +#if defined(INITIAL_COC) + // Storing the absolute normalized CoC is enough. + cocs = cocs * 2.0 - 1.0; +#endif + cocs = abs(cocs); + + half maxCoC = max(cocs.x, Max3(cocs.y, cocs.z, cocs.w)); + return half4(maxCoC, 0.0, 0.0, 0.0); +} + +half4 FragNeighborMaxCoC(VaryingsDefault i) : SV_Target +{ + float tx = _MainTex_TexelSize.x; + float ty = _MainTex_TexelSize.y; + +#if UNITY_GATHER_SUPPORTED + float2 uvA = UnityStereoTransformScreenSpaceTex(i.texcoord + _MainTex_TexelSize.xy * float2(-0.5, -0.5)); + float2 uvB = UnityStereoTransformScreenSpaceTex(i.texcoord + _MainTex_TexelSize.xy * float2( 0.5, -0.5)); + float2 uvC = UnityStereoTransformScreenSpaceTex(i.texcoord + _MainTex_TexelSize.xy * float2(-0.5, 0.5)); + float2 uvD = UnityStereoTransformScreenSpaceTex(i.texcoord + _MainTex_TexelSize.xy * float2( 0.5, 0.5)); + + half4 cocsA = GATHER_RED_TEXTURE2D(_MainTex, sampler_MainTex, uvA); + half4 cocsB = GATHER_RED_TEXTURE2D(_MainTex, sampler_MainTex, uvB); + half4 cocsC = GATHER_RED_TEXTURE2D(_MainTex, sampler_MainTex, uvC); + half4 cocsD = GATHER_RED_TEXTURE2D(_MainTex, sampler_MainTex, uvD); + half coc0 = cocsA.x; + half coc1 = cocsA.y; + half coc2 = cocsB.x; + half coc3 = cocsA.z; + half coc4 = cocsA.w; + half coc5 = cocsB.z; + half coc6 = cocsC.x; + half coc7 = cocsC.y; + half coc8 = cocsD.w; +#else + float2 uv0 = UnityStereoTransformScreenSpaceTex(i.texcoord); + float2 uv1 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2( tx, 0)); + float2 uv2 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2( tx, ty)); + float2 uv3 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2( 0, ty)); + float2 uv4 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2(-tx, ty)); + float2 uv5 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2(-tx, 0)); + float2 uv6 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2(-tx,-ty)); + float2 uv7 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2( 0,-ty)); + float2 uv8 = UnityStereoTransformScreenSpaceTex(i.texcoord + float2( tx,-ty)); + + half coc0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv0).r; + half coc1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv1).r; + half coc2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv2).r; + half coc3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv3).r; + half coc4 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv4).r; + half coc5 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv5).r; + half coc6 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv6).r; + half coc7 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv7).r; + half coc8 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv8).r; +#endif + + half maxCoC = Max3(Max3(coc0, coc1, coc2), Max3(coc3, coc4, coc5), Max3(coc6, coc7, coc8)); + return half4(maxCoC, 0.0, 0.0, 0.0); +} + +void AccumSample(int si, half4 samp0, float2 texcoord, inout half4 bgAcc, inout half4 fgAcc) +{ +#if defined(KERNEL_SMALL) + half2 disp = kSmallDiskKernel[si].xy * _KernelScale.xy; + half dist = kSmallDiskKernel[si].z * _KernelScale.z; +#else + half2 disp = kDiskAllKernels[si].xy * _KernelScale.xy; + half dist = kDiskAllKernels[si].z * _KernelScale.z; +#endif + half2 duv = disp; + + half4 samp = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(texcoord + duv)); + + // BG: Compare CoC of the current sample and the center sample + // and select smaller one. + half bgCoC = max(min(samp0.a, samp.a), 0.0); + + // Compare the CoC to the sample distance. + // Add a small margin to smooth out. + half bgWeight = saturate((bgCoC - dist + _MarginFactors.x) * _MarginFactors.y); + half fgWeight = saturate((-samp.a - dist + _MarginFactors.x) * _MarginFactors.y); + + // Cut influence from focused areas because they're darkened by CoC + // premultiplying. This is only needed for near field. + fgWeight *= step(_MainTex_TexelSize.y, -samp.a); + + // Accumulation + bgAcc += half4(samp.rgb, 1.0) * bgWeight; + fgAcc += half4(samp.rgb, 1.0) * fgWeight; +} + +half4 FragBlurSmallBokeh (VaryingsDefault i) : SV_Target { half4 samp0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo); half4 bgAcc = 0.0; // Background: far field bokeh half4 fgAcc = 0.0; // Foreground: near field bokeh - UNITY_LOOP - for (int si = 0; si < kSampleCount; si++) - { - float2 disp = kDiskKernel[si] * _MaxCoC; - float dist = length(disp); + AccumSample(0, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(1, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(2, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(3, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(4, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(5, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(6, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(7, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(8, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(9, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(10, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(11, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(12, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(13, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(14, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(15, samp0, i.texcoord, bgAcc, fgAcc); + + // Get the weighted average. + bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard + fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0); - float2 duv = float2(disp.x * _RcpAspect, disp.y); - half4 samp = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + duv)); + // FG: Normalize the total of the weights. + fgAcc.a *= PI / kSmallSampleCount; + + // Alpha premultiplying + half alpha = saturate(fgAcc.a); + half3 rgb = lerp(bgAcc.rgb, fgAcc.rgb, alpha); - // BG: Compare CoC of the current sample and the center sample - // and select smaller one. - half bgCoC = max(min(samp0.a, samp.a), 0.0); + return half4(rgb, alpha); +} - // Compare the CoC to the sample distance. - // Add a small margin to smooth out. - const half margin = _MainTex_TexelSize.y * 2; - half bgWeight = saturate((bgCoC - dist + margin) / margin); - half fgWeight = saturate((-samp.a - dist + margin) / margin); +// Bokeh filter with disk-shaped kernels +half4 FragBlurDynamic(VaryingsDefault i) : SV_Target +{ + half4 samp0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo); + // normalized value in range [0, 1] + half maxCoC = SAMPLE_TEXTURE2D(_MaxCoCTex, sampler_MaxCoCTex, i.texcoordStereo * _MaxCoCTexScale.zw).r; - // Cut influence from focused areas because they're darkened by CoC - // premultiplying. This is only needed for near field. - fgWeight *= step(_MainTex_TexelSize.y, -samp.a); + int kernelRingIndex; - // Accumulation - bgAcc += half4(samp.rgb, 1.0) * bgWeight; - fgAcc += half4(samp.rgb, 1.0) * fgWeight; + // margin adjustment +1 in the shader code artifically expand bokeh by 4px in fullscreen units (1 extra ring), we cannot have small bokeh as a result! + if (maxCoC < _CoCKernelLimits[0]) + kernelRingIndex = 0; + else if (maxCoC < _CoCKernelLimits[1]) + kernelRingIndex = 1 + 1; + else if (maxCoC < _CoCKernelLimits[2]) + kernelRingIndex = 2 + 1; + else if (maxCoC < _CoCKernelLimits[3]) + kernelRingIndex = 3 + 1; + else + kernelRingIndex = 4; + + kernelRingIndex = min(_MaxRingIndex, kernelRingIndex); + + int sampleCount = kDiskAllKernelSizes[kernelRingIndex]; + half sampleCountRcp = kDiskAllKernelRcpSizes[kernelRingIndex]; + + half4 bgAcc = 0.0; // Background: far field bokeh + half4 fgAcc = 0.0; // Foreground: near field bokeh + + AccumSample(0, samp0, i.texcoord, bgAcc, fgAcc); + + UNITY_BRANCH if (kernelRingIndex >= 1) + { + AccumSample(1, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(2, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(3, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(4, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(5, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(6, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(7, samp0, i.texcoord, bgAcc, fgAcc); + } + + UNITY_BRANCH if (kernelRingIndex >= 2) + { + AccumSample(8, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(9, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(10, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(11, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(12, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(13, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(14, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(15, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(16, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(17, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(18, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(19, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(20, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(21, samp0, i.texcoord, bgAcc, fgAcc); + } + + UNITY_BRANCH if (kernelRingIndex >= 3) + { + AccumSample(22, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(23, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(24, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(25, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(26, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(27, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(28, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(29, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(30, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(31, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(32, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(33, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(34, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(35, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(36, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(37, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(38, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(39, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(40, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(41, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(42, samp0, i.texcoord, bgAcc, fgAcc); + } + + UNITY_BRANCH if (kernelRingIndex >= 4) + { + AccumSample(43, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(44, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(45, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(46, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(47, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(48, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(49, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(50, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(51, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(52, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(53, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(54, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(55, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(56, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(57, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(58, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(59, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(60, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(61, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(62, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(63, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(64, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(65, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(66, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(67, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(68, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(69, samp0, i.texcoord, bgAcc, fgAcc); + AccumSample(70, samp0, i.texcoord, bgAcc, fgAcc); } // Get the weighted average. bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0); - // BG: Calculate the alpha value only based on the center CoC. - // This is a rather aggressive approximation but provides stable results. - bgAcc.a = smoothstep(_MainTex_TexelSize.y, _MainTex_TexelSize.y * 2.0, samp0.a); - - // FG: Normalize the total of the weights. - fgAcc.a *= PI / kSampleCount; + // FG: fgAcc roughly represents the number of samples in the foreground which bleed into the pixel being processed. + // We can use this value to gradually blend-in the DoF texture into the original source image. We use the number + // of samples on the first or second ring as threshold to full-blend the DoF texture (when other outer rings are sampled, + // we are already at full-blend). + // The choice of first or second ring is arbitrary and decided to closely reproduce the original algorithm result. + // The original algorithm produces unnatural (physically inaccurate) blending that varies with "MaxBlurSize" parameter, + // so there is no good fix for it. + fgAcc.a *= max(sampleCountRcp, _FgAlphaFactor); // Alpha premultiplying half alpha = saturate(fgAcc.a); diff --git a/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.shader b/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.shader index 69c363f6540..57ec927631f 100644 --- a/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.shader +++ b/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.shader @@ -33,69 +33,79 @@ Shader "Hidden/PostProcessing/DepthOfField" Pass // 2 { - Name "Downsample and Prefilter" + Name "Downsample initial MaxCoC" HLSLPROGRAM #pragma target 5.0 #pragma vertex VertDefault - #pragma fragment FragPrefilter + #pragma fragment FragDownsampleMaxCoC + #define INITIAL_COC #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 3 { - Name "Bokeh Filter (small)" + Name "Downsample MaxCoC" HLSLPROGRAM - #pragma target 3.5 - #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_SMALL + #pragma target 5.0 + #pragma vertex VertDownsampleMaxCoC + #pragma fragment FragDownsampleMaxCoC #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 4 { - Name "Bokeh Filter (medium)" + Name "Neighbor MaxCoC" HLSLPROGRAM - #pragma target 3.5 + #pragma target 5.0 #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_MEDIUM + #pragma fragment FragNeighborMaxCoC #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 5 { - Name "Bokeh Filter (large)" + Name "Downsample and Prefilter" HLSLPROGRAM - #pragma target 3.5 + #pragma target 5.0 #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_LARGE + #pragma fragment FragPrefilter #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 6 { - Name "Bokeh Filter (very large)" + Name "Bokeh Filter (small)" HLSLPROGRAM #pragma target 3.5 #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_VERYLARGE + #pragma fragment FragBlurSmallBokeh + #define KERNEL_SMALL #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 7 + { + Name "Bokeh Filter (dynamic)" + + HLSLPROGRAM + #pragma target 3.5 + #pragma vertex VertDefault + #pragma fragment FragBlurDynamic + #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" + ENDHLSL + } + + Pass // 8 { Name "Postfilter" @@ -107,7 +117,7 @@ Shader "Hidden/PostProcessing/DepthOfField" ENDHLSL } - Pass // 8 + Pass // 9 { Name "Combine" @@ -119,7 +129,7 @@ Shader "Hidden/PostProcessing/DepthOfField" ENDHLSL } - Pass // 9 + Pass // 10 { Name "Debug Overlay" @@ -164,69 +174,79 @@ Shader "Hidden/PostProcessing/DepthOfField" Pass // 2 { - Name "Downsample and Prefilter" + Name "Downsample initial MaxCoC" HLSLPROGRAM #pragma target 3.5 #pragma vertex VertDefault - #pragma fragment FragPrefilter + #pragma fragment FragDownsampleMaxCoC + #define INITIAL_COC #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 3 { - Name "Bokeh Filter (small)" + Name "Downsample MaxCoC" HLSLPROGRAM #pragma target 3.5 - #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_SMALL + #pragma vertex VertDownsampleMaxCoC + #pragma fragment FragDownsampleMaxCoC #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 4 { - Name "Bokeh Filter (medium)" + Name "Neighbor MaxCoC" HLSLPROGRAM #pragma target 3.5 #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_MEDIUM + #pragma fragment FragNeighborMaxCoC #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 5 { - Name "Bokeh Filter (large)" + Name "Downsample and Prefilter" HLSLPROGRAM #pragma target 3.5 #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_LARGE + #pragma fragment FragPrefilter #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 6 { - Name "Bokeh Filter (very large)" + Name "Bokeh Filter (small)" HLSLPROGRAM #pragma target 3.5 #pragma vertex VertDefault - #pragma fragment FragBlur - #define KERNEL_VERYLARGE + #pragma fragment FragBlurSmallBokeh + #define KERNEL_SMALL #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" ENDHLSL } Pass // 7 + { + Name "Bokeh Filter (dynamic)" + + HLSLPROGRAM + #pragma target 3.5 + #pragma vertex VertDefault + #pragma fragment FragBlurDynamic + #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DepthOfField.hlsl" + ENDHLSL + } + + Pass // 8 { Name "Postfilter" @@ -238,7 +258,7 @@ Shader "Hidden/PostProcessing/DepthOfField" ENDHLSL } - Pass // 8 + Pass // 9 { Name "Combine" @@ -250,7 +270,7 @@ Shader "Hidden/PostProcessing/DepthOfField" ENDHLSL } - Pass // 9 + Pass // 10 { Name "Debug Overlay" diff --git a/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DiskKernels.hlsl b/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DiskKernels.hlsl index b817ce852ed..32b1e24d1db 100644 --- a/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DiskKernels.hlsl +++ b/com.unity.postprocessing/PostProcessing/Shaders/Builtins/DiskKernels.hlsl @@ -1,204 +1,115 @@ #ifndef UNITY_POSTFX_DISK_KERNELS #define UNITY_POSTFX_DISK_KERNELS -#if !defined(KERNEL_SMALL) && !defined(KERNEL_MEDIUM) && \ - !defined(KERNEL_LARGE) && !defined(KERNEL_VERYLARGE) - -static const int kSampleCount = 1; -static const float2 kDiskKernel[1] = { float2(0, 0) }; - -#endif - -#if defined(KERNEL_SMALL) - // rings = 2 -// points per ring = 5 -static const int kSampleCount = 16; -static const float2 kDiskKernel[kSampleCount] = { - float2(0,0), - float2(0.54545456,0), - float2(0.16855472,0.5187581), - float2(-0.44128203,0.3206101), - float2(-0.44128197,-0.3206102), - float2(0.1685548,-0.5187581), - float2(1,0), - float2(0.809017,0.58778524), - float2(0.30901697,0.95105654), - float2(-0.30901703,0.9510565), - float2(-0.80901706,0.5877852), - float2(-1,0), - float2(-0.80901694,-0.58778536), - float2(-0.30901664,-0.9510566), - float2(0.30901712,-0.9510565), - float2(0.80901694,-0.5877853), -}; - -#endif - -#if defined(KERNEL_MEDIUM) - -// rings = 3 -// points per ring = 7 -static const int kSampleCount = 22; -static const float2 kDiskKernel[kSampleCount] = { - float2(0,0), - float2(0.53333336,0), - float2(0.3325279,0.4169768), - float2(-0.11867785,0.5199616), - float2(-0.48051673,0.2314047), - float2(-0.48051673,-0.23140468), - float2(-0.11867763,-0.51996166), - float2(0.33252785,-0.4169769), - float2(1,0), - float2(0.90096885,0.43388376), - float2(0.6234898,0.7818315), - float2(0.22252098,0.9749279), - float2(-0.22252095,0.9749279), - float2(-0.62349,0.7818314), - float2(-0.90096885,0.43388382), - float2(-1,0), - float2(-0.90096885,-0.43388376), - float2(-0.6234896,-0.7818316), - float2(-0.22252055,-0.974928), - float2(0.2225215,-0.9749278), - float2(0.6234897,-0.7818316), - float2(0.90096885,-0.43388376), +// points per ring = 5 (+5 per ring) +// 1st ring spacing: 8/15 +// 2nd ring spacing: 15/15 +static const int kSmallSampleCount = 16; +static const half3 kSmallDiskKernel[kSmallSampleCount] = { + half3(0,0,0), + half3(0.54545456,0,0.5454546), + half3(0.16855472,0.5187581,0.5454546), + half3(-0.44128203,0.3206101,0.5454546), + half3(-0.44128197,-0.3206102,0.5454546), + half3(0.1685548,-0.5187581,0.5454546), + half3(1,0,1), + half3(0.809017,0.58778524,1), + half3(0.30901697,0.95105654,1), + half3(-0.30901703,0.9510565,1), + half3(-0.80901706,0.5877852,1), + half3(-1,0,1), + half3(-0.80901694,-0.58778536,1), + half3(-0.30901664,-0.9510566,1), + half3(0.30901712,-0.9510565,1), + half3(0.80901694,-0.5877853,1), }; -#endif - -#if defined(KERNEL_LARGE) - // rings = 4 -// points per ring = 7 -static const int kSampleCount = 43; -static const float2 kDiskKernel[kSampleCount] = { - float2(0,0), - float2(0.36363637,0), - float2(0.22672357,0.28430238), - float2(-0.08091671,0.35451925), - float2(-0.32762504,0.15777594), - float2(-0.32762504,-0.15777591), - float2(-0.08091656,-0.35451928), - float2(0.22672352,-0.2843024), - float2(0.6818182,0), - float2(0.614297,0.29582983), - float2(0.42510667,0.5330669), - float2(0.15171885,0.6647236), - float2(-0.15171883,0.6647236), - float2(-0.4251068,0.53306687), - float2(-0.614297,0.29582986), - float2(-0.6818182,0), - float2(-0.614297,-0.29582983), - float2(-0.42510656,-0.53306705), - float2(-0.15171856,-0.66472363), - float2(0.1517192,-0.6647235), - float2(0.4251066,-0.53306705), - float2(0.614297,-0.29582983), - float2(1,0), - float2(0.9555728,0.2947552), - float2(0.82623875,0.5633201), - float2(0.6234898,0.7818315), - float2(0.36534098,0.93087375), - float2(0.07473,0.9972038), - float2(-0.22252095,0.9749279), - float2(-0.50000006,0.8660254), - float2(-0.73305196,0.6801727), - float2(-0.90096885,0.43388382), - float2(-0.98883086,0.14904208), - float2(-0.9888308,-0.14904249), - float2(-0.90096885,-0.43388376), - float2(-0.73305184,-0.6801728), - float2(-0.4999999,-0.86602545), - float2(-0.222521,-0.9749279), - float2(0.07473029,-0.99720377), - float2(0.36534148,-0.9308736), - float2(0.6234897,-0.7818316), - float2(0.8262388,-0.56332), - float2(0.9555729,-0.29475483), +// points per ring = 7 (+7 per ring) +// 1st ring spacing : 8/29 +// 2nd ring spacing : 15/29 +// 3rd ring spacing : 22/29 +// 4th ring spacing : 29/29 +static const int kDiskAllKernelSizes[5] = { 1, 8, 22, 43, 71 }; +static const half kDiskAllKernelRcpSizes[5] = { 1, 1.0/8, 1.0/22, 1.0/43, 1.0/71 }; +static const half3 kDiskAllKernels[71] = { + half3(0, 0, 0), + // ring 1 index=1 + half3(0.275862068965517, 0, 0.275862068965517), + half3(0.171997186719651, 0.215677650336008, 0.275862068965517), + half3(-0.0613850852293281, 0.26894563094671, 0.275862068965517), + half3(-0.248543135973081, 0.119692065963464, 0.275862068965517), + half3(-0.248543135973081, -0.119692065963464, 0.275862068965517), + half3(-0.0613850852293282, -0.26894563094671, 0.275862068965517), + half3(0.171997186719651, -0.215677650336008, 0.275862068965517), + // ring 2 index=8 + half3(0.517241379310345, 0, 0.517241379310345), + half3(0.466018379949527, 0.224422623681496, 0.517241379310345), + half3(0.322494725099345, 0.404395594380015, 0.517241379310345), + half3(0.11509703480499, 0.504273058025081, 0.517241379310345), + half3(-0.11509703480499, 0.504273058025081, 0.517241379310345), + half3(-0.322494725099345, 0.404395594380015, 0.517241379310345), + half3(-0.466018379949527, 0.224422623681496, 0.517241379310345), + half3(-0.517241379310345, 6.33437999558976E-17, 0.517241379310345), + half3(-0.466018379949527, -0.224422623681496, 0.517241379310345), + half3(-0.322494725099345, -0.404395594380015, 0.517241379310345), + half3(-0.11509703480499, -0.504273058025081, 0.517241379310345), + half3(0.11509703480499, -0.504273058025081, 0.517241379310345), + half3(0.322494725099345, -0.404395594380015, 0.517241379310345), + half3(0.466018379949527, -0.224422623681495, 0.517241379310345), + // ring 3 index=22 + half3(0.758620689655172, 0, 0.758620689655172), + half3(0.72491730094121, 0.223607373691031, 0.758620689655172), + half3(0.626801828791444, 0.427346250944817, 0.758620689655172), + half3(0.472992263479039, 0.593113538424023, 0.758620689655172), + half3(0.277155259864162, 0.706180085178362, 0.758620689655172), + half3(0.0566917951345288, 0.756499432344343, 0.758620689655172), + half3(-0.168808984380652, 0.739600485103452, 0.758620689655172), + half3(-0.379310344827586, 0.65698478907785, 0.758620689655172), + half3(-0.556108316560558, 0.515993111412422, 0.758620689655172), + half3(-0.683493623925973, 0.329153181399527, 0.758620689655172), + half3(-0.750147523343201, 0.113066546754339, 0.758620689655172), + half3(-0.750147523343201, -0.113066546754339, 0.758620689655172), + half3(-0.683493623925973, -0.329153181399527, 0.758620689655172), + half3(-0.556108316560558, -0.515993111412422, 0.758620689655172), + half3(-0.379310344827587, -0.65698478907785, 0.758620689655172), + half3(-0.168808984380652, -0.739600485103452, 0.758620689655172), + half3(0.0566917951345288, -0.756499432344343, 0.758620689655172), + half3(0.277155259864162, -0.706180085178362, 0.758620689655172), + half3(0.472992263479039, -0.593113538424023, 0.758620689655172), + half3(0.626801828791444, -0.427346250944817, 0.758620689655172), + half3(0.72491730094121, -0.223607373691031, 0.758620689655172), + // ring 4 index=43 + half3(1, 0, 1), + half3(0.974927912181824, 0.222520933956314, 1), + half3(0.900968867902419, 0.433883739117558, 1), + half3(0.78183148246803, 0.623489801858733, 1), + half3(0.623489801858734, 0.78183148246803, 1), + half3(0.433883739117558, 0.900968867902419, 1), + half3(0.222520933956314, 0.974927912181824, 1), + half3(6.12323399573677E-17, 1, 1), + half3(-0.222520933956314, 0.974927912181824, 1), + half3(-0.433883739117558, 0.900968867902419, 1), + half3(-0.623489801858733, 0.78183148246803, 1), + half3(-0.781831482468029, 0.623489801858734, 1), + half3(-0.900968867902419, 0.433883739117558, 1), + half3(-0.974927912181824, 0.222520933956314, 1), + half3(-1, 1.22464679914735E-16, 1), + half3(-0.974927912181824, -0.222520933956314, 1), + half3(-0.900968867902419, -0.433883739117558, 1), + half3(-0.78183148246803, -0.623489801858734, 1), + half3(-0.623489801858734, -0.78183148246803, 1), + half3(-0.433883739117558, -0.900968867902419, 1), + half3(-0.222520933956315, -0.974927912181824, 1), + half3(-1.83697019872103E-16, -1, 1), + half3(0.222520933956313, -0.974927912181824, 1), + half3(0.433883739117558, -0.900968867902419, 1), + half3(0.623489801858733, -0.78183148246803, 1), + half3(0.78183148246803, -0.623489801858734, 1), + half3(0.900968867902419, -0.433883739117558, 1), + half3(0.974927912181824, -0.222520933956315, 1), + // totalSampleCount=71 }; -#endif - -#if defined(KERNEL_VERYLARGE) - -// rings = 5 -// points per ring = 7 -static const int kSampleCount = 71; -static const float2 kDiskKernel[kSampleCount] = { - float2(0,0), - float2(0.2758621,0), - float2(0.1719972,0.21567768), - float2(-0.061385095,0.26894566), - float2(-0.24854316,0.1196921), - float2(-0.24854316,-0.11969208), - float2(-0.061384983,-0.2689457), - float2(0.17199717,-0.21567771), - float2(0.51724136,0), - float2(0.46601835,0.22442262), - float2(0.32249472,0.40439558), - float2(0.11509705,0.50427306), - float2(-0.11509704,0.50427306), - float2(-0.3224948,0.40439552), - float2(-0.46601835,0.22442265), - float2(-0.51724136,0), - float2(-0.46601835,-0.22442262), - float2(-0.32249463,-0.40439564), - float2(-0.11509683,-0.5042731), - float2(0.11509732,-0.504273), - float2(0.32249466,-0.40439564), - float2(0.46601835,-0.22442262), - float2(0.7586207,0), - float2(0.7249173,0.22360738), - float2(0.6268018,0.4273463), - float2(0.47299224,0.59311354), - float2(0.27715522,0.7061801), - float2(0.056691725,0.75649947), - float2(-0.168809,0.7396005), - float2(-0.3793104,0.65698475), - float2(-0.55610836,0.51599306), - float2(-0.6834936,0.32915324), - float2(-0.7501475,0.113066405), - float2(-0.7501475,-0.11306671), - float2(-0.6834936,-0.32915318), - float2(-0.5561083,-0.5159932), - float2(-0.37931028,-0.6569848), - float2(-0.16880904,-0.7396005), - float2(0.056691945,-0.7564994), - float2(0.2771556,-0.7061799), - float2(0.47299215,-0.59311366), - float2(0.62680185,-0.4273462), - float2(0.72491735,-0.22360711), - float2(1,0), - float2(0.9749279,0.22252093), - float2(0.90096885,0.43388376), - float2(0.7818315,0.6234898), - float2(0.6234898,0.7818315), - float2(0.43388364,0.9009689), - float2(0.22252098,0.9749279), - float2(0,1), - float2(-0.22252095,0.9749279), - float2(-0.43388385,0.90096885), - float2(-0.62349,0.7818314), - float2(-0.7818317,0.62348956), - float2(-0.90096885,0.43388382), - float2(-0.9749279,0.22252093), - float2(-1,0), - float2(-0.9749279,-0.22252087), - float2(-0.90096885,-0.43388376), - float2(-0.7818314,-0.6234899), - float2(-0.6234896,-0.7818316), - float2(-0.43388346,-0.900969), - float2(-0.22252055,-0.974928), - float2(0,-1), - float2(0.2225215,-0.9749278), - float2(0.4338835,-0.90096897), - float2(0.6234897,-0.7818316), - float2(0.78183144,-0.62348986), - float2(0.90096885,-0.43388376), - float2(0.9749279,-0.22252086), -}; - -#endif - #endif // UNITY_POSTFX_DISK_KERNELS