Files
UnrealEngine/Engine/Shaders/Private/TemporalSuperResolution/TSRReprojectionField.ush
2025-05-18 13:04:45 +08:00

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;
}