포스트

[ Dx11 ] (solution) 디노이징 오류

문제


모션 벡터 탐색에 실패한 픽셀을 Edge-Avoiding À-Trous Filter에서 edge로 판단, 디노이징 효과가 제대로 되지 않는 문제가 발생했다.

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
88
89
90
91
92
93
94
95
96
97
98
static const float Gaussiankernel[25] =
{
   0.00390625f, 0.015625f,   0.0234375f,   0.015625f,   0.00390625f,
   0.015625f,    0.0625f,   0.09375f,   0.0625f,   0.015625f,
   0.0234375f,    0.09375f,   0.140625f,   0.09375f,   0.0234375f,
   0.015625f,    0.0625f,   0.09375f,   0.0625f,   0.015625f,
   0.00390625f, 0.015625f,   0.0234375f,   0.015625f,   0.00390625f,
};

static const float2 offsets[25] =
{
   float2(-2.0f, -2.0f), float2(-1.0f, -2.0f), float2(0.0f, -2.0f), float2(1.0f, -2.0f), float2(2.0f, -2.0f),
   float2(-2.0f, -1.0f), float2(-1.0f, -1.0f), float2(0.0f, -1.0f), float2(1.0f, -1.0f), float2(2.0f, -2.0f),
   float2(-2.0f, 0.0f),  float2(-1.0f, 0.0f),  float2(0.0f, 0.0f),  float2(1.0f, 0.0f),  float2(2.0f, 0.0f),
   float2(-2.0f, 1.0f),  float2(-1.0f, 1.0f),  float2(0.0f, 1.0f),  float2(1.0f, 1.0f),  float2(2.0f, 1.0f),
   float2(-2.0f, 2.0f),  float2(-1.0f, 2.0f),  float2(0.0f, 2.0f),  float2(1.0f, 2.0f),  float2(2.0f, 2.0f),
};


float4 doEdgeAvoidATrousWavelet_improved(float ScreenWidth, float ScreenHeight, float2 uv, float stepwidth)
{
	float weight, l_w, cum_w = 0.0f;
	float2 UV, deltaDepth, deltaLuminance, step;
	float3 ntmp, RGBtmp, sum, generalColor;
	float searchSuccessRatetmp = 0.0f;

	generalColor = g_ColorMap.Sample(g_samPoint, uv).xyz;
	step = float2(1.0f / ScreenWidth, 1.0f / ScreenHeight);
	sum = float3(0.0f, 0.0f, 0.0f);

	[unroll(25)] for (int j = 0; j < 25; j++)
	{
		UV = uv + offsets[j] * step * stepwidth;

		// Luminance
		RGBtmp = g_FullscreenQuad.Sample(g_samPoint, UV).xyz;
		// Luminance
		searchSuccessRatetmp = g_FullscreenQuad.Sample(g_samPoint, UV).w;

		float3 t = generalColor - RGBtmp.xyz;
		float c_w = max(min(1.0 - dot(t, t), 1.0), 0.0);

		l_w = Gaussiankernel[j] * searchSuccessRatetmp;// *c_w;
		//l_w = searchSuccessRatetmp;
		//l_w = Gaussiankernel[j];

		weight = l_w;
		sum += RGBtmp * weight;
		cum_w += weight;
	}

	sum /= cum_w;

	//return float4(cum_w/25, cum_w / 25, cum_w / 25, 1.0f);
	return float4(sum, 1.0f);
}
//-------------------------------------denoising----------------

struct FullScreenQuadDenoisingVertexOut
{
	float4 position : SV_POSITION;
	float2 uv : TEXCOORD;
};

FullScreenQuadDenoisingVertexOut FullScreenQuadDenoisingVS(uint vertexID : SV_VertexID)
{
	FullScreenQuadDenoisingVertexOut OutputVS;
	//---------------------------------------------------------------------------------
	// Option 1: Cull Mode = Back face culling
	//---------------------------------------------------------------------------------
	OutputVS.uv = float2((vertexID << 1) & 2, vertexID & 2);
	OutputVS.position = float4(OutputVS.uv * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);

	//---------------------------------------------------------------------------------
	// Option 2: Cull Mode = Front face culling
	//---------------------------------------------------------------------------------
	//OutputVS.uv = float2(((vertexID << 1) & 2) * 2.0f, (vertexID == 0) * -4.0f);
	//OutputVS.position = float4(OutputVS.uv + float2(-1.0f, 1.0f), 0.0f, 1.0f);

	return OutputVS;
}

