景深后处理颜色溢出处理
景深后处理颜色溢出处理
景深后处理颜色溢出处理
00 前言
景深后处理开启时, 在物体边缘处会出现颜色溢出的问题.
经过排查, Unity在进行景深的剔除前, 就对景深的原图和Mask进行了模糊处理.
同时, 最根本的原因是深度图并不能”严格”的覆盖漫反射图. 推测原因是两张图片的格式, 深度图为R8, 而屏幕截图是RGB111110Float, 同时由于图片都是Bilinear的Filter方式, 导致无法严格的遮挡.
01 处理方法
该处理方式会导致在明亮场景中出现分割线的问题, 抛弃.
采样原图时不做模糊. 这样可以减弱颜色溢出, 但如前图所示, 仍旧无法完全的进行遮蔽.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
half4 FragPrefilter(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
#if SHADER_TARGET >= 45 && defined(PLATFORM_SUPPORT_GATHER)
// Sample source colors
half4 cr = GATHER_RED_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv);
half4 cg = GATHER_GREEN_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv);
half4 cb = GATHER_BLUE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv);
half3 c0 = half3(cr.x, cg.x, cb.x);
half3 c1 = half3(cr.y, cg.y, cb.y);
half3 c2 = half3(cr.z, cg.z, cb.z);
half3 c3 = half3(cr.w, cg.w, cb.w);
// Sample CoCs
half4 cocs = GATHER_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv) * 2.0 - 1.0;
half coc0 = cocs.x;
half coc1 = cocs.y;
half coc2 = cocs.z;
half coc3 = cocs.w;
#else
float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
float2 uv0 = uv - duv.xy;
float2 uv1 = uv - duv.zy;
float2 uv2 = uv + duv.zy;
float2 uv3 = uv + duv.xy;
// Sample source colors
half3 c0 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv0).xyz;
half3 c1 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv1).xyz;
half3 c2 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv2).xyz;
half3 c3 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv3).xyz;
// Sample CoCs
half coc0 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv0).x * 2.0 - 1.0;
half coc1 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv1).x * 2.0 - 1.0;
half coc2 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv2).x * 2.0 - 1.0;
half coc3 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv3).x * 2.0 - 1.0;
#endif
#if COC_LUMA_WEIGHTING
// Apply CoC and luma weights to reduce bleeding and flickering
half w0 = abs(coc0) / (Max3(c0.x, c0.y, c0.z) + 1.0);
half w1 = abs(coc1) / (Max3(c1.x, c1.y, c1.z) + 1.0);
half w2 = abs(coc2) / (Max3(c2.x, c2.y, c2.z) + 1.0);
half w3 = abs(coc3) / (Max3(c3.x, c3.y, c3.z) + 1.0);
// Weighted average of the color samples
half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3;
avg /= max(w0 + w1 + w2 + w3, 1e-5);
#else
half3 avg = (c0 + c1 + c2 + c3) / 4.0;
#endif
//修改, 直接采样原图和_FullCoCTexture, 不模糊.
float2 uv4 = uv;
half3 c4 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv4).xyz;
half coc4 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv4).x * 2.0 - 1.0;
half3 avg =c4 * abs(coc4);
//修改
// Select the largest CoC value
half cocMin = min(coc0, Min3(coc1, coc2, coc3));
half cocMax = max(coc0, Max3(coc1, coc2, coc3));
half coc = (-cocMin > cocMax ? cocMin : cocMax) * MaxRadius;
// Premultiply CoC
avg *= smoothstep(0, _MainTex_TexelSize.y * 2.0, abs(coc));
#if defined(UNITY_COLORSPACE_GAMMA)
avg = SRGBToLinear(avg);
#endif
return half4(avg, coc);
}
参考网页
02 定制记录
涉及文件:
- 着色器:
Packages/com.unity.render-pipelines.universal@14.0.8/Shaders/PostProcessing/BokehDepthOfField.shader - 面板(不涉及, 仅关联):
Packages/com.unity.render-pipelines.universal@14.0.8/Runtime/Overrides/DepthOfField.csPackages/com.unity.render-pipelines.universal@14.0.8/Editor/Overrides/DepthOfFieldEditor.cs - Pass:
Packages/com.unity.render-pipelines.universal@14.0.8/Runtime/Passes/PostProcessPass.cs
完整代码
shader代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
half4 FragPrefilterV2(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
float2 uv0 = uv - duv.xy;
float2 uv1 = uv - duv.zy;
float2 uv2 = uv + duv.zy;
float2 uv3 = uv + duv.xy;
half3 c4 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv).xyz;
half coc0 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv0).x * 2.0 - 1.0;
half coc1 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv1).x * 2.0 - 1.0;
half coc2 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv2).x * 2.0 - 1.0;
half coc3 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv3).x * 2.0 - 1.0;
half cocMin = min(coc0, Min3(coc1, coc2, coc3));
half cocMax = max(coc0, Max3(coc1, coc2, coc3));
half coc = (-cocMin > cocMax ? cocMin : cocMax) * MaxRadius;
half coc4 = SAMPLE_TEXTURE2D_X(_FullCoCTexture, sampler_LinearClamp, uv).x * 2.0 - 1.0;
half3 avg =c4 * abs(coc4);
#if defined(UNITY_COLORSPACE_GAMMA)
avg = SRGBToLinear(avg);
#endif
return half4(avg, coc);
}
...
Pass
{
Name "Bokeh Depth Of Field PrefilterV2"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragPrefilterV2
#pragma target 3.0
ENDHLSL
}
Pass代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
void DoDepthOfField(Camera camera, CommandBuffer cmd, int source, int destination, Rect pixelRect)
{
if (m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian)
DoGaussianDepthOfField(camera, cmd, source, destination, pixelRect);
else if (m_DepthOfField.mode.value == DepthOfFieldMode.Bokeh)
DoBokehDepthOfField(cmd, source, destination, pixelRect);
//C10132023
else if (m_DepthOfField.mode.value == DepthOfFieldMode.BokehVer2)
{
DoBokehDepthOfFieldV2(cmd, source, destination, pixelRect);
}
//C10132023
}
...
void DoBokehDepthOfFieldV2(CommandBuffer cmd, int source, int destination, Rect pixelRect)
{
m_DepthOfField.nearClearPlane.value = URPUserData.NearClearPlane;
m_DepthOfField.farClearPlane.value = URPUserData.FarClearPlane;
m_DepthOfField.farBlurAttend.value = URPUserData.FarBlurAttend;
m_DepthOfField.focalLength.value = URPUserData.FocalLength;
m_DepthOfField.aperture.value = URPUserData.Aperture;
var material = m_Materials.bokehDepthOfField;
int wh = m_Descriptor.width / 2;
int hh = m_Descriptor.height / 2;
// "A Lens and Aperture Camera Model for Synthetic Image Generation" [Potmesil81]
float F = m_DepthOfField.focalLength.value / 1000f;
float A = m_DepthOfField.focalLength.value / m_DepthOfField.aperture.value;
//C10132023
// float P = m_DepthOfField.focusDistance.value;
float P = m_DepthOfField.nearClearPlane.value / 100f;
//C10132023
float maxCoC = (A * F) / (P - F);
float maxRadius = GetMaxBokehRadiusInPixels(m_Descriptor.height);
float rcpAspect = 1f / (wh / (float)hh);
//C10132023
float N = m_DepthOfField.farClearPlane.value / 100f; //因为是厘米
float farBlurAttend = m_DepthOfField.farBlurAttend.value;
cmd.SetGlobalFloat(ShaderConstants._FarClearPlane, N);
cmd.SetGlobalFloat(ShaderConstants._FarBlurAttend, farBlurAttend);
//C10132023
cmd.SetGlobalVector(ShaderConstants._CoCParams, new Vector4(P, maxCoC, maxRadius, rcpAspect));
// Prepare the bokeh kernel constant buffer
int hash = m_DepthOfField.GetHashCode();
if (hash != m_BokehHash)
{
m_BokehHash = hash;
PrepareBokehKernel();
}
cmd.SetGlobalVectorArray(ShaderConstants._BokehKernel, m_BokehKernel);
// Temporary textures
cmd.GetTemporaryRT(ShaderConstants._FullCoCTexture, GetStereoCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8_UNorm), FilterMode.Bilinear);
cmd.GetTemporaryRT(ShaderConstants._PingTexture, GetStereoCompatibleDescriptor(wh, hh, GraphicsFormat.R16G16B16A16_SFloat), FilterMode.Bilinear);
cmd.GetTemporaryRT(ShaderConstants._PongTexture, GetStereoCompatibleDescriptor(wh, hh, GraphicsFormat.R16G16B16A16_SFloat), FilterMode.Bilinear);
// Compute CoC
cmd.Blit(source, ShaderConstants._FullCoCTexture, material, 5);
cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
// Downscale & prefilter color + coc
cmd.Blit(source, ShaderConstants._PingTexture, material, 6);
// Bokeh blur
cmd.Blit(ShaderConstants._PingTexture, ShaderConstants._PongTexture, material, 2);
// Post-filtering
cmd.Blit(ShaderConstants._PongTexture, BlitDstDiscardContent(cmd, ShaderConstants._PingTexture), material, 3);
// Composite
cmd.SetGlobalTexture(ShaderConstants._DofTexture, ShaderConstants._PingTexture);
cmd.Blit(source, BlitDstDiscardContent(cmd, destination), material, 4);
// Cleanup
cmd.ReleaseTemporaryRT(ShaderConstants._FullCoCTexture);
cmd.ReleaseTemporaryRT(ShaderConstants._PingTexture);
cmd.ReleaseTemporaryRT(ShaderConstants._PongTexture);
}
本文由作者按照 CC BY 4.0 进行授权
