You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
300 lines
12 KiB
Plaintext
300 lines
12 KiB
Plaintext
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PostProcessUpscale.usf: PostProcessing shader to upscale
|
|
=============================================================================*/
|
|
|
|
#include "Common.usf"
|
|
#include "PostProcessCommon.usf"
|
|
#include "PaniniProjection.usf"
|
|
|
|
// only for MainPS
|
|
float UpscaleSoftness;
|
|
|
|
// only for MainVS()
|
|
// .x:HalfFOV .y:tan(HalfFov) .z:CylinderDistortion(0=none, 1:full) .w:Correction to scale Y the same as X is scaled in the center
|
|
float3 PaniniParams;
|
|
|
|
// to avoid compiler errors on the PS
|
|
#ifndef TESS_RECT_X
|
|
#define TESS_RECT_X 1
|
|
#endif
|
|
#ifndef TESS_RECT_Y
|
|
#define TESS_RECT_Y 1
|
|
#endif
|
|
|
|
|
|
float Luma(float3 Color)
|
|
{
|
|
// Rec 709 function for luma.
|
|
return dot(Color, float3(0.2126, 0.7152, 0.0722));
|
|
}
|
|
|
|
float Gaussian(float Scale, float2 Offset)
|
|
{
|
|
return exp2(Scale * dot(Offset, Offset));
|
|
}
|
|
|
|
// Panini projection in the screen pos
|
|
// @param InScreenPos: the position to project in the screen space
|
|
// @return the panini projected postion in screen space
|
|
float2 PaniniProjectionScreenPos(float2 InScreenPos)
|
|
{
|
|
const float d = PaniniParams.x;
|
|
const float s = PaniniParams.y;
|
|
const float OutScreenPosScale = PaniniParams.z;
|
|
#if 0
|
|
const float2 ScreenSpaceToPaniniFactor = tan(0.5 * View.FieldOfViewWideAngles);
|
|
const float2 PaniniToScreenSpaceFactor = 1 / ScreenSpaceToPaniniFactor;
|
|
#else
|
|
const float2 ScreenSpaceToPaniniFactor = GetTanHalfFieldOfView();
|
|
const float2 PaniniToScreenSpaceFactor = GetCotanHalfFieldOfView();
|
|
#endif
|
|
|
|
const float2 PaniniDirection = InScreenPos * ScreenSpaceToPaniniFactor;
|
|
const float2 PaniniPosition = PaniniProjection(PaniniDirection, d, s);
|
|
|
|
// Return the new position back in the screen space frame
|
|
return PaniniPosition * PaniniToScreenSpaceFactor * OutScreenPosScale;
|
|
}
|
|
|
|
|
|
// vertex shader entry point
|
|
void MainVS(
|
|
in uint VertexId : SV_VertexID,
|
|
out float4 OutTexCoord : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
// amount of Quads in X and Y, from GTesselatedScreenRectangleIndexBuffer
|
|
uint2 RectangleTessellation = uint2(TESS_RECT_X, TESS_RECT_Y);
|
|
|
|
float2 TexCoord = float2((uint)fmod(VertexId, (RectangleTessellation.x + 1)), VertexId / (RectangleTessellation.x + 1)) / float2(RectangleTessellation);
|
|
|
|
// still in 0..1 range
|
|
float4 Position = float4(TexCoord.x, TexCoord.y, 0, 1);
|
|
|
|
float2 PlanarScreenPos = TexCoord * 2 - 1;
|
|
|
|
// distort pos
|
|
Position.xy = PaniniProjectionScreenPos(PlanarScreenPos) * 0.5f + 0.5f;
|
|
|
|
DrawRectangle(Position, TexCoord, OutPosition, OutTexCoord.xy);
|
|
OutTexCoord.zw = OutPosition.xy;
|
|
}
|
|
|
|
|
|
void MainPS(float4 UVAndScreenPos : TEXCOORD0, float4 SvPosition : SV_POSITION, out float4 OutColor : SV_Target0)
|
|
{
|
|
#if METHOD == 0
|
|
// Nearest sampling (not blurry but blocky, more for testing)
|
|
OutColor = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UVAndScreenPos.xy, 0, int2(0, 0));
|
|
#endif
|
|
|
|
#if METHOD == 1
|
|
// Bilinear (fast, aliasing)
|
|
float2 UV = UVAndScreenPos.xy;
|
|
OutColor = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV);
|
|
#endif
|
|
|
|
#if METHOD == 2
|
|
// 4 Bilinear samples (good quality)
|
|
float2 UV = UVAndScreenPos.xy;
|
|
float r = UpscaleSoftness;
|
|
OutColor = 0;
|
|
OutColor += Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + float2( -r, -r) * PostprocessInput0Size.zw);
|
|
OutColor += Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + float2( +r, -r) * PostprocessInput0Size.zw);
|
|
OutColor += Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + float2( -r, +r) * PostprocessInput0Size.zw);
|
|
OutColor += Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV + float2( +r, +r) * PostprocessInput0Size.zw);
|
|
OutColor /= 4;
|
|
#endif
|
|
|
|
#if METHOD == 3
|
|
// Directional blur with unsharp mask upsample.
|
|
float2 UV = UVAndScreenPos.xy;
|
|
float X = 0.5;
|
|
float3 ColorNW = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV + float2(-X, -X) * PostprocessInput0Size.zw, 0).rgb;
|
|
float3 ColorNE = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV + float2( X, -X) * PostprocessInput0Size.zw, 0).rgb;
|
|
float3 ColorSW = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV + float2(-X, X) * PostprocessInput0Size.zw, 0).rgb;
|
|
float3 ColorSE = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV + float2( X, X) * PostprocessInput0Size.zw, 0).rgb;
|
|
OutColor.rgb = (ColorNW * 0.25) + (ColorNE * 0.25) + (ColorSW * 0.25) + (ColorSE * 0.25);
|
|
|
|
float LumaNW = Luma(ColorNW);
|
|
float LumaNE = Luma(ColorNE);
|
|
float LumaSW = Luma(ColorSW);
|
|
float LumaSE = Luma(ColorSE);
|
|
LumaNE += 1.0/65536.0;
|
|
|
|
float LumaCC = Luma(OutColor.rgb);
|
|
float UVShift = saturate(LumaCC) * 2.0 - 1.0;
|
|
|
|
float DirSWMinusNE = LumaSW - LumaNE;
|
|
float DirSEMinusNW = LumaSE - LumaNW;
|
|
float2 Dir;
|
|
Dir.x = DirSWMinusNE + DirSEMinusNW;
|
|
Dir.y = DirSWMinusNE - DirSEMinusNW;
|
|
|
|
{
|
|
// minor rendering artifacts when using the distortion feature
|
|
//Dir = normalize(Dir);
|
|
|
|
// fixed these problems
|
|
Dir = Dir * rsqrt(dot(Dir, Dir) + 0.0001f);
|
|
}
|
|
|
|
float2 Dir90 = float2(-Dir.y, Dir.x);
|
|
|
|
UVShift = 1.0 - UVShift;
|
|
UVShift *= UVShift;
|
|
UVShift = 1.0 - UVShift;
|
|
|
|
float2 UVShifted = UV + Dir90 * PostprocessInput0Size.zw * (abs(UVShift) * (-0.125));
|
|
|
|
Dir *= 0.125;
|
|
float3 ColorN = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UVShifted - Dir * PostprocessInput0Size.zw, 0).rgb;
|
|
float3 ColorP = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UVShifted + Dir * PostprocessInput0Size.zw, 0).rgb;
|
|
|
|
float UnsharpMask = 0.25;
|
|
OutColor.rgb = (ColorN + ColorP) * ((UnsharpMask + 1.0) * 0.5) - (OutColor.rgb * UnsharpMask);
|
|
#endif
|
|
|
|
#if 0
|
|
// Traditional gaussian resampling, assuming uniform scaling.
|
|
// This can be sharper and higher quality than the default for minor amounts of up sampling.
|
|
// This can also be used for high quality down-sampling.
|
|
// This is here for future usage.
|
|
|
|
// Find nearest texel manually to work around interpolation problems, then floating point offset.
|
|
float2 TexelUV = UVAndScreenPos.xy * PostprocessInput1Size.xy;
|
|
float2 Texel = floor(TexelUV);
|
|
float2 UV = (Texel + 0.5) * PostprocessInput1Size.zw;
|
|
float2 Offset = (TexelUV - Texel) - 0.5;
|
|
|
|
// Sample pattern (different number of samples are used based on quality level)
|
|
// abc
|
|
// defgh
|
|
// ijklm
|
|
// nopqr
|
|
// stu
|
|
float3 OutColorA = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-1, -2)).rgb;
|
|
float3 OutColorB = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 0, -2)).rgb;
|
|
float3 OutColorC = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 1, -2)).rgb;
|
|
float3 OutColorD = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-2, -1)).rgb;
|
|
float3 OutColorE = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-1, -1)).rgb;
|
|
float3 OutColorF = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 0, -1)).rgb;
|
|
float3 OutColorG = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 1, -1)).rgb;
|
|
float3 OutColorH = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 2, -1)).rgb;
|
|
float3 OutColorI = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-2, 0)).rgb;
|
|
float3 OutColorJ = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-1, 0)).rgb;
|
|
float3 OutColorK = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 0, 0)).rgb;
|
|
float3 OutColorL = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 1, 0)).rgb;
|
|
float3 OutColorM = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 2, 0)).rgb;
|
|
float3 OutColorN = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-2, 1)).rgb;
|
|
float3 OutColorO = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-1, 1)).rgb;
|
|
float3 OutColorP = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 0, 1)).rgb;
|
|
float3 OutColorQ = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 1, 1)).rgb;
|
|
float3 OutColorR = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 2, 1)).rgb;
|
|
float3 OutColorS = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2(-1, 2)).rgb;
|
|
float3 OutColorT = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 0, 2)).rgb;
|
|
float3 OutColorU = PostprocessInput1.SampleLevel(PostprocessInput1Sampler, UV, 0, int2( 1, 2)).rgb;
|
|
|
|
// Sharpness
|
|
float Scale = rcp(UpscaleSoftness);
|
|
Scale = rcp(0.25);
|
|
Scale = -0.25 * Scale * Scale;
|
|
|
|
// Filter weights
|
|
float WeightA = Gaussian(Scale, Offset - float2(-1.0, -2.0));
|
|
float WeightB = Gaussian(Scale, Offset - float2( 0.0, -2.0));
|
|
float WeightC = Gaussian(Scale, Offset - float2( 1.0, -2.0));
|
|
float WeightD = Gaussian(Scale, Offset - float2(-2.0, -1.0));
|
|
float WeightE = Gaussian(Scale, Offset - float2(-1.0, -1.0));
|
|
float WeightF = Gaussian(Scale, Offset - float2( 0.0, -1.0));
|
|
float WeightG = Gaussian(Scale, Offset - float2( 1.0, -1.0));
|
|
float WeightH = Gaussian(Scale, Offset - float2( 2.0, -1.0));
|
|
float WeightI = Gaussian(Scale, Offset - float2(-2.0, 0.0));
|
|
float WeightJ = Gaussian(Scale, Offset - float2(-1.0, 0.0));
|
|
float WeightK = Gaussian(Scale, Offset - float2( 0.0, 0.0));
|
|
float WeightL = Gaussian(Scale, Offset - float2( 1.0, 0.0));
|
|
float WeightM = Gaussian(Scale, Offset - float2( 2.0, 0.0));
|
|
float WeightN = Gaussian(Scale, Offset - float2(-2.0, 1.0));
|
|
float WeightO = Gaussian(Scale, Offset - float2(-1.0, 1.0));
|
|
float WeightP = Gaussian(Scale, Offset - float2( 0.0, 1.0));
|
|
float WeightQ = Gaussian(Scale, Offset - float2( 1.0, 1.0));
|
|
float WeightR = Gaussian(Scale, Offset - float2( 2.0, 1.0));
|
|
float WeightS = Gaussian(Scale, Offset - float2(-1.0, 2.0));
|
|
float WeightT = Gaussian(Scale, Offset - float2( 0.0, 2.0));
|
|
float WeightU = Gaussian(Scale, Offset - float2( 1.0, 2.0));
|
|
|
|
#define UPSCALE_QUALITY 2
|
|
|
|
// Filtering at different quality levels
|
|
// 9 taps
|
|
#if (UPSCALE_QUALITY == 1)
|
|
OutColor.rgb = (
|
|
OutColorE * WeightE + OutColorF * WeightF + OutColorG * WeightG +
|
|
OutColorJ * WeightJ + OutColorK * WeightK + OutColorL * WeightL +
|
|
OutColorO * WeightO + OutColorP * WeightP + OutColorQ * WeightQ
|
|
) * rcp(
|
|
WeightE + WeightF + WeightG +
|
|
WeightJ + WeightK + WeightL +
|
|
WeightO + WeightP + WeightQ
|
|
);
|
|
#endif
|
|
|
|
// 13 taps
|
|
#if (UPSCALE_QUALITY == 2)
|
|
OutColor.rgb = (
|
|
OutColorB * WeightB +
|
|
OutColorE * WeightE + OutColorF * WeightF + OutColorG * WeightG +
|
|
OutColorI * WeightI + OutColorJ * WeightJ + OutColorK * WeightK + OutColorL * WeightL + OutColorM * WeightM +
|
|
OutColorO * WeightO + OutColorP * WeightP + OutColorQ * WeightQ +
|
|
OutColorT * WeightT
|
|
) * rcp(
|
|
WeightB +
|
|
WeightE + WeightF + WeightG +
|
|
WeightI + WeightJ + WeightK + WeightL + WeightM +
|
|
WeightO + WeightP + WeightQ +
|
|
WeightT
|
|
);
|
|
#endif
|
|
|
|
// 21 taps
|
|
#if (UPSCALE_QUALITY == 3)
|
|
OutColor.rgb = (
|
|
OutColorA * WeightA + OutColorB * WeightB + OutColorC * WeightC +
|
|
OutColorD * WeightD + OutColorE * WeightE + OutColorF * WeightF + OutColorG * WeightG + OutColorH * WeightH +
|
|
OutColorI * WeightI + OutColorJ * WeightJ + OutColorK * WeightK + OutColorL * WeightL + OutColorM * WeightM +
|
|
OutColorN * WeightN + OutColorO * WeightO + OutColorP * WeightP + OutColorQ * WeightQ + OutColorR * WeightR +
|
|
OutColorS * WeightS + OutColorT * WeightT + OutColorU * WeightU
|
|
) * rcp(
|
|
WeightA + WeightB + WeightC +
|
|
WeightD + WeightE + WeightF + WeightG + WeightH +
|
|
WeightI + WeightJ + WeightK + WeightL + WeightM +
|
|
WeightN + WeightO + WeightP + WeightQ + WeightR +
|
|
WeightS + WeightT + WeightU
|
|
);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
// Horz scan line pattern.
|
|
float Base = 0.25;
|
|
OutColor.rgb *= Base + frac(SvPosition.y * 0.5);
|
|
#endif
|
|
|
|
#if 0
|
|
// TV pattern.
|
|
float T;
|
|
float Base = 0.25;
|
|
T = frac((SvPosition.x + 0.0) * 0.5 + (SvPosition.y + 0.0) * 0.25);
|
|
OutColor.r *= Base + T;
|
|
T = frac((SvPosition.x + 0.0) * 0.5 + (SvPosition.y + 1.0) * 0.25);
|
|
OutColor.g *= Base + T;
|
|
T = frac((SvPosition.x + 0.0) * 0.5 + (SvPosition.y + 2.0) * 0.25);
|
|
OutColor.b *= Base + T;
|
|
#endif
|
|
|
|
}
|