Shader "Hidden/DepthOfField/DepthOfField" { Properties { _MainTex ("-", 2D) = "black" _SecondTex ("-", 2D) = "black" _ThirdTex ("-", 2D) = "black" } CGINCLUDE #pragma target 3.0 #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" //undef USE_LOCAL_TONEMAPPING if you dont want to use local tonemapping. //tweaking these values down will trade stability for less bokeh (see Tonemap/ToneMapInvert methods below). #ifndef SHADER_API_MOBILE #define USE_LOCAL_TONEMAPPING #endif #define LOCAL_TONEMAP_START_LUMA 1.0 #define LOCAL_TONEMAP_RANGE_LUMA 5.0 sampler2D _SecondTex; sampler2D _ThirdTex; uniform half4 _MainTex_TexelSize; uniform half4 _BlurCoe; uniform half4 _BlurParams; uniform half4 _BoostParams; uniform half4 _Convolved_TexelSize; uniform float4 _Offsets; uniform half4 _MainTex_ST; uniform half4 _SecondTex_ST; uniform half4 _ThirdTex_ST; #if (SHADER_TARGET >= 50 && !defined(SHADER_API_PSSL)) #define USE_TEX2DOBJECT_FOR_COC #endif #if defined(USE_TEX2DOBJECT_FOR_COC) Texture2D _CameraDepthTexture; SamplerState sampler_CameraDepthTexture; Texture2D _MainTex; SamplerState sampler_MainTex; #else sampler2D _MainTex; sampler2D _CameraDepthTexture; #endif /////////////////////////////////////////////////////////////////////////////// // Verter Shaders and declaration /////////////////////////////////////////////////////////////////////////////// struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct v2fDepth { half4 pos : SV_POSITION; half2 uv : TEXCOORD0; }; struct v2fBlur { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 uv01 : TEXCOORD1; float4 uv23 : TEXCOORD2; float4 uv45 : TEXCOORD3; float4 uv67 : TEXCOORD4; float4 uv89 : TEXCOORD5; }; v2fDepth vert(appdata_img v) { v2fDepth o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1-o.uv.y; #endif return o; } v2fDepth vertNoFlip(appdata_img v) { v2fDepth o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; return o; } v2f vert_d( appdata_img v ) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv1.xy = v.texcoord.xy; o.uv.xy = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1-o.uv.y; #endif return o; } v2f vertFlip( appdata_img v ) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv1.xy = v.texcoord.xy; o.uv.xy = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1-o.uv.y; if (_MainTex_TexelSize.y < 0) o.uv1.y = 1-o.uv1.y; #endif return o; } v2fBlur vertBlurPlusMinus (appdata_img v) { v2fBlur o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv.xy = v.texcoord.xy; o.uv01 = v.texcoord.xyxy + _Offsets.xyxy * float4(1,1, -1,-1) * _MainTex_TexelSize.xyxy / 6.0; o.uv23 = v.texcoord.xyxy + _Offsets.xyxy * float4(2,2, -2,-2) * _MainTex_TexelSize.xyxy / 6.0; o.uv45 = v.texcoord.xyxy + _Offsets.xyxy * float4(3,3, -3,-3) * _MainTex_TexelSize.xyxy / 6.0; o.uv67 = v.texcoord.xyxy + _Offsets.xyxy * float4(4,4, -4,-4) * _MainTex_TexelSize.xyxy / 6.0; o.uv89 = v.texcoord.xyxy + _Offsets.xyxy * float4(5,5, -5,-5) * _MainTex_TexelSize.xyxy / 6.0; return o; } /////////////////////////////////////////////////////////////////////////////// // Helpers /////////////////////////////////////////////////////////////////////////////// inline half4 FetchMainTex(float2 uv) { #if defined(USE_TEX2DOBJECT_FOR_COC) return _MainTex.SampleLevel(sampler_MainTex, uv, 0); #else return tex2Dlod (_MainTex, float4(uv,0,0)); #endif } inline half2 GetBilinearFetchTexOffsetFromAbsCoc(half4 absCoc) { half4 cocWeights = absCoc * absCoc * absCoc; half2 offset = 0; offset += cocWeights.r * float2(-1,+1); offset += cocWeights.g * float2(+1,+1); offset += cocWeights.b * float2(+1,-1); offset += cocWeights.a * float2(-1,-1); offset = clamp((half2)-1,(half2)1, offset); offset *= 0.5; return offset; } inline half4 FetchColorAndCocFromMainTex(float2 uv, float2 offsetFromKernelCenter) { //bilinear half4 fetch = FetchMainTex(uv); //coc can't be linearly interpolated while doing "scatter and gather" or we will have haloing where coc vary sharply. #if defined(USE_SPECIAL_FETCH_FOR_COC) #if defined(USE_TEX2DOBJECT_FOR_COC) half4 allCoc = _MainTex.GatherAlpha(sampler_MainTex, uv); half cocAB = (abs(allCoc.r) instead point sample the coc from the fartest away texel (not as good). half2 bilinearCenter = floor(uv * _MainTex_TexelSize.zw - 0.5) + 1.0; half2 cocUV = bilinearCenter + 0.5 * sign(offsetFromKernelCenter); half coc = tex2Dlod (_MainTex, float4( cocUV * _MainTex_TexelSize.xy,0,0)).a; #endif fetch.a = coc; #endif return fetch; } inline half3 getBoostAmount(half4 colorAndCoc) { half boost = colorAndCoc.a * (colorAndCoc.a < 0.0f ?_BoostParams.x:_BoostParams.y); half luma = dot(colorAndCoc.rgb, half3(0.3h, 0.59h, 0.11h)); return luma < _BoostParams.z ? half3(0.0h, 0.0h, 0.0h):colorAndCoc.rgb * boost.rrr; } inline half GetCocFromZValue(half d, bool useExplicit) { d = Linear01Depth (d); if (useExplicit) { half coc = d < _BlurCoe.z ? clamp((_BlurParams.x * d + _BlurParams.y), -1.0f, 0.0f):clamp((_BlurParams.z * d + _BlurParams.w), 0.0f, 1.0f); return coc; } else { half aperture = _BlurParams.x; half focalLength = _BlurParams.y; half focusDistance01 = _BlurParams.z; half focusRange01 = _BlurParams.w; half coc = aperture * abs(d - focusDistance01) / (d + 1e-5f) - focusRange01; coc = (d < focusDistance01 ? -1.0h:1.0h) * clamp(coc, 0.0f, 1.0f); return coc; } } inline half GetCocFromDepth(half2 uv, bool useExplicit) { #if defined(USE_TEX2DOBJECT_FOR_COC) half d = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, uv, 0); #else half d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); #endif return GetCocFromZValue(d,useExplicit); } #if (SHADER_TARGET < 50 && !defined(SHADER_API_PSSL)) half rcp(half x) { return 1 / x; } #endif //from http://graphicrants.blogspot.dk/2013/12/tone-mapping.html inline half3 Tonemap(half3 color) { #ifdef USE_LOCAL_TONEMAPPING half a = LOCAL_TONEMAP_START_LUMA; half b = LOCAL_TONEMAP_RANGE_LUMA; half luma = max(color.r, max(color.g, color.b)); if (luma <= a) return color; return color * rcp(luma) * (a*a - b * luma) / (2*a - b - luma); #else return color; #endif } inline half3 ToneMapInvert(half3 color) { #ifdef USE_LOCAL_TONEMAPPING half a = LOCAL_TONEMAP_START_LUMA; half b = LOCAL_TONEMAP_RANGE_LUMA; half luma = max(color.r, max(color.g, color.b)); if (luma <= a) return color; return color * rcp(luma) * (a*a - (2*a - b) * luma) / (b - luma); #else return color; #endif } /////////////////////////////////////////////////////////////////////////////// // Directional (hexagonal/octogonal) bokeh /////////////////////////////////////////////////////////////////////////////// #define SAMPLE_NUM_L 6 #define SAMPLE_NUM_M 11 #define SAMPLE_NUM_H 16 inline half4 shapeDirectionalBlur(half2 uv, bool mergePass, int numSample, bool sampleDilatedFG) { half4 centerTap = FetchMainTex(uv); half fgCoc = centerTap.a; half fgBlendFromPreviousPass = centerTap.a * _Offsets.z; if (sampleDilatedFG) { half2 cocs = tex2Dlod(_SecondTex, half4(uv,0,0)).rg; fgCoc = min(cocs.r, cocs.g); centerTap.a = cocs.g; } half bgRadius = smoothstep(0.0h, 0.85h, centerTap.a) * _BlurCoe.y; half fgRadius = smoothstep(0.0h, 0.85h, -fgCoc) * _BlurCoe.x; half radius = max(bgRadius, fgRadius); if (radius < 1e-2f ) { return half4(centerTap.rgb, (sampleDilatedFG||mergePass)?fgBlendFromPreviousPass:centerTap.a); } half radOtherFgRad = radius/(fgRadius + 1e-2h); half radOtherBgRad = radius/(bgRadius + 1e-2h); half2 range = radius * _MainTex_TexelSize.xy; half fgWeight = 0.001h; half bgWeight = 0.001h; half3 fgSum = half3(0,0,0); half3 bgSum = half3(0,0,0); for (int k = 0; k < numSample; k++) { half t = (half)k / half(numSample-1); half2 kVal = lerp(_Offsets.xy, -_Offsets.xy, t); half2 offset = kVal * range; half2 texCoord = uv + offset; half4 sample0 = FetchColorAndCocFromMainTex(texCoord, offset); if (sampleDilatedFG) { sample0.a = tex2Dlod(_SecondTex, half4(texCoord,0,0)).g; } half dist = abs(2.0h * t - 1); half distanceFactor = saturate(-0.5f * abs(sample0.a - centerTap.a) * dist + 1.0f); half isNear = max(0.0h, -sample0.a); half isFar = max(0.0h, sample0.a) * distanceFactor; isNear *= 1- smoothstep(1.0h, 2.0h, dist * radOtherFgRad); isFar *= 1- smoothstep(1.0h, 2.0h, dist * radOtherBgRad); fgWeight += isNear; fgSum += sample0.rgb * isNear; bgWeight += isFar; bgSum += sample0.rgb * isFar; } half3 fgColor = fgSum / (fgWeight + 0.0001h); half3 bgColor = bgSum / (bgWeight + 0.0001h); half bgBlend = saturate (2.0h * bgWeight / numSample); half fgBlend = saturate (2.0h * fgWeight / numSample); half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); half3 finalColor = lerp(finalBg, fgColor, max(max(0.0h , -centerTap.a) , fgBlend)); if (mergePass) { finalColor = min(finalColor, tex2Dlod(_ThirdTex, half4(uv,0,0)).rgb); } finalColor = lerp(centerTap.rgb, finalColor, saturate(bgBlend+fgBlend)); fgBlend = max(fgBlendFromPreviousPass, fgBlend); return half4(finalColor, (sampleDilatedFG||mergePass)?fgBlend:centerTap.a); } half4 fragShapeLowQuality(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, false); } half4 fragShapeLowQualityDilateFg(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, true); } half4 fragShapeLowQualityMerge(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, false); } half4 fragShapeLowQualityMergeDilateFg(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, true); } half4 fragShapeMediumQuality(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, false); } half4 fragShapeMediumQualityDilateFg(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, true); } half4 fragShapeMediumQualityMerge(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, false); } half4 fragShapeMediumQualityMergeDilateFg(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, true); } half4 fragShapeHighQuality(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, false); } half4 fragShapeHighQualityDilateFg(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, true); } half4 fragShapeHighQualityMerge(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, false); } half4 fragShapeHighQualityMergeDilateFg(v2fDepth i) : SV_Target { return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, true); } /////////////////////////////////////////////////////////////////////////////// // Disk Bokeh /////////////////////////////////////////////////////////////////////////////// static const half3 DiscBokeh48[48] = { //48 tap regularly spaced circular kernel (x,y, length) //fill free to change the shape to try other bokehs style :) half3( 0.99144h, 0.13053h, 1.0h), half3( 0.92388h, 0.38268h, 1.0h), half3( 0.79335h, 0.60876h, 1.0h), half3( 0.60876h, 0.79335h, 1.0h), half3( 0.38268h, 0.92388h, 1.0h), half3( 0.13053h, 0.99144h, 1.0h), half3(-0.13053h, 0.99144h, 1.0h), half3(-0.38268h, 0.92388h, 1.0h), half3(-0.60876h, 0.79335h, 1.0h), half3(-0.79335h, 0.60876h, 1.0h), half3(-0.92388h, 0.38268h, 1.0h), half3(-0.99144h, 0.13053h, 1.0h), half3(-0.99144h,-0.13053h, 1.0h), half3(-0.92388h,-0.38268h, 1.0h), half3(-0.79335h,-0.60876h, 1.0h), half3(-0.60876h,-0.79335h, 1.0h), half3(-0.38268h,-0.92388h, 1.0h), half3(-0.13053h,-0.99144h, 1.0h), half3( 0.13053h,-0.99144h, 1.0h), half3( 0.38268h,-0.92388h, 1.0h), half3( 0.60876h,-0.79335h, 1.0h), half3( 0.79335h,-0.60876h, 1.0h), half3( 0.92388h,-0.38268h, 1.0h), half3( 0.99144h,-0.13053h, 1.0h), half3( 0.64732h, 0.12876h, 0.66h), half3( 0.54877h, 0.36668h, 0.66h), half3( 0.36668h, 0.54877h, 0.66h), half3( 0.12876h, 0.64732h, 0.66h), half3(-0.12876h, 0.64732h, 0.66h), half3(-0.36668h, 0.54877h, 0.66h), half3(-0.54877h, 0.36668h, 0.66h), half3(-0.64732h, 0.12876h, 0.66h), half3(-0.64732h,-0.12876h, 0.66h), half3(-0.54877h,-0.36668h, 0.66h), half3(-0.36668h,-0.54877h, 0.66h), half3(-0.12876h,-0.64732h, 0.66h), half3( 0.12876h,-0.64732h, 0.66h), half3( 0.36668h,-0.54877h, 0.66h), half3( 0.54877h,-0.36668h, 0.66h), half3( 0.64732h,-0.12876h, 0.66h), half3( 0.30488h, 0.12629h, 0.33h), half3( 0.12629h, 0.30488h, 0.33h), half3(-0.12629h, 0.30488h, 0.33h), half3(-0.30488h, 0.12629h, 0.33h), half3(-0.30488h,-0.12629h, 0.33h), half3(-0.12629h,-0.30488h, 0.33h), half3( 0.12629h,-0.30488h, 0.33h), half3( 0.30488h,-0.12629h, 0.33h) }; inline half4 circleCocBokeh(half2 uv, bool sampleDilatedFG, int increment) { half4 centerTap = FetchMainTex(uv); half fgCoc = centerTap.a; if (sampleDilatedFG) { fgCoc = min(tex2Dlod(_SecondTex, half4(uv,0,0)).r, fgCoc); } half bgRadius = 0.5h * smoothstep(0.0h, 0.85h, centerTap.a) * _BlurCoe.y; half fgRadius = 0.5h * smoothstep(0.0h, 0.85h, -fgCoc) * _BlurCoe.x; half radius = max(bgRadius, fgRadius); if (radius < 1e-2f ) { return half4(centerTap.rgb, 0); } half2 poissonScale = radius * _MainTex_TexelSize.xy; half fgWeight = max(0,-centerTap.a); half bgWeight = max(0, centerTap.a); half3 fgSum = centerTap.rgb * fgWeight; half3 bgSum = centerTap.rgb * bgWeight; half radOtherFgRad = radius/(fgRadius + 1e-2h); half radOtherBgRad = radius/(bgRadius + 1e-2h); for (int l = 0; l < 48; l+= increment) { half2 sampleUV = uv + DiscBokeh48[l].xy * poissonScale.xy; half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscBokeh48[l].xy); half isNear = max(0.0h, -sample0.a); half distanceFactor = saturate(-0.5f * abs(sample0.a - centerTap.a) * DiscBokeh48[l].z + 1.0f); half isFar = max(0.0h, sample0.a) * distanceFactor; isNear *= 1- smoothstep(1.0h, 2.0h, DiscBokeh48[l].z * radOtherFgRad); isFar *= 1- smoothstep(1.0h, 2.0h, DiscBokeh48[l].z * radOtherBgRad); fgWeight += isNear; fgSum += sample0.rgb * isNear; bgWeight += isFar; bgSum += sample0.rgb * isFar; } half3 fgColor = fgSum / (fgWeight + 0.0001h); half3 bgColor = bgSum / (bgWeight + 0.0001h); half bgBlend = saturate (2.0h * bgWeight / 49.0h); half fgBlend = saturate (2.0h * fgWeight / 49.0h); half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); half3 finalColor = lerp(finalBg, fgColor, max(max(0.0h , -centerTap.a) , fgBlend)); half4 returnValue = half4(finalColor, fgBlend ); return returnValue; } half4 fragCircleBlurWithDilatedFg (v2fDepth i) : SV_Target { return circleCocBokeh(i.uv, true, 1); } half4 fragCircleBlur (v2fDepth i) : SV_Target { return circleCocBokeh(i.uv, false, 1); } half4 fragCircleBlurWithDilatedFgLowQuality (v2fDepth i) : SV_Target { return circleCocBokeh(i.uv, true, 2); } half4 fragCircleBlurLowQuality (v2fDepth i) : SV_Target { return circleCocBokeh(i.uv, false, 2); } /////////////////////////////////////////////////////////////////////////////// // Prefilter blur /////////////////////////////////////////////////////////////////////////////// #define DISC_PREFILTER_SAMPLE 9 static const half2 DiscPrefilter[DISC_PREFILTER_SAMPLE] = { half2(0.01288369f, 0.5416069f), half2(-0.9192798f, -0.09529364f), half2(0.7596578f, 0.1922738f), half2(-0.14132f, -0.2880242f), half2(-0.5249333f, 0.7777638f), half2(-0.5871695f, -0.7403569f), half2(0.3202196f, -0.6442268f), half2(0.8553214f, -0.3920982f), half2(0.5827708f, 0.7599297f) }; half4 fragCocPrefilter (v2fDepth i) : SV_Target { half4 centerTap = FetchMainTex(i.uv); half radius = 0.33h * 0.5h * (centerTap.a < 0.0f ? -(centerTap.a * _BlurCoe.x):(centerTap.a * _BlurCoe.y)); half2 poissonScale = radius * _MainTex_TexelSize.xy; if (radius < 0.01h ) { return centerTap; } half sampleCount = 1; half3 sum = centerTap.rgb * 1; for (int l = 0; l < DISC_PREFILTER_SAMPLE; l++) { half2 sampleUV = i.uv + DiscPrefilter[l].xy * poissonScale.xy; half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscPrefilter[l].xy); half weight = max(sample0.a * centerTap.a,0.0h); sum += sample0.rgb * weight; sampleCount += weight; } half4 returnValue = half4(sum / sampleCount, centerTap.a); return returnValue; } /////////////////////////////////////////////////////////////////////////////// // Final merge and upsample /////////////////////////////////////////////////////////////////////////////// inline half4 upSampleConvolved(half2 uv, bool useBicubic, bool useExplicit) { half2 convolvedTexelPos = uv * _Convolved_TexelSize.xy; half2 convolvedTexelCenter = floor( convolvedTexelPos ) + 0.5; half2 convolvedTexelOffsetFromCenter = convolvedTexelPos - convolvedTexelCenter; half2 offsetFromCoc = 0; #if defined(USE_TEX2DOBJECT_FOR_COC) half2 cocUV = (convolvedTexelOffsetFromCenter * _Convolved_TexelSize.zw) + uv; half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, cocUV); coc.r = GetCocFromZValue(coc.r, useExplicit); coc.g = GetCocFromZValue(coc.g, useExplicit); coc.b = GetCocFromZValue(coc.b, useExplicit); coc.a = GetCocFromZValue(coc.a, useExplicit); half4 absCoc = abs(coc); offsetFromCoc = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * 0.5; uv += offsetFromCoc * _Convolved_TexelSize.zw; #endif if (useBicubic) { //bicubic upsampling (B-spline) //adding offsetFromCoc "antialias" haloing from bright in focus region on dark out of focus region. //however its a hack as we should consider all the COC of the bicubic region and kill the bicubic //interpolation to avoid in any leaking but that would be too expensive, so when this is a problem //one should rather disable bicubic interpolation. half2 f = convolvedTexelOffsetFromCenter + offsetFromCoc; half2 f2 = f * f; half2 f3 = f * f2; half2 w0 = -0.166h * f3 + 0.5h * f2 - 0.5h * f + 0.166h; half2 w1 = 0.5h * f3 - f2 + 0.666h; half2 w3 = 0.166h * f3; half2 w2 = 1.0h - w0 - w1 - w3; half2 s0 = w0 + w1; half2 s1 = w2 + w3; half2 f0 = w1 / s0; half2 f1 = w3 / s1; half2 t0 = _Convolved_TexelSize.zw * (convolvedTexelCenter - 1.0h + f0); half2 t1 = _Convolved_TexelSize.zw * (convolvedTexelCenter + 1.0h + f1); return tex2Dlod(_SecondTex, half4(t0.x, t0.y, 0, 0)) * s0.x * s0.y + tex2Dlod(_SecondTex, half4(t1.x, t0.y, 0, 0)) * s1.x * s0.y + tex2Dlod(_SecondTex, half4(t0.x, t1.y, 0, 0)) * s0.x * s1.y + tex2Dlod(_SecondTex, half4(t1.x, t1.y, 0, 0)) * s1.x * s1.y; } else { return tex2Dlod(_SecondTex, half4(uv,0,0)); } } inline half4 dofMerge (half2 uv, bool useExplicit, bool useBicubic) { half4 convolvedTap = upSampleConvolved(uv, useBicubic, useExplicit); convolvedTap.rgb = ToneMapInvert(convolvedTap.rgb); half4 sourceTap = FetchMainTex(uv); half coc = GetCocFromDepth(uv, useExplicit); sourceTap.rgb += getBoostAmount(half4(sourceTap.rgb, coc)); coc = (coc * _BlurCoe.y > 1.0h )?coc:0.0h; half blendValue = smoothstep(0.0, 0.33h, max(coc, convolvedTap.a)); half3 returnValue = lerp(sourceTap.rgb, convolvedTap.rgb, blendValue); return (blendValue < 1e-2f) ? sourceTap : half4(returnValue.rgb, sourceTap.a); } half4 fragMergeBicubic (v2fDepth i) : SV_Target { return dofMerge(i.uv, false, true); } half4 fragMergeExplicitBicubic (v2fDepth i) : SV_Target { return dofMerge(i.uv, true, true); } half4 fragMerge (v2fDepth i) : SV_Target { return dofMerge(i.uv, false, false); } half4 fragMergeExplicit (v2fDepth i) : SV_Target { return dofMerge(i.uv, true, false); } /////////////////////////////////////////////////////////////////////////////// // Downsampling and COC computation /////////////////////////////////////////////////////////////////////////////// inline half4 captureCoc(half2 uvColor, half2 uvDepth, bool useExplicit) { /*****************/ /* coc.a | coc.b */ /* coc.r | coc.g */ /*****************/ #if defined(USE_TEX2DOBJECT_FOR_COC) half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, uvDepth); coc.r = GetCocFromZValue(coc.r, useExplicit); coc.g = GetCocFromZValue(coc.g, useExplicit); coc.b = GetCocFromZValue(coc.b, useExplicit); coc.a = GetCocFromZValue(coc.a, useExplicit); #else half4 coc; coc.r = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25f,+0.25f), useExplicit); coc.g = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(+0.25f,+0.25f), useExplicit); coc.b = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(+0.25f,-0.25f), useExplicit); coc.a = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25f,-0.25f), useExplicit); #endif half4 absCoc = abs(coc); half2 offset = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * _MainTex_TexelSize.xy; half4 color = FetchMainTex(uvColor + offset); half cocRG = (absCoc.r