-
Notifications
You must be signed in to change notification settings - Fork 774
/
BilateralUpsample.hlsl
168 lines (144 loc) · 7.82 KB
/
BilateralUpsample.hlsl
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#define _UpsampleTolerance 1e-9f
#define _NoiseFilterStrength 0.99999999f
// This table references the set of pixels that are used for bilateral upscale based on the expected order
static const int2 UpscaleBilateralPixels[16] = {int2(0, 0), int2(0, -1), int2(-1, -1), int2(-1, 0)
, int2(0, 0), int2(0, -1), int2(1, -1), int2(1, 0)
, int2(0, 0) , int2(-1, 0), int2(-1, 1), int2(0, 1)
, int2(0, 0), int2(1, 0), int2(1, 1), int2(0, 1), };
static const int2 IndexToLocalOffsetCoords[9] = {int2(-1, -1), int2(0, -1), int2(1, -1)
, int2(-1, 0), int2(0, 0), int2(1, 0)
, int2(-1, 1) , int2(0, 1), int2(1, 1)};
// The bilateral upscale function (2x2 neighborhood, color3 version), uniform weight version
float3 BilUpColor3_Uniform(float HiDepth, float4 LowDepths, float3 lowValue0, float3 lowValue1, float3 lowValue2, float3 lowValue3)
{
float4 weights = float4(3, 3, 3, 3) / (abs(HiDepth - LowDepths) + _UpsampleTolerance);
float TotalWeight = dot(weights, 1) + _NoiseFilterStrength;
float3 WeightedSum = lowValue0 * weights.x
+ lowValue1 * weights.y
+ lowValue2 * weights.z
+ lowValue3 * weights.w
+ _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}
// THe bilateral upscale function (2x2 neighborhood, color3 version)
float3 BilUpColor3(float HiDepth, float4 LowDepths, float3 lowValue0, float3 lowValue1, float3 lowValue2, float3 lowValue3)
{
float4 weights = float4(9, 3, 1, 3) / (abs(HiDepth - LowDepths) + _UpsampleTolerance);
float TotalWeight = dot(weights, 1) + _NoiseFilterStrength;
float3 WeightedSum = lowValue0 * weights.x
+ lowValue1 * weights.y
+ lowValue2 * weights.z
+ lowValue3 * weights.w
+ _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}
// The bilateral upscale function (2x2 neighborhood, color4 version)
float4 BilUpColor(float HiDepth, float4 LowDepths, float4 lowValue0, float4 lowValue1, float4 lowValue2, float4 lowValue3)
{
float4 weights = float4(9, 3, 1, 3) / (abs(HiDepth - LowDepths) + _UpsampleTolerance);
float TotalWeight = dot(weights, 1) + _NoiseFilterStrength;
float4 WeightedSum = lowValue0 * weights.x
+ lowValue1 * weights.y
+ lowValue2 * weights.z
+ lowValue3 * weights.w
+ _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}
static const float BilateralUpSampleWeights3x3[9] = {9.0, 3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0};
// Due to compiler issues, it is not possible to use arrays to store the neighborhood values, we then store
// them in this structure
struct NeighborhoodUpsampleData3x3
{
// Low resolution depths
float4 lowDepthA;
float4 lowDepthB;
float lowDepthC;
// The low resolution masks
float4 lowMasksA;
float4 lowMasksB;
float lowMasksC;
// The low resolution values
float4 lowValue0;
float4 lowValue1;
float4 lowValue2;
float4 lowValue3;
float4 lowValue4;
float4 lowValue5;
float4 lowValue6;
float4 lowValue7;
float4 lowValue8;
};
void EvaluateMaskValidity(float linearHighDepth, float lowDepth, int currentIndex,
inout float inputMask, inout int closestNeighhor,
inout float currentDistance, inout float rejectedNeighborhood)
{
if(inputMask == 0.0f)
return;
// Convert the depths to linear
float candidateLinearDepth = Linear01Depth(lowDepth, _ZBufferParams);
// Compute the distance between the two values
float candidateDistance = abs(linearHighDepth - candidateLinearDepth);
// Evaluate if this becomes the closest neighbor
if (candidateDistance < currentDistance)
{
closestNeighhor = currentIndex;
currentDistance = candidateDistance;
}
bool validSample = candidateDistance < (linearHighDepth * 0.3);
inputMask = validSample ? 1.0f : 0.0f;
rejectedNeighborhood *= (validSample ? 0.0f : 1.0f);
}
void OverrideMaskValues(float highDepth, inout NeighborhoodUpsampleData3x3 data,
out float rejectedNeighborhood, out int closestNeighhor)
{
// First of all compute the linear version of the high depth
float linearHighDepth = Linear01Depth(highDepth, _ZBufferParams);
// Flag that tells us which pixel holds valid information
rejectedNeighborhood = 1.0f;
closestNeighhor = 4;
float currentDistance = 1.0f;
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.x, 0, data.lowMasksA.x, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.y, 1, data.lowMasksA.y, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.z, 2, data.lowMasksA.z, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.w, 3, data.lowMasksA.w, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.x, 4, data.lowMasksB.x, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.y, 5, data.lowMasksB.y, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.z, 6, data.lowMasksB.z, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.w, 7, data.lowMasksB.w, closestNeighhor, currentDistance, rejectedNeighborhood);
EvaluateMaskValidity(linearHighDepth, data.lowDepthC, 8, data.lowMasksC, closestNeighhor, currentDistance, rejectedNeighborhood);
}
// The bilateral upscale function (3x3 neighborhood)
float4 BilUpColor3x3(float highDepth, in NeighborhoodUpsampleData3x3 data)
{
float4 weightsA = float4(1, 3, 1, 3) / (abs(highDepth - data.lowDepthA) + _UpsampleTolerance);
float4 weightsB = float4(9, 3, 1, 3) / (abs(highDepth - data.lowDepthB) + _UpsampleTolerance);
float weightsC = 1.0 / (abs(highDepth - data.lowDepthC) + _UpsampleTolerance);
float TotalWeight = dot(weightsA, 1) + dot(weightsB, 1) + weightsC + _NoiseFilterStrength;
float4 WeightedSum = data.lowValue0 * weightsA.x
+ data.lowValue1 * weightsA.y
+ data.lowValue2 * weightsA.z
+ data.lowValue3 * weightsA.w
+ data.lowValue4 * weightsB.x
+ data.lowValue5 * weightsB.y
+ data.lowValue6 * weightsB.z
+ data.lowValue7 * weightsB.w
+ data.lowValue8 * weightsC
+ _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}
// The bilateral upscale function (2x2 neighborhood) (single channel version)
float BilUpSingle(float HiDepth, float4 LowDepths, float4 lowValue)
{
float4 weights = float4(9, 3, 1, 3) / (abs(HiDepth - LowDepths) + _UpsampleTolerance);
float TotalWeight = dot(weights, 1) + _NoiseFilterStrength;
float WeightedSum = dot(lowValue, weights) + _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}
// The bilateral upscale function (2x2 neighborhood) (single channel version), uniform version
float BilUpSingle_Uniform(float HiDepth, float4 LowDepths, float4 lowValue)
{
float4 weights = float4(3, 3, 3, 3) / (abs(HiDepth - LowDepths) + _UpsampleTolerance);
float TotalWeight = dot(weights, 1) + _NoiseFilterStrength;
float WeightedSum = dot(lowValue, weights) + _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}