float4 FullScreenQuadDenoisingPS(FullScreenQuadDenoisingVertexOut In) : SV_TARGET
{
	float stepWidth = 1.0f;

	float4 color = doEdgeAvoidATrousWavelet_improved(gWidth, gHeight, In.uv, stepWidth);// 디노이징 한거
	//float4 color = g_FullscreenQuad.Sample(g_samLinear, In.uv);// 디노이징 하기전
	//float4 color = g_ColorMap.SampleLevel(g_samLinear, In.uv, 0);
	//float4 color = g_motionVector3DMap4.SampleLevel(g_samLinear, In.uv, 0);
	//float4 color = g_previousDepthMap.SampleLevel(g_samLinear, In.uv, 0)/100;

	return color;
}



해결


Edge-Avoiding À-Trous Filter

P를 중심으로 거리에 따른 가중치를 이용한 Gaussian 분포도와 P 와 C_(〖P_i〗_  ) 의 색상차이를 계산해 edge를 구분하는 filter. 단, 이 방법을 사용하게 되면 모션벡터 탐색에 실패한 픽셀을 edge로 판단해, 높은 가중치로 계산되어 노이즈 제거에 실패

Denoising with Pixel Reliability

• Reliability : CalculateMotionBlurredColor() 에서 출력된 successRate (Number Of Color Sample / Sample per frame)

• Finding motion vector passing through current pixel을 실패했을 때 CalculateMotionBlurredColor()는 실행되지 않음

• 모션벡터 탐색에 실패한 픽셀은 Sample per frame 대비 실패율이 높기 때문에 낮은 Reliability를 가지기 때문에  노이즈로 판단 가능

폴리곤의 정보가 소실된 픽셀 샘플 픽셀


따라서 이를 낮은 가중치로 계산하기 위해 픽셀의 신뢰도를 추가한 필터를 사용

Denoising with Pixel Reliability : 모션벡터 탐색에 실패한 픽셀의 가중치를 낮게 계산하기 위해 w(P_(i ))에 Reliability를 추가


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
float4 denoising(float2 uv)
{
    float sum_w = 0, depthCmp = 0.99;
    float3 sumColor = float3(0.0f, 0.0f, 0.0f);
    uint4 firstLayer = g_sorted_Color_Depth_MotionVectorMap.Load(int4(GetScreenUV(uv), 0, 0));
    float3 curPixelColor = unpack_rgb(firstLayer.x).xyz;

    [unroll(25)]
    for (int j = 0; j < 25; j++)
    {
        float2 aroundUV = uv + offsets[j];
        float3 RGBtmp = g_MotionBlurColorMap.Sample(g_samLinear, aroundUV).xyz;
        float4 aroundDepth_SuccessRate_motionVector = g_MotionBlurDepthWeightMap.Sample(g_samLinear, aroundUV);
        float c_w = abs(1 - dot(RGBtmp, curPixelColor));
        float d_w = max((1 - abs(unpack_depth(firstLayer.y) - aroundDepth_SuccessRate_motionVector.x) / ZFAR), 0);
        if (d_w < depthCmp)
            d_w = 0.3;

        //float weight = gaussianKernel[j] * aroundDepth_SuccessRate_motionVector.y * c_w;
        float weight = gaussianKernel[j] * aroundDepth_SuccessRate_motionVector.y * d_w * c_w;
        sumColor += RGBtmp * weight;
        sum_w += weight;
        //if (needDenoging == false && aroundDepth_SuccessRate_motionVector.z != 0.f && aroundDepth_SuccessRate_motionVector.w != 0.f) needDenoging = true;
    }
    float3 resColor = sumColor / sum_w;

    return float4(resColor, 1);
}


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.