You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

220 lines
9.9 KiB

#define _UpsampleTolerance 1e-5f
#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, color3 version)
float3 BilUpColor3WithWeight(float HiDepth, float4 LowDepths, float3 lowValue0, float3 lowValue1, float3 lowValue2, float3 lowValue3, float4 initialWeight)
{
float4 weights = initialWeight * 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;
}
// 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;
}
// 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;
// Weights used to combine the neighborhood
float4 lowWeightA;
float4 lowWeightB;
float lowWeightC;
};
void EvaluateMaskValidity(float linearHighDepth, float lowDepth, int currentIndex,
inout float inputMask, inout int closestNeighhor,
inout float currentDistance)
{
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;
}
void OverrideMaskValues(float highDepth, inout NeighborhoodUpsampleData3x3 data,
out bool rejectedNeighborhood, out int closestNeighbor)
{
// First of all compute the linear version of the high depth
float linearHighDepth = Linear01Depth(highDepth, _ZBufferParams);
float currentDistance = 1.0f;
closestNeighbor = 4; // Index of the closest neighbor (center by default)
// The center has precedence over the other pixels
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.x, 4, data.lowMasksB.x, closestNeighbor, currentDistance);
// Then the plus
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.y, 1, data.lowMasksA.y, closestNeighbor, currentDistance);
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.w, 3, data.lowMasksA.w, closestNeighbor, currentDistance);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.y, 5, data.lowMasksB.y, closestNeighbor, currentDistance);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.w, 7, data.lowMasksB.w, closestNeighbor, currentDistance);
// Then the cross
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.x, 0, data.lowMasksA.x, closestNeighbor, currentDistance);
EvaluateMaskValidity(linearHighDepth, data.lowDepthA.z, 2, data.lowMasksA.z, closestNeighbor, currentDistance);
EvaluateMaskValidity(linearHighDepth, data.lowDepthB.z, 6, data.lowMasksB.z, closestNeighbor, currentDistance);
EvaluateMaskValidity(linearHighDepth, data.lowDepthC, 8, data.lowMasksC, closestNeighbor, currentDistance);
// Flag that tells us which pixel holds valid information
rejectedNeighborhood = (currentDistance >= (linearHighDepth * 0.3));
}
// The bilateral upscale function (3x3 neighborhood)
float4 BilUpColor3x3(float highDepth, in NeighborhoodUpsampleData3x3 data)
{
float4 combinedWeightsA = data.lowWeightA / (abs(highDepth - data.lowDepthA) + _UpsampleTolerance);
float4 combinedWeightsB = data.lowWeightB / (abs(highDepth - data.lowDepthB) + _UpsampleTolerance);
float combinedWeightsC = data.lowWeightC / (abs(highDepth - data.lowDepthC) + _UpsampleTolerance);
float TotalWeight = combinedWeightsA.x + combinedWeightsA.y + combinedWeightsA.z + combinedWeightsA.w
+ combinedWeightsB.x + combinedWeightsB.y + combinedWeightsB.z + combinedWeightsB.w
+ combinedWeightsC
+ _NoiseFilterStrength;
float4 WeightedSum = data.lowValue0 * combinedWeightsA.x
+ data.lowValue1 * combinedWeightsA.y
+ data.lowValue2 * combinedWeightsA.z
+ data.lowValue3 * combinedWeightsA.w
+ data.lowValue4 * combinedWeightsB.x
+ data.lowValue5 * combinedWeightsB.y
+ data.lowValue6 * combinedWeightsB.z
+ data.lowValue7 * combinedWeightsB.w
+ data.lowValue8 * combinedWeightsC
+ float4(_NoiseFilterStrength, _NoiseFilterStrength, _NoiseFilterStrength, 0.0);
return WeightedSum / TotalWeight;
}
// Due to compiler issues, it is not possible to use arrays to store the neighborhood values, we then store them in this structure
struct NeighborhoodUpsampleData2x2_RGB
{
// Low resolution depths
float4 lowDepth;
// The low resolution values
float3 lowValue0;
float3 lowValue1;
float3 lowValue2;
float3 lowValue3;
// Weights used to combine the neighborhood
float4 lowWeight;
};
// The bilateral upscale function (3x3 neighborhood)
float3 BilUpColor2x2_RGB(float highDepth, in NeighborhoodUpsampleData2x2_RGB data)
{
float4 combinedWeights = data.lowWeight / (abs(highDepth - data.lowDepth) + _UpsampleTolerance);
float TotalWeight = combinedWeights.x + combinedWeights.y + combinedWeights.z + combinedWeights.w + _NoiseFilterStrength;
float3 WeightedSum = data.lowValue0.xyz * combinedWeights.x
+ data.lowValue1.xyz * combinedWeights.y
+ data.lowValue2.xyz * combinedWeights.z
+ data.lowValue3.xyz * combinedWeights.w
+ _NoiseFilterStrength;
return WeightedSum / TotalWeight;
}