167 lines
7.4 KiB
HLSL
167 lines
7.4 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "TSRCommon.ush"
|
|
|
|
|
|
//------------------------------------------------------- CONSTANTS
|
|
|
|
static const uint kReprojectionVectorOutputIndex = 0;
|
|
static const uint kReprojectionJacobianOutputIndex = 1;
|
|
static const uint kReprojectionBoundaryOutputIndex = 2;
|
|
|
|
|
|
//------------------------------------------------------- REPROJECTION's DILATING OFFSET & BOUNDARY
|
|
|
|
static const tsr_half2 kFullDilateBoundary = tsr_half2(0.0, 1.0);
|
|
|
|
uint EncodeReprojectionOffset(tsr_short2 ReprojectionOffset)
|
|
{
|
|
return uint(dot(tsr_ushort2(ReprojectionOffset + tsr_ushort(1)), tsr_ushort2(1, 4)));
|
|
}
|
|
|
|
/** Encodes the reprojection field's dilating offset [-1;1]^2 in first 4bits, and ReprojectionBoundary.xy in 11bit eachs, 26bits total. */
|
|
uint EncodeReprojectionBoundary(tsr_short2 ReprojectionOffset, tsr_half2 ReprojectionBoundary)
|
|
{
|
|
uint EncodedReprojectionOffset = EncodeReprojectionOffset(ReprojectionOffset);
|
|
|
|
tsr_short2 BoundaryBits = tsr_short2(round(ReprojectionBoundary * tsr_half(1023))) + 1024;
|
|
BoundaryBits = fastClamp(BoundaryBits, tsr_short(1).xx, tsr_short(2047).xx);
|
|
|
|
uint EncodedReprojectionBoundary = EncodedReprojectionOffset | (uint(BoundaryBits.x) << 4) | (uint(BoundaryBits.y) << 15);
|
|
return EncodedReprojectionBoundary;
|
|
}
|
|
|
|
/** Decodes EncodeReprojectionBoundary()'s ReprojectionOffset. */
|
|
tsr_short2 DecodeReprojectionOffset(uint EncodedReprojectionBoundary)
|
|
{
|
|
tsr_short2 ReprojectionOffset = (tsr_short2(EncodedReprojectionBoundary, EncodedReprojectionBoundary >> 2u) & tsr_short(0x3)) - tsr_short(1);
|
|
return ReprojectionOffset;
|
|
}
|
|
|
|
/** Returns any(EncodeReprojectionBoundary() != 0). */
|
|
bool HasEncodedReprojectionOffset(uint EncodedReprojectionBoundary)
|
|
{
|
|
uint EncodedReprojectionOffset = EncodedReprojectionBoundary & 0xFu;
|
|
bool bHasReprojectionOffset = EncodedReprojectionOffset != 5;
|
|
return bHasReprojectionOffset;
|
|
}
|
|
|
|
/** Decodes EncodeReprojectionBoundary()'s ReprojectionBoundary. */
|
|
tsr_half2 DecodeReprojectionBoundary(uint EncodedReprojectionBoundary)
|
|
{
|
|
tsr_short2 BoundaryBits = (tsr_short2(EncodedReprojectionBoundary >> 4u, EncodedReprojectionBoundary >> 15u) & tsr_short(0x7FF)) - tsr_short(1024);
|
|
tsr_half2 ReprojectionBoundary = fastClamp(tsr_half2(BoundaryBits) * rcp(tsr_half(1023)), tsr_half(-1.0).xx, tsr_half(1.0).xx);
|
|
return ReprojectionBoundary;
|
|
}
|
|
|
|
/** Estimate the coverage of the boundary over the rendered pixel. */
|
|
tsr_half ComputeReprojectionBoundaryCoverage(tsr_half2 ReprojectionBoundary)
|
|
{
|
|
tsr_half ReprojectionBoundaryCoverage = length(ReprojectionBoundary);
|
|
return ReprojectionBoundaryCoverage;
|
|
}
|
|
|
|
/** Returns whether the history's pixel has any overlap with the velocity boundary, to apply the ReprojectionOffset. */
|
|
bool IsHistoryPixelWithinOffsetBoundary(tsr_half2 dInputKO, tsr_half2 ReprojectionBoundary, float HistoryToInputFactor)
|
|
{
|
|
tsr_half2 dInputKC = tsr_half(0.5) - tsr_half2(sign_bit(ReprojectionBoundary));
|
|
tsr_half2 dInputOR = + dInputKC * tsr_half(HistoryToInputFactor);
|
|
|
|
tsr_half2 dInputBC = ReprojectionBoundary;
|
|
tsr_half2 dInputBR = dInputBC - dInputKC + dInputKO + dInputOR;
|
|
|
|
bool bHistoryPixelWithinOffsetBoundary = dot(dInputBR, dInputBC) > tsr_half(0.0);
|
|
return bHistoryPixelWithinOffsetBoundary;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------- REPROJECTION's VECTOR
|
|
|
|
/** Encodes the reprojection vector into 32bits. */
|
|
uint EncodeReprojectionVector(float2 ReprojectionVector)
|
|
{
|
|
float2 EncodedScreenVelocity = EncodeVelocityToTexture(float3(ReprojectionVector.xy, 0.0)).xy;
|
|
|
|
float2 UnormEncoding = clamp(EncodedScreenVelocity * 65535.0f + 0.5f, 0.0f, 65535.0f);
|
|
|
|
uint EncodedReprojectionVector = 0u;
|
|
EncodedReprojectionVector |= uint(UnormEncoding.x) << 0u;
|
|
EncodedReprojectionVector |= uint(UnormEncoding.y) << 16u;
|
|
return EncodedReprojectionVector;
|
|
}
|
|
|
|
/** Inverse of EncodeReprojectionVector() */
|
|
float2 DecodeReprojectionVector(uint EncodedReprojectionVector)
|
|
{
|
|
float2 UnormEncoding = float2(uint2(EncodedReprojectionVector, EncodedReprojectionVector >> 16u) & 0xFFFFu);
|
|
|
|
float2 ReprojectionVector = DecodeVelocityFromTexture(float4(UnormEncoding * rcp(65535.0f), 0.0, 0.0)).xy;
|
|
return ReprojectionVector;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------- REPROJECTION's JACOBIAN
|
|
|
|
static const tsr_half kVelocityJacobianRange = tsr_half(2.0);
|
|
//static const tsr_half kVelocityJacobianRange = tsr_half(0.5);
|
|
static const uint kVelocityJacobianBits = 8u;
|
|
|
|
/** Encodes the reprojection's jacobian into 32bits. */
|
|
uint EncodeReprojectionJacobian(tsr_half2x2 ReprojectionJacobian)
|
|
{
|
|
const tsr_half EncodingRange = tsr_half((1u << (kVelocityJacobianBits - 1u)) - 1u);
|
|
const tsr_half EncodingOffset = EncodingRange + tsr_half(0.5);
|
|
const tsr_half EncodingMultiply = EncodingRange / kVelocityJacobianRange;
|
|
|
|
ReprojectionJacobian[0] = clamp(ReprojectionJacobian[0], -kVelocityJacobianRange, kVelocityJacobianRange);
|
|
ReprojectionJacobian[1] = clamp(ReprojectionJacobian[1], -kVelocityJacobianRange, kVelocityJacobianRange);
|
|
|
|
#if 1
|
|
ReprojectionJacobian[0] = tsr_half2(sign(ReprojectionJacobian[0])) * sqrt(abs(ReprojectionJacobian[0])) * sqrt(kVelocityJacobianRange);
|
|
ReprojectionJacobian[1] = tsr_half2(sign(ReprojectionJacobian[1])) * sqrt(abs(ReprojectionJacobian[1])) * sqrt(kVelocityJacobianRange);
|
|
#endif
|
|
|
|
tsr_ushort2x2 DiscreteJacobian = tsr_ushort2x2(EncodingMultiply * ReprojectionJacobian + EncodingOffset);
|
|
uint EncodedReprojectionJacobian = 0u;
|
|
EncodedReprojectionJacobian |= uint(DiscreteJacobian[0][0]) << (0u * kVelocityJacobianBits);
|
|
EncodedReprojectionJacobian |= uint(DiscreteJacobian[0][1]) << (1u * kVelocityJacobianBits);
|
|
EncodedReprojectionJacobian |= uint(DiscreteJacobian[1][0]) << (2u * kVelocityJacobianBits);
|
|
EncodedReprojectionJacobian |= uint(DiscreteJacobian[1][1]) << (3u * kVelocityJacobianBits);
|
|
return EncodedReprojectionJacobian;
|
|
}
|
|
|
|
/** Inverse of EncodeReprojectionJacobian() */
|
|
tsr_half2x2 DecodeReprojectionJacobian(uint EncodedReprojectionJacobian)
|
|
{
|
|
const uint ComponentMask = (1u << kVelocityJacobianBits) - 1u;
|
|
const tsr_half EncodingRange = tsr_half((1u << (kVelocityJacobianBits - 1u)) - 1u);
|
|
const tsr_half DecodingMultiply = kVelocityJacobianRange / EncodingRange;
|
|
|
|
tsr_ushort2x2 DiscreteJacobian;
|
|
DiscreteJacobian[0][0] = tsr_ushort((EncodedReprojectionJacobian >> (0u * kVelocityJacobianBits)) & ComponentMask);
|
|
DiscreteJacobian[0][1] = tsr_ushort((EncodedReprojectionJacobian >> (1u * kVelocityJacobianBits)) & ComponentMask);
|
|
DiscreteJacobian[1][0] = tsr_ushort((EncodedReprojectionJacobian >> (2u * kVelocityJacobianBits)) & ComponentMask);
|
|
DiscreteJacobian[1][1] = tsr_ushort((EncodedReprojectionJacobian >> (3u * kVelocityJacobianBits)) & ComponentMask);
|
|
|
|
tsr_half2x2 ReprojectionJacobian = tsr_half2x2(DiscreteJacobian) * DecodingMultiply - tsr_half(kVelocityJacobianRange);
|
|
|
|
#if 1
|
|
ReprojectionJacobian[0] = ReprojectionJacobian[0] * abs(ReprojectionJacobian[0]) * rcp(kVelocityJacobianRange);
|
|
ReprojectionJacobian[1] = ReprojectionJacobian[1] * abs(ReprojectionJacobian[1]) * rcp(kVelocityJacobianRange);
|
|
#endif
|
|
|
|
return ReprojectionJacobian;
|
|
}
|
|
|
|
/** Estimate upscale ratio of the reprojection jsut from the jacobian. */
|
|
tsr_half ComputeReprojectionUpscaleFactorFromJacobian(tsr_half2x2 ReprojectionJacobian)
|
|
{
|
|
tsr_half2 VectorOffsetE = tsr_half2(1.0, 0.0) + ReprojectionJacobian[0];
|
|
tsr_half2 VectorOffsetS = tsr_half2(0.0, 1.0) + ReprojectionJacobian[1];
|
|
|
|
tsr_half ReprojectionUpscaleFactor = sqrt(max(dot(VectorOffsetE, VectorOffsetE), tsr_half(1.0)) * max(dot(VectorOffsetS, VectorOffsetS), tsr_half(1.0)));
|
|
return ReprojectionUpscaleFactor;
|
|
}
|