You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
1148 lines
39 KiB
Plaintext
1148 lines
39 KiB
Plaintext
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PostProcessMobile.usf: Combined {bloom, sunshafts, depth of field}
|
|
=============================================================================*/
|
|
|
|
#include "Common.usf"
|
|
#include "PostProcessCommon.usf"
|
|
|
|
// Point on circle.
|
|
float2 Circle(float Start, float Points, float Point)
|
|
{
|
|
float Rad = (3.141592 * 2.0 * (1.0 / Points)) * (Point + Start);
|
|
return float2(sin(Rad), cos(Rad));
|
|
}
|
|
|
|
// x:BloomThreshold, yz:unused, w:ExposureScale (useful if eyeadaptation is locked)
|
|
float4 BloomThreshold;
|
|
|
|
half FocusDistFar()
|
|
{
|
|
return View.DepthOfFieldFocalDistance + View.DepthOfFieldFocalRegion;
|
|
}
|
|
|
|
half FocusDistNear()
|
|
{
|
|
return View.DepthOfFieldFocalDistance;
|
|
}
|
|
|
|
// Alpha = 0.5 is full size, >0.5 rate at which near and far hit maximum.
|
|
float4 SunColorApertureDiv2;
|
|
|
|
// Returns 0=max near DOF, 0.5=in focus, 1.0=max far DOF
|
|
half Coc(half Depth)
|
|
{
|
|
half FocusDist = clamp(Depth,half(FocusDistNear()),half(FocusDistFar()));
|
|
half CocValue = ((Depth - FocusDist) / Depth);
|
|
return saturate(CocValue * SunColorApertureDiv2.a + 0.5);
|
|
}
|
|
|
|
half2 SunConstDepthMaskScaleBias()
|
|
{
|
|
half DepthMin = 65504.0 - 16384.0;
|
|
half DepthMax = 65504.0 - 0.0;
|
|
// Compute scale and bias.
|
|
half Scale = 1.0/(DepthMax-DepthMin);
|
|
return half2(Scale,-DepthMin * Scale);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Convert depth in alpha into combined circle of confusion and sun intensity.
|
|
// Or pre-tonemap before hardware box-filtered resolve.
|
|
//
|
|
|
|
void SunMaskVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float4 OutUVPos : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, OutUVPos.xy);
|
|
OutUVPos.zw = OutPosition.xy;
|
|
}
|
|
|
|
void SunMaskPS_ES2(
|
|
float4 InUVPos : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
#if (COMPILER_GLSL_ES2 && ES2_USE_FETCH) || METAL_PROFILE
|
|
OutColor = FramebufferFetchES2();
|
|
#else
|
|
OutColor = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVPos.xy);
|
|
#endif
|
|
|
|
#if ES2_USE_MSAA
|
|
// On-chip pre-tonemap before MSAA resolve.
|
|
OutColor.rgb *= rcp(OutColor.r*0.299 + OutColor.g*0.587 + OutColor.b*0.114 + 1.0);
|
|
#else
|
|
half InDepth = OutColor.a;
|
|
|
|
#if ES2_USE_SUN
|
|
half2 DepthMaskScaleBias = SunConstDepthMaskScaleBias();
|
|
half FarAmount = saturate(InDepth * DepthMaskScaleBias.x + DepthMaskScaleBias.y);
|
|
half3 SunAmount = OutColor.rgb * SunColorApertureDiv2.rgb;
|
|
|
|
half2 Pos = InUVPos.zw * 0.5 + 0.5;
|
|
half EdgeMask = 1.0f - Pos.x * (1.0f - Pos.x) * Pos.y * (1.0f - Pos.y) * 8.0f;
|
|
EdgeMask = EdgeMask * EdgeMask;
|
|
|
|
FarAmount *= 1.0-EdgeMask;
|
|
|
|
OutColor.a = min(min(SunAmount.r, SunAmount.g), SunAmount.b) * FarAmount;
|
|
#else
|
|
OutColor.a = 0.0;
|
|
#endif
|
|
|
|
#if ES2_USE_DOF
|
|
OutColor.a += Coc(InDepth);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Bloom Setup - Mask Bloom and Downsample 1/16 Area
|
|
//
|
|
|
|
void BloomVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoords[4] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
float2 TransformedUV;
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, TransformedUV);
|
|
|
|
OutTexCoords[0] = TransformedUV + PostprocessInput0Size.zw * float2(-1, -1);
|
|
OutTexCoords[1] = TransformedUV + PostprocessInput0Size.zw * float2( 1, -1);
|
|
OutTexCoords[2] = TransformedUV + PostprocessInput0Size.zw * float2(-1, 1);
|
|
OutTexCoords[3] = TransformedUV + PostprocessInput0Size.zw * float2( 1, 1);
|
|
}
|
|
|
|
void BloomPS_ES2(
|
|
float2 InUVs[4] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
half4 C0 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0]);
|
|
half4 C1 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1]);
|
|
half4 C2 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2]);
|
|
half4 C3 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3]);
|
|
|
|
// Output color is average.
|
|
OutColor.rgb = (C0.rgb * 0.25) + (C1.rgb * 0.25) + (C2.rgb * 0.25) + (C3.rgb * 0.25);
|
|
|
|
#if ES2_USE_MSAA
|
|
// This should really happen before the average, instead doing after average as optimization.
|
|
OutColor.rgb *= rcp(OutColor.r*(-0.299) + OutColor.g*(-0.587) + OutColor.b*(-0.114) + 1.0);
|
|
#endif
|
|
|
|
// Try to kill negatives and NaNs here
|
|
OutColor.rgb = max(OutColor.rgb, 0);
|
|
|
|
// Trim bloom and sunshafts black level.
|
|
half TotalLuminance = Luminance(OutColor.rgb);
|
|
half BloomLuminance = TotalLuminance - BloomThreshold.x;
|
|
half Amount = saturate(BloomLuminance * 0.5f);
|
|
OutColor.rgb *= Amount;
|
|
|
|
// In the case of both DOF and SUN,
|
|
// Split out alpha back into dual components (circle of confusion size and sun amount).
|
|
// Expand {near to in-focus} {0.0 to 0.5} to {0.0 to 1.0} for near DOF diolation.
|
|
// Must keep 1.0 the in-focus here (sunshaft pass will use this data).
|
|
|
|
#if ES2_USE_DOF
|
|
// Expand {near to in-focus} {0.0 to 0.5} to {0.0 to 1.0} for near DOF diolation.
|
|
// Must keep 1.0 the in-focus here (sunshaft pass will use this data).
|
|
half Coc0 = saturate(C0.a*2.0);
|
|
half Coc1 = saturate(C1.a*2.0);
|
|
half Coc2 = saturate(C2.a*2.0);
|
|
half Coc3 = saturate(C3.a*2.0);
|
|
|
|
// Take min of COC (which is maximum near radius).
|
|
OutColor.a = min(min(Coc0,Coc1),min(Coc2,Coc3));
|
|
|
|
// Improve the quality of near diolation.
|
|
OutColor.a = 1.0 - OutColor.a;
|
|
OutColor.a *= OutColor.a;
|
|
OutColor.a = 1.0 - OutColor.a;
|
|
#else
|
|
OutColor.a = 0.0;
|
|
#endif
|
|
|
|
#if ES2_USE_SUN
|
|
half Sun0 = max(0.0, C0.a-1.0);
|
|
half Sun1 = max(0.0, C1.a-1.0);
|
|
half Sun2 = max(0.0, C2.a-1.0);
|
|
half Sun3 = max(0.0, C3.a-1.0);
|
|
|
|
// Take average of sun intensity and adjust by bloom threshold.
|
|
Amount *= 0.25;
|
|
OutColor.a += (Sun0 * Amount) + (Sun1 * Amount) + (Sun2 * Amount) + (Sun3 * Amount);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Bloom Setup Small - Downsample 1/16 Area
|
|
//
|
|
|
|
void BloomSmallVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float4 OutTexCoords[8] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
float Start = 2.0/14.0;
|
|
float Scale = 0.66 * 4.0 * 2.0;
|
|
|
|
OutTexCoords[0].xy = InTexCoord.xy;
|
|
OutTexCoords[0].zw = InTexCoord.xy + Circle(Start, 14.0, 0.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1].xy = InTexCoord.xy + Circle(Start, 14.0, 1.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1].zw = InTexCoord.xy + Circle(Start, 14.0, 2.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2].xy = InTexCoord.xy + Circle(Start, 14.0, 3.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2].zw = InTexCoord.xy + Circle(Start, 14.0, 4.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[3].xy = InTexCoord.xy + Circle(Start, 14.0, 5.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[3].zw = InTexCoord.xy + Circle(Start, 14.0, 6.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[4].xy = InTexCoord.xy + Circle(Start, 14.0, 7.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[4].zw = InTexCoord.xy + Circle(Start, 14.0, 8.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[5].xy = InTexCoord.xy + Circle(Start, 14.0, 9.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[5].zw = InTexCoord.xy + Circle(Start, 14.0, 10.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[6].xy = InTexCoord.xy + Circle(Start, 14.0, 11.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[6].zw = InTexCoord.xy + Circle(Start, 14.0, 12.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[7].xy = InTexCoord.xy + Circle(Start, 14.0, 13.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[7].zw = float2(0.0, 0.0);
|
|
}
|
|
|
|
void BloomSmallPS_ES2(
|
|
float4 InUVs[8] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
half3 N0 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].xy).rgb;
|
|
half3 N1 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].zw).rgb;
|
|
half3 N2 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].xy).rgb;
|
|
half3 N3 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].zw).rgb;
|
|
half3 N4 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].xy).rgb;
|
|
half3 N5 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].zw).rgb;
|
|
half3 N6 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].xy).rgb;
|
|
half3 N7 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].zw).rgb;
|
|
half3 N8 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4].xy).rgb;
|
|
half3 N9 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4].zw).rgb;
|
|
half3 N10 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5].xy).rgb;
|
|
half3 N11 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5].zw).rgb;
|
|
half3 N12 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6].xy).rgb;
|
|
half3 N13 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6].zw).rgb;
|
|
half3 N14 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[7].xy).rgb;
|
|
|
|
half W = 1.0/15.0;
|
|
OutColor.rgb =
|
|
(N0 * W) +
|
|
(N1 * W) +
|
|
(N2 * W) +
|
|
(N3 * W) +
|
|
(N4 * W) +
|
|
(N5 * W) +
|
|
(N6 * W) +
|
|
(N7 * W) +
|
|
(N8 * W) +
|
|
(N9 * W) +
|
|
(N10 * W) +
|
|
(N11 * W) +
|
|
(N12 * W) +
|
|
(N13 * W) +
|
|
(N14 * W);
|
|
|
|
// Trim bloom black level.
|
|
half TotalLuminance = Luminance(OutColor.rgb);
|
|
half BloomLuminance = TotalLuminance - BloomThreshold.x;
|
|
half Amount = saturate(BloomLuminance * 0.5f);
|
|
OutColor.rgb *= Amount;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Bloom Downsample
|
|
//
|
|
|
|
float BloomDownScale;
|
|
|
|
void BloomDownVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float4 OutTexCoords[8] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
float Start = 2.0/14.0;
|
|
float Scale = BloomDownScale;
|
|
|
|
OutTexCoords[0].xy = InTexCoord.xy;
|
|
OutTexCoords[0].zw = InTexCoord.xy + Circle(Start, 14.0, 0.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1].xy = InTexCoord.xy + Circle(Start, 14.0, 1.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1].zw = InTexCoord.xy + Circle(Start, 14.0, 2.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2].xy = InTexCoord.xy + Circle(Start, 14.0, 3.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2].zw = InTexCoord.xy + Circle(Start, 14.0, 4.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[3].xy = InTexCoord.xy + Circle(Start, 14.0, 5.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[3].zw = InTexCoord.xy + Circle(Start, 14.0, 6.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[4].xy = InTexCoord.xy + Circle(Start, 14.0, 7.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[4].zw = InTexCoord.xy + Circle(Start, 14.0, 8.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[5].xy = InTexCoord.xy + Circle(Start, 14.0, 9.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[5].zw = InTexCoord.xy + Circle(Start, 14.0, 10.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[6].xy = InTexCoord.xy + Circle(Start, 14.0, 11.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[6].zw = InTexCoord.xy + Circle(Start, 14.0, 12.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[7].xy = InTexCoord.xy + Circle(Start, 14.0, 13.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[7].zw = float2(0.0, 0.0);
|
|
}
|
|
|
|
void BloomDownPS_ES2(
|
|
float4 InUVs[8] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
half3 N0 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].xy).rgb;
|
|
half3 N1 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].zw).rgb;
|
|
half3 N2 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].xy).rgb;
|
|
half3 N3 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].zw).rgb;
|
|
half3 N4 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].xy).rgb;
|
|
half3 N5 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].zw).rgb;
|
|
half3 N6 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].xy).rgb;
|
|
half3 N7 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].zw).rgb;
|
|
half3 N8 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4].xy).rgb;
|
|
half3 N9 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4].zw).rgb;
|
|
half3 N10 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5].xy).rgb;
|
|
half3 N11 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5].zw).rgb;
|
|
half3 N12 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6].xy).rgb;
|
|
half3 N13 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6].zw).rgb;
|
|
half3 N14 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[7].xy).rgb;
|
|
|
|
half W = 1.0/15.0;
|
|
OutColor.rgb =
|
|
(N0 * W) +
|
|
(N1 * W) +
|
|
(N2 * W) +
|
|
(N3 * W) +
|
|
(N4 * W) +
|
|
(N5 * W) +
|
|
(N6 * W) +
|
|
(N7 * W) +
|
|
(N8 * W) +
|
|
(N9 * W) +
|
|
(N10 * W) +
|
|
(N11 * W) +
|
|
(N12 * W) +
|
|
(N13 * W) +
|
|
(N14 * W);
|
|
}
|
|
|
|
|
|
//
|
|
// Bloom Upsample
|
|
//
|
|
|
|
float2 BloomUpScales;
|
|
|
|
void BloomUpVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float4 OutTexCoords[8] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
float Start;
|
|
float Scale;
|
|
|
|
Start = 2.0/7.0;
|
|
Scale = BloomUpScales.x;
|
|
|
|
|
|
OutTexCoords[0].xy = InTexCoord.xy + Circle(Start, 7.0, 0.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[0].zw = InTexCoord.xy + Circle(Start, 7.0, 1.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1].xy = InTexCoord.xy + Circle(Start, 7.0, 2.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1].zw = InTexCoord.xy + Circle(Start, 7.0, 3.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2].xy = InTexCoord.xy + Circle(Start, 7.0, 4.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2].zw = InTexCoord.xy + Circle(Start, 7.0, 5.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[3].xy = InTexCoord.xy + Circle(Start, 7.0, 6.0) * Scale * PostprocessInput0Size.zw;
|
|
|
|
OutTexCoords[3].zw = InTexCoord.xy;
|
|
|
|
Start = 2.0/7.0;
|
|
Scale = BloomUpScales.y;
|
|
|
|
OutTexCoords[4].xy = InTexCoord.xy + Circle(Start, 7.0, 0.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[4].zw = InTexCoord.xy + Circle(Start, 7.0, 1.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[5].xy = InTexCoord.xy + Circle(Start, 7.0, 2.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[5].zw = InTexCoord.xy + Circle(Start, 7.0, 3.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[6].xy = InTexCoord.xy + Circle(Start, 7.0, 4.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[6].zw = InTexCoord.xy + Circle(Start, 7.0, 5.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[7].xy = InTexCoord.xy + Circle(Start, 7.0, 6.0) * Scale * PostprocessInput1Size.zw;
|
|
OutTexCoords[7].zw = float2(0.0, 0.0);
|
|
}
|
|
|
|
float4 BloomTintA;
|
|
float4 BloomTintB;
|
|
|
|
void BloomUpPS_ES2(
|
|
float4 InUVs[8] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
half3 A0 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].xy).rgb;
|
|
half3 A1 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].zw).rgb;
|
|
half3 A2 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].xy).rgb;
|
|
half3 A3 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].zw).rgb;
|
|
half3 A4 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].xy).rgb;
|
|
half3 A5 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].zw).rgb;
|
|
half3 A6 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].xy).rgb;
|
|
half3 A7 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].zw).rgb;
|
|
|
|
half3 B0 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[3].zw).rgb;
|
|
half3 B1 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[4].xy).rgb;
|
|
half3 B2 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[4].zw).rgb;
|
|
half3 B3 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[5].xy).rgb;
|
|
half3 B4 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[5].zw).rgb;
|
|
half3 B5 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[6].xy).rgb;
|
|
half3 B6 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[6].zw).rgb;
|
|
half3 B7 = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[7].xy).rgb;
|
|
|
|
// A is the same size source.
|
|
half3 WA = BloomTintA.rgb;
|
|
// B is the upsampled source.
|
|
half3 WB = BloomTintB.rgb;
|
|
|
|
OutColor.rgb =
|
|
A0 * WA +
|
|
A1 * WA +
|
|
A2 * WA +
|
|
A3 * WA +
|
|
A4 * WA +
|
|
A5 * WA +
|
|
A6 * WA +
|
|
A7 * WA +
|
|
B0 * WB +
|
|
B1 * WB +
|
|
B2 * WB +
|
|
B3 * WB +
|
|
B4 * WB +
|
|
B5 * WB +
|
|
B6 * WB +
|
|
B7 * WB;
|
|
}
|
|
|
|
|
|
//
|
|
// Near Setup - Generate near diolation for DOF.
|
|
//
|
|
|
|
void DofNearVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoords2 : TEXCOORD0,
|
|
out float4 OutTexCoords4[4] : TEXCOORD1,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
OutTexCoords2 = InTexCoord;
|
|
OutTexCoords4[0].xy = InTexCoord + PostprocessInput0Size.zw * float2(-0.5,-1.0);
|
|
OutTexCoords4[0].zw = InTexCoord + PostprocessInput0Size.zw * float2( 1.0,-0.5);
|
|
OutTexCoords4[1].xy = InTexCoord + PostprocessInput0Size.zw * float2( 0.5, 1.0);
|
|
OutTexCoords4[1].zw = InTexCoord + PostprocessInput0Size.zw * float2(-1.0, 0.5);
|
|
OutTexCoords4[2].xy = InTexCoord + PostprocessInput0Size.zw * float2( 0.5,-1.0);
|
|
OutTexCoords4[2].zw = InTexCoord + PostprocessInput0Size.zw * float2( 1.0, 0.5);
|
|
OutTexCoords4[3].xy = InTexCoord + PostprocessInput0Size.zw * float2(-0.5, 1.0);
|
|
OutTexCoords4[3].zw = InTexCoord + PostprocessInput0Size.zw * float2(-1.0,-0.5);
|
|
}
|
|
|
|
void DofNearPS_ES2(
|
|
float2 InUVs2 : TEXCOORD0,
|
|
float4 InUVs[4] : TEXCOORD1,
|
|
out half OutColor : SV_Target0
|
|
)
|
|
{
|
|
half N0 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs2).a;
|
|
half N1 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].xy).a;
|
|
half N2 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].zw).a;
|
|
half N3 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].xy).a;
|
|
half N4 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].zw).a;
|
|
half N5 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].xy).a;
|
|
half N6 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].zw).a;
|
|
half N7 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].xy).a;
|
|
half N8 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].zw).a;
|
|
|
|
// Remove sunshaft intensity component and reverse.
|
|
#if ES2_USE_SUN
|
|
N0 = saturate(1.0 - N0);
|
|
N1 = saturate(1.0 - N1);
|
|
N2 = saturate(1.0 - N2);
|
|
N3 = saturate(1.0 - N3);
|
|
N4 = saturate(1.0 - N4);
|
|
N5 = saturate(1.0 - N5);
|
|
N6 = saturate(1.0 - N6);
|
|
N7 = saturate(1.0 - N7);
|
|
N8 = saturate(1.0 - N8);
|
|
#else
|
|
// If no sun-shafts then don't need the saturate.
|
|
N0 = 1.0 - N0;
|
|
N1 = 1.0 - N1;
|
|
N2 = 1.0 - N2;
|
|
N3 = 1.0 - N3;
|
|
N4 = 1.0 - N4;
|
|
N5 = 1.0 - N5;
|
|
N6 = 1.0 - N6;
|
|
N7 = 1.0 - N7;
|
|
N8 = 1.0 - N8;
|
|
#endif
|
|
|
|
// The first sample is 1/4 the size as the rest of the samples.
|
|
OutColor = (N0 * 0.25 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8) / 8.25;
|
|
if(OutColor > 0.0) OutColor = sqrt(OutColor);
|
|
}
|
|
|
|
|
|
//
|
|
// DOF Setup - Downsample to 1/4 area
|
|
//
|
|
|
|
|
|
|
|
void DofDownVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoords[5] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
// Near position fixed to use UV based out output position.
|
|
OutTexCoords[0] = OutPosition.xy * float2(0.5,-0.5) + 0.5;
|
|
// Other source UVs based on possible non-full texture.
|
|
OutTexCoords[1] = InTexCoord + PostprocessInput0Size.zw * float2(-0.5, -0.5);
|
|
OutTexCoords[2] = InTexCoord + PostprocessInput0Size.zw * float2( 0.5, -0.5);
|
|
OutTexCoords[3] = InTexCoord + PostprocessInput0Size.zw * float2(-0.5, 0.5);
|
|
OutTexCoords[4] = InTexCoord + PostprocessInput0Size.zw * float2( 0.5, 0.5);
|
|
}
|
|
|
|
void DofDownPS_ES2(
|
|
float2 InUVs[5] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
// This shader needs float precision to work.
|
|
|
|
// Fetch near diolation and scale to (0 to 16384.0) range.
|
|
float N = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[0]).r * 16384.0;
|
|
|
|
float4 A = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1]);
|
|
float4 B = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2]);
|
|
float4 C = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3]);
|
|
float4 D = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4]);
|
|
|
|
#if ES2_USE_SUN
|
|
// The {0.0 to 1.0} range is focus.
|
|
// The {1.0 to 65504.0} range is light shaft source intensity (always at fully out of focus).
|
|
// Must clamp back to {0.0 to 1.0} range.
|
|
A.a = min(1.0, A.a);
|
|
B.a = min(1.0, B.a);
|
|
C.a = min(1.0, C.a);
|
|
D.a = min(1.0, D.a);
|
|
#endif
|
|
|
|
// To support near DOF the {0.0 to 1.0} maps to {-16384.0 to 16384.0}.
|
|
A.a = A.a * (2.0 * 16384.0) - 16384.0;
|
|
B.a = B.a * (2.0 * 16384.0) - 16384.0;
|
|
C.a = C.a * (2.0 * 16384.0) - 16384.0;
|
|
D.a = D.a * (2.0 * 16384.0) - 16384.0;
|
|
|
|
// Make sure there are no zeros.
|
|
// Alpha ends up as circle of confusion size.
|
|
// Near diolation factor applied here.
|
|
// The 1/8 factor is to workaround mobile hardware lack of precision.
|
|
A.a = max(N, abs(A.a) + 1.0/8.0);
|
|
B.a = max(N, abs(B.a) + 1.0/8.0);
|
|
C.a = max(N, abs(C.a) + 1.0/8.0);
|
|
D.a = max(N, abs(D.a) + 1.0/8.0);
|
|
|
|
// Mix weighted by circle of confusion.
|
|
// This tends to erode the effect of more infocus samples (removes bleeding artifacts).
|
|
OutColor = ((A * A.a) + (B * B.a) + (C * C.a) + (D * D.a)) * rcp(A.a + B.a + C.a + D.a);
|
|
OutColor.rgb *= OutColor.a;
|
|
}
|
|
|
|
|
|
//
|
|
// DOF Blur
|
|
//
|
|
|
|
// DOF BOKEH SAMPLING PATTERN
|
|
// --------------------
|
|
// # = bilinear tap
|
|
// * = the single point tap to get the current pixel
|
|
//
|
|
// 1 1
|
|
// 4 4 1 * 2 2
|
|
// 4 4 3 3 2 2
|
|
// 3 3
|
|
//
|
|
// This pattern is very important.
|
|
// All bilinear taps are not always exactly in the middle of 4 texels.
|
|
// It is an asymetric pattern (minimize overlap, allow for different radii).
|
|
#define DOF_1 half2(-0.500, 0.50)
|
|
#define DOF_2 half2( 0.75,-0.50)
|
|
#define DOF_3 half2(-0.500,-1.25)
|
|
#define DOF_4 half2(-1.75,-0.50)
|
|
|
|
|
|
|
|
// This will compute a constant half2 from a constant half2.
|
|
// This computes the soft blend factor for intersection test
|
|
// (does circle of confusion intersect pixel center).
|
|
// Large feather here to make transitions smooth with a few samples.
|
|
half2 DofIntersectionScaleBias(half2 Offset)
|
|
{
|
|
// Working in distance squared.
|
|
// Normalize by maximum distance
|
|
half RcpMaxDst = rcp(sqrt(dot(DOF_4, DOF_4)));
|
|
half Dst0 = sqrt(dot(DOF_1, DOF_1));
|
|
half Dst1 = sqrt(dot(Offset, Offset));
|
|
Dst0 = max(Dst0, Dst1 - 0.25);
|
|
Dst0 *= RcpMaxDst;
|
|
Dst1 *= RcpMaxDst;
|
|
half Scale = 1.0/(Dst1 - Dst0);
|
|
half Bias = (-Dst0) * Scale;
|
|
return half2(Scale, Bias);
|
|
}
|
|
|
|
half DofIntersect(half CocTap, half2 Offset)
|
|
{
|
|
half2 ConstScaleBias = DofIntersectionScaleBias(Offset);
|
|
// Undo the scale factor.
|
|
ConstScaleBias.x *= 1.0/16384.0;
|
|
return saturate(CocTap * ConstScaleBias.x + ConstScaleBias.y);
|
|
}
|
|
|
|
half DofWeight(half Coc)
|
|
{
|
|
half Dst0 = sqrt(dot(DOF_3, DOF_3)) / sqrt(dot(DOF_4, DOF_4));
|
|
half Dst1 = sqrt(dot(DOF_4, DOF_4)) / sqrt(dot(DOF_4, DOF_4));
|
|
half Scale = 1.0/(Dst1 - Dst0);
|
|
half Bias = (-Dst0) * Scale;
|
|
// Undo the 16384.0 scale factor in this constant.
|
|
Scale *= 1.0/16384.0;
|
|
// Scale and Bias should be compile time constants.
|
|
return saturate(Coc * Scale + Bias);
|
|
}
|
|
|
|
void DofBlurVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoords[5] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
OutTexCoords[0] = InTexCoord.xy;
|
|
OutTexCoords[1] = InTexCoord.xy + float2(DOF_1) * PostprocessInput0Size.zw;
|
|
OutTexCoords[2] = InTexCoord.xy + float2(DOF_2) * PostprocessInput0Size.zw;
|
|
OutTexCoords[3] = InTexCoord.xy + float2(DOF_3) * PostprocessInput0Size.zw;
|
|
OutTexCoords[4] = InTexCoord.xy + float2(DOF_4) * PostprocessInput0Size.zw;
|
|
}
|
|
|
|
void DofBlurPS_ES2(
|
|
float2 InUVs[5] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
// Near diolation size is copied into alpha for the tonemapper pass.
|
|
OutColor.a = PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[0]).r;
|
|
|
|
half4 C1 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1]);
|
|
half4 C2 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2]);
|
|
half4 C3 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3]);
|
|
half4 C4 = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4]);
|
|
|
|
// Restore color (colors are weighted by CoC to help remove bleeding).
|
|
C1.rgb *= rcp(C1.a);
|
|
C2.rgb *= rcp(C2.a);
|
|
C3.rgb *= rcp(C3.a);
|
|
C4.rgb *= rcp(C4.a);
|
|
|
|
// First bilinear tap always has 1.0 weight, the rest are weighted.
|
|
half W1 = 1.0, W2, W3, W4;
|
|
W2 = W3 = W4 = DofWeight(C1.a);
|
|
|
|
// Remove contribution of taps who's circle of confusion does not intersect the pixel.
|
|
W2 *= DofIntersect(C2.a, DOF_2);
|
|
W3 *= DofIntersect(C3.a, DOF_3);
|
|
W4 *= DofIntersect(C4.a, DOF_4);
|
|
|
|
OutColor.rgb = ((C1.rgb * W1) + (C2.rgb * W2) + (C3.rgb * W3) + (C4.rgb * W4)) * rcp(W1 + W2 + W3 + W4);
|
|
}
|
|
|
|
|
|
//
|
|
// First sun shaft blur and move sun intensity from alpha to single channel output.
|
|
//
|
|
|
|
half HighlightCompression(half Channel)
|
|
{
|
|
return Channel * rcp(1.0 + Channel);
|
|
}
|
|
|
|
half HighlightDecompression(half Channel)
|
|
{
|
|
return Channel * rcp(1.0 - Channel);
|
|
}
|
|
|
|
|
|
// Convert from [-1 to 1] to view rectangle in texture which is somewhere in [0 to 1].
|
|
float2 SunShaftPosToUV(float2 Pos)
|
|
{
|
|
// return (Pos.xy * ScreenPosToPixel.xy + ScreenPosToPixel.zw + 0.5f) * PostprocessInput0Size.zw;
|
|
return Pos.xy * float2(0.5,-0.5) + 0.5;
|
|
}
|
|
|
|
// Center of light shaft.
|
|
float4 LightShaftCenter;
|
|
|
|
// Position in {-1 to 1} space.
|
|
float2 SunPos()
|
|
{
|
|
return LightShaftCenter.xy;
|
|
}
|
|
|
|
float2 SunShaftRect(float2 InPosition, float amount)
|
|
{
|
|
float2 center = SunPos();
|
|
return SunShaftPosToUV(lerp(center, InPosition, amount));
|
|
}
|
|
|
|
// Positions for sun shaft steps.
|
|
// The very tight first position makes direct light to eye bloom a little.
|
|
// Otherwise want even spacing.
|
|
#define SUN_P0 (31.0/32.0)
|
|
#define SUN_P1 (27.0/32.0)
|
|
#define SUN_P2 (23.0/32.0)
|
|
#define SUN_P3 (19.0/32.0)
|
|
#define SUN_P4 (15.0/32.0)
|
|
#define SUN_P5 (11.0/32.0)
|
|
#define SUN_P6 (7.0/32.0)
|
|
// SUN_P7 is fixed at zero.
|
|
|
|
#define SUN_M 1.0
|
|
|
|
void SunAlphaVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoords[8] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
OutTexCoords[0] = SunShaftRect(InPosition.xy, 1.0 - SUN_P0 * SUN_M);
|
|
OutTexCoords[1] = SunShaftRect(InPosition.xy, 1.0 - SUN_P1 * SUN_M);
|
|
OutTexCoords[2] = SunShaftRect(InPosition.xy, 1.0 - SUN_P2 * SUN_M);
|
|
OutTexCoords[3] = SunShaftRect(InPosition.xy, 1.0 - SUN_P3 * SUN_M);
|
|
OutTexCoords[4] = SunShaftRect(InPosition.xy, 1.0 - SUN_P4 * SUN_M);
|
|
OutTexCoords[5] = SunShaftRect(InPosition.xy, 1.0 - SUN_P5 * SUN_M);
|
|
OutTexCoords[6] = SunShaftRect(InPosition.xy, 1.0 - SUN_P6 * SUN_M);
|
|
OutTexCoords[7] = InTexCoord.xy;
|
|
}
|
|
|
|
#undef SUN_M
|
|
|
|
// Remove the +1 bias.
|
|
// This sets negatives to zero because 0-1 is used for DOF.
|
|
half SunUnBias(half A)
|
|
{
|
|
#if ES2_USE_DOF
|
|
return max(0.0, A - 1.0);
|
|
#else
|
|
return A;
|
|
#endif
|
|
}
|
|
|
|
void SunAlphaPS_ES2(
|
|
float2 InUVs[8] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
OutColor.r =
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6]).a) * 0.125 +
|
|
SunUnBias(PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[7]).a) * 0.125;
|
|
OutColor.r = HighlightCompression(OutColor.r);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Second sun shaft blur.
|
|
//
|
|
|
|
#define SUN_M 0.5
|
|
|
|
void SunBlurVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoords[8] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
OutTexCoords[0] = SunShaftRect(InPosition.xy, 1.0 - SUN_P0 * SUN_M);
|
|
OutTexCoords[1] = SunShaftRect(InPosition.xy, 1.0 - SUN_P1 * SUN_M);
|
|
OutTexCoords[2] = SunShaftRect(InPosition.xy, 1.0 - SUN_P2 * SUN_M);
|
|
OutTexCoords[3] = SunShaftRect(InPosition.xy, 1.0 - SUN_P3 * SUN_M);
|
|
OutTexCoords[4] = SunShaftRect(InPosition.xy, 1.0 - SUN_P4 * SUN_M);
|
|
OutTexCoords[5] = SunShaftRect(InPosition.xy, 1.0 - SUN_P5 * SUN_M);
|
|
OutTexCoords[6] = SunShaftRect(InPosition.xy, 1.0 - SUN_P6 * SUN_M);
|
|
OutTexCoords[7] = InTexCoord.xy;
|
|
}
|
|
|
|
#undef SUN_M
|
|
|
|
void SunBlurPS_ES2(
|
|
float2 InUVs[8] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
OutColor.r =
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6]).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[7]).r * 0.125;
|
|
}
|
|
|
|
|
|
//
|
|
// Third sun shaft blur, composite with bloom, vignette.
|
|
//
|
|
|
|
#define SUN_M 0.25
|
|
|
|
void SunMergeVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float4 OutTexCoordVignette : TEXCOORD0,
|
|
out float4 OutTexCoords[7] : TEXCOORD1,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
OutTexCoordVignette.xy = InTexCoord.xy;
|
|
OutTexCoordVignette.zw = VignetteSpace(OutPosition.xy);
|
|
|
|
float Start;
|
|
float Scale;
|
|
|
|
Start = 2.0/6.0;
|
|
Scale = 0.66/2.0;
|
|
|
|
OutTexCoords[0].xy = InTexCoord.xy + Circle(Start, 6.0, 0.0) * Scale * PostprocessInput2Size.zw;
|
|
OutTexCoords[1].xy = InTexCoord.xy + Circle(Start, 6.0, 1.0) * Scale * PostprocessInput2Size.zw;
|
|
OutTexCoords[2].xy = InTexCoord.xy + Circle(Start, 6.0, 2.0) * Scale * PostprocessInput2Size.zw;
|
|
OutTexCoords[3].xy = InTexCoord.xy + Circle(Start, 6.0, 3.0) * Scale * PostprocessInput2Size.zw;
|
|
OutTexCoords[4].xy = InTexCoord.xy + Circle(Start, 6.0, 4.0) * Scale * PostprocessInput2Size.zw;
|
|
OutTexCoords[5].xy = InTexCoord.xy + Circle(Start, 6.0, 5.0) * Scale * PostprocessInput2Size.zw;
|
|
|
|
OutTexCoords[0].zw = SunShaftRect(InPosition.xy, 1.0 - SUN_P0 * SUN_M);
|
|
OutTexCoords[1].zw = SunShaftRect(InPosition.xy, 1.0 - SUN_P1 * SUN_M);
|
|
OutTexCoords[2].zw = SunShaftRect(InPosition.xy, 1.0 - SUN_P2 * SUN_M);
|
|
OutTexCoords[3].zw = SunShaftRect(InPosition.xy, 1.0 - SUN_P3 * SUN_M);
|
|
OutTexCoords[4].zw = SunShaftRect(InPosition.xy, 1.0 - SUN_P4 * SUN_M);
|
|
OutTexCoords[5].zw = SunShaftRect(InPosition.xy, 1.0 - SUN_P5 * SUN_M);
|
|
OutTexCoords[6].xy = SunShaftRect(InPosition.xy, 1.0 - SUN_P6 * SUN_M);
|
|
OutTexCoords[6].zw = float2(0.0, 0.0);
|
|
|
|
}
|
|
|
|
#undef SUN_M
|
|
|
|
float4 SunColorVignetteIntensity;
|
|
float3 BloomColor;
|
|
|
|
void SunMergePS_ES2(
|
|
float4 InUVVignette : TEXCOORD0,
|
|
float4 InUVs[7] : TEXCOORD1,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
#if ES2_USE_BLOOM
|
|
|
|
float Scale1 = 1.0/7.0;
|
|
|
|
float Scale2 = 1.0/7.0;
|
|
|
|
half3 Bloom2 = (
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVVignette.xy).rgb * Scale1 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[0].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[1].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[2].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[3].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[4].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[5].xy).rgb * Scale2) * rcp(Scale1 * 1.0 + Scale2 * 6.0);
|
|
|
|
OutColor.rgb = PostprocessInput2.Sample(PostprocessInput2Sampler, InUVVignette.xy).rgb;
|
|
|
|
OutColor.rgb += Bloom2 * BloomColor;
|
|
|
|
// Have 5 layers on mobile.
|
|
OutColor.rgb *= 1.0/5.0;
|
|
|
|
#else
|
|
OutColor.rgb = half3(0.0, 0.0, 0.0);
|
|
#endif
|
|
|
|
#if ES2_USE_SUN
|
|
half Sun =
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].zw).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].zw).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].zw).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].zw).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4].zw).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5].zw).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[6].xy).r * 0.125 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVVignette.xy).r * 0.125;
|
|
Sun = HighlightDecompression(Sun);
|
|
OutColor.rgb += SunColorVignetteIntensity.rgb * Sun;
|
|
#endif
|
|
|
|
half Vignette = ComputeVignetteMask(InUVVignette.zw, SunColorVignetteIntensity.a);
|
|
|
|
OutColor.a = Vignette;
|
|
OutColor.rgb *= OutColor.a;
|
|
}
|
|
|
|
#undef SUN_P0
|
|
#undef SUN_P1
|
|
#undef SUN_P2
|
|
#undef SUN_P3
|
|
#undef SUN_P4
|
|
#undef SUN_P5
|
|
#undef SUN_P6
|
|
|
|
|
|
|
|
|
|
//
|
|
// Sun merge pass without sun but for small bloom final pass and vignette only.
|
|
//
|
|
|
|
void SunMergeSmallVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float4 OutTexCoordVignette : TEXCOORD0,
|
|
out float2 OutTexCoords[6] : TEXCOORD1,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
OutTexCoordVignette.xy = InTexCoord.xy;
|
|
OutTexCoordVignette.zw = VignetteSpace(OutPosition.xy);
|
|
|
|
float Start;
|
|
float Scale;
|
|
|
|
Start = 2.0/6.0;
|
|
Scale = 0.66/2.0;
|
|
Scale *= 8.0;
|
|
|
|
OutTexCoords[0] = InTexCoord.xy + Circle(Start, 6.0, 0.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[1] = InTexCoord.xy + Circle(Start, 6.0, 1.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[2] = InTexCoord.xy + Circle(Start, 6.0, 2.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[3] = InTexCoord.xy + Circle(Start, 6.0, 3.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[4] = InTexCoord.xy + Circle(Start, 6.0, 4.0) * Scale * PostprocessInput0Size.zw;
|
|
OutTexCoords[5] = InTexCoord.xy + Circle(Start, 6.0, 5.0) * Scale * PostprocessInput0Size.zw;
|
|
}
|
|
|
|
float3 BloomColor2;
|
|
|
|
void SunMergeSmallPS_ES2(
|
|
float4 InUVVignette : TEXCOORD0,
|
|
float2 InUVs[6] : TEXCOORD1,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
float Scale1 = 1.0/7.0;
|
|
|
|
float Scale2 = 1.0/7.0;
|
|
|
|
half3 Bloom1 = (
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVVignette.xy).rgb * Scale1 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[0].xy).rgb * Scale2 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[1].xy).rgb * Scale2 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[2].xy).rgb * Scale2 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[3].xy).rgb * Scale2 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[4].xy).rgb * Scale2 +
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUVs[5].xy).rgb * Scale2) * rcp(Scale1 * 1.0 + Scale2 * 6.0);
|
|
|
|
OutColor.rgb = (
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVVignette.xy).rgb * Scale1 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[0].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[1].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[2].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[3].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[4].xy).rgb * Scale2 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUVs[5].xy).rgb * Scale2) * rcp(Scale1 * 1.0 + Scale2 * 6.0);
|
|
|
|
OutColor.rgb *= BloomColor2;
|
|
|
|
OutColor.rgb += Bloom1 * BloomColor;
|
|
|
|
// Have 5 layers on mobile (actually only 2 in this shader).
|
|
OutColor.rgb *= 1.0/5.0;
|
|
|
|
// Adjusting for area difference in layers vs PC.
|
|
OutColor.rgb *= 1.0/4.0;
|
|
|
|
half Vignette = ComputeVignetteMask(InUVVignette.zw, SunColorVignetteIntensity.a);
|
|
|
|
OutColor.a = Vignette;
|
|
OutColor.rgb *= OutColor.a;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Average results of bloom/sunshaft/vignette for 2 frames (used for temporal AA).
|
|
//
|
|
|
|
void SunAvgVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutTexCoord : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, OutTexCoord);
|
|
}
|
|
|
|
void SunAvgPS_ES2(
|
|
float2 InUV : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
OutColor =
|
|
PostprocessInput0.Sample(PostprocessInput0Sampler, InUV.xy).rgba * 0.5 +
|
|
PostprocessInput1.Sample(PostprocessInput1Sampler, InUV.xy).rgba * 0.5;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Ultra simple temporal antialiasing shader which works without motion vectors.
|
|
//
|
|
|
|
float AaBlendAmount;
|
|
|
|
void AaVS_ES2(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
in float2 InTexCoord : ATTRIBUTE1,
|
|
out float2 OutUV[6] : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
DrawRectangle(InPosition, InTexCoord, OutPosition, InTexCoord);
|
|
|
|
// AA texture coordinates.
|
|
float AaX = View.TemporalAAParams.x;
|
|
// Y is flipped here in comparison with the coords in SceneVisibility (GL -y flip).
|
|
float2 Aa1 = float2(0.5,-0.0);
|
|
float2 Aa2 = float2(-0.0,0.5);
|
|
if(abs(AaX) == 0.0) Aa1 = float2(-0.0,0.5);
|
|
if(abs(AaX) == 0.0) Aa2 = float2(0.5,-0.0);
|
|
OutUV[0] = InTexCoord.xy + (Aa1 + float2(-0.75, 0.0)) * PostprocessInput0Size.zw;
|
|
OutUV[1] = InTexCoord.xy + (Aa1 + float2( 0.0,-0.75)) * PostprocessInput0Size.zw;
|
|
OutUV[2] = InTexCoord.xy + Aa1 * PostprocessInput0Size.zw;
|
|
OutUV[3] = InTexCoord.xy + (Aa1 + float2( 0.0, 0.75)) * PostprocessInput0Size.zw;
|
|
OutUV[4] = InTexCoord.xy + (Aa1 + float2( 0.75, 0.0)) * PostprocessInput0Size.zw;
|
|
OutUV[5] = InTexCoord.xy + Aa2 * PostprocessInput0Size.zw;
|
|
}
|
|
|
|
void AaPS_ES2(
|
|
float2 UV[6] : TEXCOORD0,
|
|
out half4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
// N
|
|
// w M E P = previous middle
|
|
// S
|
|
half4 ColorN = PostprocessInput0.Sample(PostprocessInput0Sampler, UV[0].xy);
|
|
half4 ColorW = PostprocessInput0.Sample(PostprocessInput0Sampler, UV[1].xy);
|
|
half4 ColorM = PostprocessInput0.Sample(PostprocessInput0Sampler, UV[2].xy);
|
|
half4 ColorE = PostprocessInput0.Sample(PostprocessInput0Sampler, UV[3].xy);
|
|
half4 ColorS = PostprocessInput0.Sample(PostprocessInput0Sampler, UV[4].xy);
|
|
half4 ColorP = PostprocessInput1.Sample(PostprocessInput1Sampler, UV[5].xy);
|
|
|
|
half LumaN = ColorN.g;
|
|
half LumaW = ColorW.g;
|
|
half LumaM = ColorM.g;
|
|
half LumaE = ColorE.g;
|
|
half LumaS = ColorS.g;
|
|
half LumaP = ColorP.g;
|
|
|
|
half LumaMin = min(LumaM, min(min(LumaN, LumaS), min(LumaW, LumaE)));
|
|
half LumaMax = max(LumaM, max(max(LumaN, LumaS), max(LumaW, LumaE)));
|
|
|
|
// Using circle of confusion size in alpha to increase the blend between two frames.
|
|
// Depth of field would flicker otherwise.
|
|
half BlendAmount = saturate(min(ColorM.a, ColorP.a) * 4.0);
|
|
BlendAmount = max(BlendAmount * 0.5, AaBlendAmount);
|
|
|
|
// BlendAmount = 0.5 -> Full ghosting (average of two frames).
|
|
// BlendAmount = 0.0 -> No ghosting but lots of flicker.
|
|
LumaMin = min(LumaM, LumaP) * BlendAmount + LumaMin * (1.0 - BlendAmount);
|
|
LumaMax = max(LumaM, LumaP) * BlendAmount + LumaMax * (1.0 - BlendAmount);
|
|
|
|
half LumaT = LumaM * 0.5 + LumaP * 0.5;
|
|
|
|
LumaT = max(LumaT, LumaMin);
|
|
LumaT = min(LumaT, LumaMax);
|
|
|
|
half BlendFinal = saturate((LumaT - LumaM) * rcp(LumaP - LumaM));
|
|
|
|
OutColor.rgb = lerp(ColorM.rgb, ColorP.rgb, BlendFinal);
|
|
}
|
|
|