991 lines
33 KiB
HLSL
991 lines
33 KiB
HLSL
////----------------//
|
||
///**Blooming HDR**///
|
||
//----------------////
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// *//
|
||
//*For Reshade 3.0+ HDR Bloom
|
||
//*--------------------------
|
||
//* Blooming HDR
|
||
//*
|
||
//* Due Diligence
|
||
//* Eye Adaptation
|
||
//* https://knarkowicz.wordpress.com/2016/01/09/automatic-exposure/ Search Ref. Temporal Adaptation
|
||
//* Prods80 AKA ThatRedDot port of exposure.
|
||
//* Additional credits (exposure)
|
||
//* - Padraic Hennessy for the logic
|
||
//* https://placeholderart.wordpress.com/2014/11/21/implementing-a-physically-based-camera-manual-exposure/
|
||
//* - Padraic Hennessy for the logic
|
||
//* https://placeholderart.wordpress.com/2014/12/15/implementing-a-physically-based-camera-automatic-exposure/
|
||
//* - MJP and David Neubelt for the method
|
||
//* https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/Exposure.hlsl
|
||
//* License: MIT, Copyright (c) 2016 MJP
|
||
//* Reinhard by Tom Madams
|
||
//* http://imdoingitwrong.wordpress.com/2010/08/19/why-reinhard-desaturates-my-blacks-3/
|
||
//* Uncharted2 Tone Mapper by Hable John
|
||
//* https://www.slideshare.net/ozlael/hable-john-uncharted2-hdr-lighting
|
||
//* ACES Cinematic Tonemapping by Krzysztof Narkowicz and one by Stephen Hill
|
||
//* https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
|
||
//* https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
|
||
//* Timothy Lottes Tone mapper and information from this site.
|
||
//* https://bartwronski.com/2016/09/01/dynamic-range-and-evs/
|
||
//* https://www.shadertoy.com/view/XljBRK
|
||
//* Generate Gold Noise image Based on this implamentation
|
||
//* https://www.shadertoy.com/view/wtsSW4
|
||
//* Depth Bloom CeeJay.dk
|
||
//* His brain told me to do it...... I just added it.
|
||
//* Adyss Bloom used as Insperation for Bloom Rework. Miss you man. Hope you come back.
|
||
//*
|
||
//* Since it was already witten out nicely was ported from. FidelityFX LPM was it self was not ported.
|
||
//* https://github.com/GPUOpen-Effects/FidelityFX-LPM
|
||
//* Most of the code is LICENSED this way.
|
||
//* https://github.com/GPUOpen-Effects/FidelityFX-LPM/blob/4a1442bf7405d0f703f7cf9c0bfe47a7559cc69b/sample/src/DX12/LPMSample.h#L3-L18
|
||
//*
|
||
//* The rest of the code below is under it's own license.
|
||
//* If I missed any please tell me.
|
||
//*
|
||
//* LICENSE
|
||
//* ============
|
||
//* Blooming HDR is licenses under: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
|
||
//*
|
||
//* You are free to:
|
||
//* Share - copy and redistribute the material in any medium or format
|
||
//* for any purpose, even commercially.
|
||
//* The licensor cannot revoke these freedoms as long as you follow the license terms.
|
||
//* Under the following terms:
|
||
//* Attribution - You must give appropriate credit, provide a link to the license, and indicate if changes were made.
|
||
//* You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||
//*
|
||
//* ShareAlike <20> If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
|
||
//*
|
||
//* No additional restrictions - You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||
//*
|
||
//* https://creativecommons.org/licenses/by-sa/4.0/
|
||
//*
|
||
//* Have fun,
|
||
//* Jose Negrete AKA BlueSkyDefender
|
||
//*
|
||
//* https://github.com/BlueSkyDefender/Depth3D
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
//Shared Texture for Blooming HDR or any other shader that want's to use it.
|
||
#if exists "Flair.fx" //Flair Interceptor//
|
||
#define Flare_A 1
|
||
#else
|
||
#define Flare_A 0
|
||
#endif
|
||
|
||
#if exists "Flare.fx" //Flare Interceptor//
|
||
#define Flare_B 1
|
||
#else
|
||
#define Flare_B 0
|
||
#endif
|
||
|
||
// Change this to set enable SRGB mode.
|
||
#define SRGB 0
|
||
|
||
//Do not Use.
|
||
//Use for real HDR.
|
||
#define HDR_Toggle 0 //For HDR10 10:10:10:2 use maybe 0.18/25.0 to start. Should only work with Thimothy
|
||
//Do not Use.
|
||
|
||
#if !defined(__RESHADE__) || __RESHADE__ < 40000
|
||
#define Compatibility 1
|
||
#else
|
||
#define Compatibility 0
|
||
#endif
|
||
|
||
uniform int Auto_Bloom <
|
||
ui_type = "combo";
|
||
ui_label = "Auto Bloom";
|
||
ui_items = "Off\0Auto Intensity\0Auto Desaturation\0Auto Saturation\0Auto Intensity & Desaturation\0Auto Intensity & Saturation\0";
|
||
ui_tooltip = "Auto Intensity will enable the shader to adjust Bloom Intensity automaticly though Bloom Opacity above.\n"
|
||
"Auto Saturation will enable the shader to adjust Bloom Saturation automaticly though Bloom Saturation above.\n"
|
||
"Default is Off.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = 0;
|
||
|
||
uniform float CBT_Adjust <
|
||
|
||
#if Compatibility
|
||
ui_type = "drag";
|
||
#else
|
||
ui_type = "slider";
|
||
#endif
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "Extracting Bright Colors";
|
||
ui_tooltip = "Use this to set the color based brightness threshold for what is and what isn't allowed.\n"
|
||
"This is the most important setting, use Debug View to adjust this.\n"
|
||
"Default Number is 0.5.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = 0.5;
|
||
|
||
uniform float2 Bloom_Intensity<
|
||
#if Compatibility
|
||
ui_type = "drag";
|
||
#else
|
||
ui_type = "slider";
|
||
#endif
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "Bloom Intensity & Bloom Opacity";
|
||
ui_tooltip = "Use this to set Primary & Secondary Bloom Intensity and Overall Bloom Opacity for your content.\n"
|
||
//"The 2nd Option only works when Bloom Intensity Isolation is set above.\n"
|
||
"Number 0.1 & 0.5 is default.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = float2(0.1,0.5);
|
||
|
||
uniform float BloomSensitivity <
|
||
#if Compatibility
|
||
ui_type = "drag";
|
||
#else
|
||
ui_type = "slider";
|
||
#endif
|
||
ui_min = 0.1; ui_max = 5.0;
|
||
ui_label = "Bloom Sensitivity";
|
||
ui_tooltip = "A Curve that is applied to the bloom input.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = 1.0;
|
||
|
||
uniform float BloomCurve <
|
||
#if Compatibility
|
||
ui_type = "drag";
|
||
#else
|
||
ui_type = "slider";
|
||
#endif
|
||
ui_min = 0.1; ui_max = 5.0;
|
||
ui_label = "Bloom Curve";
|
||
ui_tooltip = "Defines the way the bloom spreads.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = 2.0;
|
||
|
||
uniform float2 Saturation <
|
||
#if Compatibility
|
||
ui_type = "drag";
|
||
#else
|
||
ui_type = "slider";
|
||
#endif
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "Bloom Saturation & Auto Cutoff Point";
|
||
ui_tooltip = "Adjustment The amount to adjust the saturation of the Bloom.\n"
|
||
"Number 0.25 is default for both.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = float2(0.25,0.25);
|
||
|
||
uniform float Bloom_Spread <
|
||
#if Compatibility
|
||
ui_type = "drag";
|
||
#else
|
||
ui_type = "slider";
|
||
#endif
|
||
ui_min = 0.5; ui_max = 5.0;
|
||
ui_label = "Bloom Spread";
|
||
ui_tooltip = "Adjust to spread out the primary Bloom.\n"
|
||
"This is used for spreading Bloom.\n"
|
||
"Number 1.0 is default.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = 1.0;
|
||
|
||
uniform float Dither_Bloom <
|
||
ui_type = "slider";
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "Bloom Dither";
|
||
ui_tooltip = "Adjustment The amount Dither on bloom to reduce banding.\n"
|
||
"Number 0.25 is default.";
|
||
ui_category = "Bloom Adjustments";
|
||
> = 0.125;
|
||
|
||
uniform int Tonemappers <
|
||
ui_type = "combo";
|
||
ui_label = "Tonemappers";
|
||
ui_tooltip = "Changes how color get used for the other effects.\n";
|
||
ui_items = "Timothy\0ACESFitted\0";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 0;
|
||
|
||
uniform float WP <
|
||
ui_type = "drag";
|
||
ui_min = 0.00; ui_max = 2.00;
|
||
ui_label = "Linear White Point Value";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 1.0;
|
||
|
||
uniform float Exp <
|
||
ui_type = "drag";
|
||
ui_min = -4.0; ui_max = 4.00;
|
||
ui_label = "Exposure";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 0.0;
|
||
|
||
uniform float GreyValue <
|
||
ui_type = "drag";
|
||
ui_min = 0.0; ui_max = 0.5;
|
||
ui_label = "Exposure 50% Greyvalue";
|
||
ui_tooltip = "Exposure 50% Greyvalue Set this Higher when using ACES Fitted and Lower when using Timoithy.";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 0.128;
|
||
|
||
uniform float Gamma <
|
||
ui_type = "drag";
|
||
ui_min = 1.0; ui_max = 4.0;
|
||
ui_label = "Gamma value";
|
||
ui_tooltip = "Most monitors/images use a value of 2.2. Setting this to 1 disables the inital color space conversion from gamma to linear.";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 2.2;
|
||
|
||
uniform float Contrast <
|
||
ui_type = "drag";
|
||
ui_min = 0.0; ui_max = 3.0;
|
||
ui_tooltip = "Contrast Adjustment.\n"
|
||
"Number 1.0 is default.";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 1.0;
|
||
|
||
uniform float Saturate <
|
||
ui_type = "drag";
|
||
ui_min = 0.0; ui_max = 2.0;
|
||
ui_label = "Image Saturation";
|
||
ui_tooltip = "Adjustment The amount to adjust the saturation of the color in the image.\n"
|
||
"Number 1.0 is default.";
|
||
ui_category = "Tonemapper Adjustments";
|
||
> = 1.0;
|
||
|
||
uniform int Inv_Tonemappers <
|
||
ui_type = "combo";
|
||
ui_label = "Extract HDR Information";
|
||
ui_tooltip = "Changes how color get used for the other effects.\n"
|
||
"Turn this Off when the game has a good HDR implementation.";
|
||
ui_items = "Off\0Luma\0Color\0Max Color Brightness\0";
|
||
ui_category = "HDR";
|
||
> = 2;
|
||
|
||
uniform float HDR_BP <
|
||
ui_type = "drag";
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "HDR Power";
|
||
ui_tooltip = "Use adjsut the HDR Power, You can override this value and set it to like 1.5 or something.\n"
|
||
"Number 0.5 is default.";
|
||
ui_category = "HDR";
|
||
> = 0.5;
|
||
|
||
uniform bool Bloom_BA_iToneMapper <
|
||
ui_label = "HDR Bloom Application";
|
||
ui_tooltip = "This will let you swap between Befor HDR ToneMapper and After.";
|
||
ui_category = "HDR";
|
||
> = 0;
|
||
|
||
uniform int Auto_Exposure <
|
||
ui_type = "combo";
|
||
ui_label = "Auto Exposure Type";
|
||
ui_items = "Off\0Auto Exposure & Eye Adaptation\0Auto Exposure & Eyelids Adaptation\0";
|
||
ui_tooltip = "This will enable the shader to adjust Exposure automaticly.\n"
|
||
"This will also turn on Eye Adaptation for this shader.\n"
|
||
"This is based off Prod80's Port of an Auto-Expo Algo.\n"
|
||
"Padraic Hennessy, MJP and David Neubelt.";
|
||
ui_category = "Adaptation";
|
||
> = 1;
|
||
|
||
uniform float Adapt_Adjust <
|
||
ui_type = "drag";
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "Eye Adapt Speed";
|
||
ui_tooltip = "Use this to Adjust Eye Adaptation Speed.\n"
|
||
"Set from Zero to One, Zero is the slowest.\n"
|
||
"Number 0.5 is default.";
|
||
ui_category = "Adaptation";
|
||
> = 0.5;
|
||
|
||
uniform float Adapt_Seek <
|
||
ui_type = "drag";
|
||
ui_min = 0.0; ui_max = 1.0;
|
||
ui_label = "Eye Adapt Seeking";
|
||
ui_tooltip = "Use this to Adjust Eye Seeking Radius for Average Brightness.\n"
|
||
"Set from 0 to 1, 1 is Full-Screen Average Brightness.\n"
|
||
"Number 0.5 is default.";
|
||
ui_category = "Adaptation";
|
||
> = 0.5;
|
||
|
||
uniform int Debug_View <
|
||
ui_type = "combo";
|
||
ui_label = "Debug View";
|
||
ui_items = "Normal View\0Bloom View\0Heat Map\0";
|
||
ui_tooltip = "To view Shade & Blur effect on the game, movie piture & ect.";
|
||
ui_category = "Debugging";
|
||
> = 0;
|
||
|
||
/////////////////////////////////////////////////////D3D Starts Here/////////////////////////////////////////////////////////////////
|
||
#define pix float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT)
|
||
//#define BloomSpread Bloom_Spread * rcp(Bloom_Max)
|
||
#define DBP lerp(0.0,1.0,NFCD.z)
|
||
#define Sat lerp(0,10,Saturation.x)
|
||
#define PHI 1.61803398874989484820459 * 00000.1 // Golden Ratio
|
||
#define PI 3.14159265358979323846264 * 00000.1 // PI
|
||
#define SQ2 1.41421356237309504880169 * 10000.0 // Square Root of Two
|
||
#define BloomSamples 8
|
||
|
||
uniform float timer < source = "timer"; >;
|
||
|
||
texture DepthBufferTex : DEPTH;
|
||
|
||
sampler DepthBuffer
|
||
{
|
||
Texture = DepthBufferTex;
|
||
};
|
||
|
||
texture BackBufferTex : COLOR;
|
||
|
||
sampler BackBuffer
|
||
{
|
||
Texture = BackBufferTex;
|
||
#if SRGB
|
||
SRGBTexture = true;
|
||
#endif
|
||
};
|
||
|
||
texture texCurrColor { Width = BUFFER_WIDTH * 0.5; Height = BUFFER_HEIGHT * 0.5; Format = RGBA8; MipLevels = 8;};
|
||
|
||
sampler SamplerCurrBB
|
||
{
|
||
Texture = texCurrColor;
|
||
};
|
||
|
||
//Bloom Passes
|
||
texture2D BloomTexH_A { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F;};
|
||
sampler2D TextureBloomH_A { Texture = BloomTexH_A;};
|
||
|
||
texture2D BloomTexV_A { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F;};
|
||
sampler2D TextureBloomV_A { Texture = BloomTexV_A;};
|
||
|
||
texture2D BloomTexH_B { Width = BUFFER_WIDTH / 4; Height = BUFFER_HEIGHT / 4; Format = RGBA16F;};
|
||
sampler2D TextureBloomH_B { Texture = BloomTexH_B;};
|
||
|
||
texture2D BloomTexV_B { Width = BUFFER_WIDTH / 4; Height = BUFFER_HEIGHT / 4; Format = RGBA16F;};
|
||
sampler2D TextureBloomV_B { Texture = BloomTexV_B;};
|
||
|
||
texture2D BloomTexH_C { Width = BUFFER_WIDTH / 8; Height = BUFFER_HEIGHT / 8; Format = RGBA16F;};
|
||
sampler2D TextureBloomH_C { Texture = BloomTexH_C;};
|
||
|
||
texture2D BloomTexV_C { Width = BUFFER_WIDTH / 8; Height = BUFFER_HEIGHT / 8; Format = RGBA16F;};
|
||
sampler2D TextureBloomV_C { Texture = BloomTexV_C;};
|
||
|
||
texture2D BloomTex { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F;};
|
||
sampler2D TextureBloom { Texture = BloomTex;};
|
||
|
||
|
||
#if Flare_A
|
||
texture TexFlareShared { Width = BUFFER_WIDTH ; Height = BUFFER_HEIGHT; Format = RGBA16F;};
|
||
|
||
sampler SamplerFlare
|
||
{
|
||
Texture = TexFlareShared;
|
||
};
|
||
#endif
|
||
#if Flare_B
|
||
texture TexLensFlareShared { Width = BUFFER_WIDTH ; Height = BUFFER_HEIGHT; Format = RGBA16F;};
|
||
|
||
sampler SamplerLensFlare
|
||
{
|
||
Texture = TexLensFlareShared;
|
||
};
|
||
#endif
|
||
//Total amount of frames since the game started.
|
||
uniform float frametime < source = "frametime";>;
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
float Luma(float3 C)
|
||
{
|
||
float3 Luma;
|
||
|
||
if (HDR_Toggle == 0)
|
||
{
|
||
Luma = float3(0.2126, 0.7152, 0.0722); // (HD video) https://en.wikipedia.org/wiki/Luma_(video)
|
||
}
|
||
else
|
||
{
|
||
Luma = float3(0.2627, 0.6780, 0.0593); // (HDR video) https://en.wikipedia.org/wiki/Rec._2100
|
||
}
|
||
|
||
return dot(C,Luma);
|
||
}
|
||
|
||
float3 ApplyPQ(float3 color)
|
||
{
|
||
// Apply ST2084 curve
|
||
float m1 = 2610.0 / 4096.0 / 4;
|
||
float m2 = 2523.0 / 4096.0 * 128;
|
||
float c1 = 3424.0 / 4096.0;
|
||
float c2 = 2413.0 / 4096.0 * 32;
|
||
float c3 = 2392.0 / 4096.0 * 32;
|
||
float3 cp = pow(abs(color.xyz), m1);
|
||
color.xyz = pow((c1 + c2 * cp) / (1 + c3 * cp), m2);
|
||
return color;
|
||
}
|
||
|
||
//float3 ApplyscRGBScale(float3 color, float minLuminancePerNits, float maxLuminancePerNits)
|
||
//{
|
||
// color.xyz = (color.xyz * (maxLuminancePerNits - minLuminancePerNits)) + float3(minLuminancePerNits, minLuminancePerNits, minLuminancePerNits);
|
||
// return color;
|
||
//}
|
||
|
||
float Log2Exposure( in float avgLuminance, in float GreyValue )
|
||
{
|
||
float exposure = 0.0f;
|
||
avgLuminance = max(avgLuminance, 0.000001f);
|
||
// GreyValue should be 0.148 based on https://placeholderart.wordpress.com/2014/11/21/implementing-a-physically-based-camera-manual-exposure/
|
||
float linExp = GreyValue / avgLuminance;
|
||
exposure = log2( linExp );
|
||
return exposure;
|
||
}
|
||
|
||
float CalcExposedColor(in float avgLuminance, in float offset, in float GreyValue )
|
||
{
|
||
float exposure = Log2Exposure( avgLuminance, GreyValue * 2.2 );
|
||
exposure += offset; //offset = exposure
|
||
return exp2( exposure );
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////Adapted Luminance/////////////////////////////////////////////////////////////////////////////////
|
||
texture texDS {Width = 256; Height = 256; Format = RG16F; MipLevels = 9;}; //Sample at 256x256 map only has nine mip levels; 0-1-2-3-4-5-6-7-8 : 256,128,64,32,16,8,4,2, and 1 (1x1).
|
||
|
||
sampler SamplerDS
|
||
{
|
||
Texture = texDS;
|
||
};
|
||
|
||
texture texTA {Width = 64; Height = 64; Format = R16F; };
|
||
|
||
sampler SamplerTA
|
||
{
|
||
Texture = texTA;
|
||
};
|
||
|
||
texture texStored {Width = 64; Height = 64; Format = R16F; };
|
||
|
||
sampler SamplerStored
|
||
{
|
||
Texture = texStored;
|
||
};
|
||
|
||
float3 Downsample(float4 pos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
|
||
{
|
||
float2 texXY = texcoord;
|
||
float2 midHV = (Adapt_Seek-1) * float2(BUFFER_WIDTH * 0.5,BUFFER_HEIGHT * 0.5) * pix;
|
||
float2 TC = float2((texXY.x*Adapt_Seek)-midHV.x,(texXY.y*Adapt_Seek)-midHV.y);
|
||
|
||
return float3(Luma(tex2D(BackBuffer,TC).rgb),0,0);
|
||
}
|
||
|
||
float PS_Temporal_Adaptation(float4 pos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
|
||
{ //Temporal adaptation https://knarkowicz.wordpress.com/2016/01/09/automatic-exposure/
|
||
float TT = 32500,EA = (1-Adapt_Adjust)*1250, L = tex2Dlod(SamplerDS,float4(texcoord,0,11)).x, PL_A = tex2D(SamplerStored, float2(0.25,0.25)).x, PL_B = tex2D(SamplerStored, float2(0.25,0.75)).x;
|
||
EA = Auto_Exposure >= 1 ? PL_A + (L - PL_A) * (1.0 - exp(-frametime/EA)) : L;
|
||
TT = Auto_Exposure >= 1 ? PL_B + (L - PL_B) * (1.0 - exp(-frametime/TT)) : L;
|
||
float ITF= 1-(smoothstep(1,0,TT) < 0.85);// Is trigger Based on a Treshold... //smoothstep(1,0,tex2D(SamplerTA,0.0).y) < 0.85
|
||
float FT = 2500, PStoredfade = tex2D(SamplerStored, float2(0.75,0.25)).x;//Top Right
|
||
float TF = PStoredfade + (ITF - PStoredfade) * (1.0 - exp2(-frametime/FT)); //Fade Time
|
||
//float3(EA,TT,TF)
|
||
//EA = 0;//Top Left float2(0.25,0.25).x
|
||
//TT = 0;//Bottom Left float2(0.25,0.75).y
|
||
//TF = 0;//Top Right float2(0.75,0.25).z
|
||
return texcoord.x > 0.5 ? (texcoord.y > 0.5 ? 0 : TF) : (texcoord.y > 0.5 ? TT : EA);
|
||
}
|
||
//----------------------------------Inverse ToneMappers--------------------------------------------
|
||
float max3(float x, float y, float z)
|
||
{
|
||
return max(x, max(y, z));
|
||
}
|
||
|
||
float3 inv_Tonemapper(float4 color, int TM)
|
||
{
|
||
if(TM == 1)//Timothy Lottes fast_reversible
|
||
return color.rgb * rcp((1.0 + max(color.w,0.001)) - max3(color.r, color.g, color.b));
|
||
else if(TM == 2)//Reinhard
|
||
return color.rgb * rcp(max((1.0 + color.w) - color.rgb,0.001));
|
||
else//Luma Reinhard
|
||
return color.rgb * rcp(max((1.0 + lerp(-0.5,0,color.w) ) - Luma(color.rgb),0.001));
|
||
}
|
||
//---------------------------------------ToneMappers-----------------------------------------------
|
||
// General tonemapping operator, build 'b' term.
|
||
float ColToneB(float hdrMax, float contrast, float shoulder, float midIn, float midOut)
|
||
{
|
||
return
|
||
-((-pow(midIn, contrast) + (midOut*(pow(hdrMax, contrast*shoulder)*pow(midIn, contrast) -
|
||
pow(hdrMax, contrast)*pow(midIn, contrast*shoulder)*midOut)) /
|
||
(pow(hdrMax, contrast*shoulder)*midOut - pow(midIn, contrast*shoulder)*midOut)) /
|
||
(pow(midIn, contrast*shoulder)*midOut));
|
||
}
|
||
|
||
// General tonemapping operator, build 'c' term.
|
||
float ColToneC(float hdrMax, float contrast, float shoulder, float midIn, float midOut)
|
||
{
|
||
return (pow(hdrMax, contrast*shoulder)*pow(midIn, contrast) - pow(hdrMax, contrast)*pow(midIn, contrast*shoulder)*midOut) /
|
||
(pow(hdrMax, contrast*shoulder)*midOut - pow(midIn, contrast*shoulder)*midOut);
|
||
}
|
||
|
||
// General tonemapping operator, p := {contrast,shoulder,b,c}.
|
||
float ColTone(float x, float4 p)
|
||
{
|
||
float z = pow(x, p.r);
|
||
return z / (pow(z, p.g)*p.b + p.a);
|
||
}
|
||
|
||
float3 TimothyTonemapper(float3 color, float EX)
|
||
{
|
||
float hdrMax = HDR_Toggle ? 25.0 : 16.0; // How much HDR range before clipping. HDR modes likely need this pushed up to say 25.0.
|
||
float contrast = Contrast + 0.250; // Use as a baseline to tune the amount of contrast the tonemapper has.
|
||
static float shoulder = 1.0; // Likely don't need to mess with this factor, unless matching existing tonemapper is not working well..
|
||
static float midIn = 0.11; // most games will have a {0.0 to 1.0} range for LDR so midIn should be 0.18.But,I settled around 0.11
|
||
float midOut = HDR_Toggle ? 0.18/25.0 : 0.18; // Use for LDR. For HDR10 10:10:10:2 use maybe 0.18/25.0 to start. For scRGB, I forget what a good starting point is, need to re-calculate.
|
||
|
||
float b = ColToneB(hdrMax, contrast, shoulder, midIn, midOut);
|
||
float c = ColToneC(hdrMax, contrast, shoulder, midIn, midOut);
|
||
//Tone map all the things. But, first start with exposure.
|
||
color *= EX;
|
||
|
||
#define EPS 1e-6f
|
||
float peak = max(color.r, max(color.g, color.b));
|
||
peak = max(EPS, peak);
|
||
|
||
float3 ratio = color / peak;
|
||
peak = ColTone(peak, float4(contrast, shoulder, b, c) );
|
||
// then process ratio
|
||
|
||
// probably want send these pre-computed (so send over saturation/crossSaturation as a constant)
|
||
float crosstalk = 4.0; // controls amount of channel crosstalk
|
||
float saturation = contrast * Saturate; // full tonal range saturation control
|
||
float crossSaturation = contrast*16.0; // crosstalk saturation
|
||
|
||
float white = WP;
|
||
|
||
// wrap crosstalk in transform
|
||
ratio = pow(abs(ratio), saturation / crossSaturation);
|
||
ratio = lerp(ratio, white, pow(peak, crosstalk));
|
||
ratio = pow(abs(ratio), crossSaturation);
|
||
|
||
// then apply ratio to peak
|
||
color = peak * ratio;
|
||
return color;
|
||
}
|
||
|
||
// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
|
||
static const float3x3 ACESInputMat =
|
||
float3x3( float3(0.59719, 0.35458, 0.04823),
|
||
float3(0.07600, 0.90834, 0.01566),
|
||
float3(0.02840, 0.13383, 0.83777));
|
||
|
||
// ODT_SAT => XYZ => D60_2_D65 => sRGB
|
||
static const float3x3 ACESOutputMat =
|
||
float3x3( float3( 1.60475, -0.53108, -0.07367),
|
||
float3(-0.10208, 1.10813, -0.00605),
|
||
float3(-0.00327, -0.07276, 1.07602));
|
||
|
||
float3 RRTAndODTFit(float3 v)
|
||
{
|
||
float3 a = v * (v + 0.0245786f) - 0.000090537f;
|
||
float3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f;
|
||
return a / b;
|
||
}
|
||
|
||
float3 ACESFitted( float3 color, float EX)
|
||
{
|
||
color *= EX + 0.5; //Was told this need to be pre adjusted exposure.
|
||
color = mul(ACESInputMat,color);
|
||
color = RRTAndODTFit(color);
|
||
color = mul(ACESOutputMat,color);
|
||
|
||
return color/WP;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
float4 SimpleBlur(sampler2D InputTex, float2 Coord, float2 pixelsize)
|
||
{
|
||
float4 Blur = 0.0;
|
||
|
||
static const float2 Offsets[4]=
|
||
{
|
||
float2(1.0, 1.0),
|
||
float2(1.0, -1.0),
|
||
float2(-1.0, 1.0),
|
||
float2(-1.0, -1.0)
|
||
};
|
||
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
Blur += tex2D(InputTex, Coord + Offsets[i] * pixelsize);
|
||
}
|
||
|
||
return Blur * 0.25;
|
||
}
|
||
|
||
struct BloomData
|
||
{
|
||
float4 Blur;
|
||
float2 Pixelsize;
|
||
float2 Coord;
|
||
float Offset;
|
||
float Weight;
|
||
float WeightSum;
|
||
};
|
||
|
||
float2 GetPixelSize(float texsize)
|
||
{
|
||
return pix * texsize;//(1 / texsize) * float2(1, BUFFER_WIDTH / BUFFER_HEIGHT);
|
||
}
|
||
|
||
float3 Auto_Luma()
|
||
{
|
||
return float3(saturate(smoothstep(0,1,1-tex2D(SamplerTA,float2(0.25,0.25)).x)), //Top Left float2(0.25,0.25).x
|
||
tex2D(SamplerTA,float2(0.25,0.25)).x, //Top Left float2(0.25,0.25).x
|
||
saturate(smoothstep(0,1,tex2D(SamplerTA,float2(0.75,0.25)).x))); //Top Right float2(0.75,0.25).z
|
||
}
|
||
|
||
float3 Color_GS(float4 BC)
|
||
{ // Luma Threshold Thank you Adyss
|
||
float GS = Luma(BC.rgb), Saturate_A = Sat, Saturate_B = saturate(Saturation.y), AL = Auto_Luma().x;//Luma and more
|
||
// Gamma Curve
|
||
BC.rgb = pow(abs(BC.rgb), BloomSensitivity);
|
||
BC.rgb /= max(GS, 0.001);
|
||
BC.a = max(0.0, GS - CBT_Adjust);
|
||
BC.rgb *= BC.a;
|
||
//Bloom Saturation
|
||
if(Auto_Bloom == 2 || Auto_Bloom == 4) //Desaturate
|
||
Saturate_A *= lerp(0.0 + Saturate_B,1,AL);
|
||
|
||
if(Auto_Bloom == 3 || Auto_Bloom == 5) //Saturate
|
||
Saturate_A *= lerp(2.0 - Saturate_B,1,AL);
|
||
|
||
BC.rgb = lerp(BC.a, BC.rgb, min(10,Saturate_A));
|
||
|
||
return saturate(BC.rgb);
|
||
}
|
||
|
||
void PS_CurrentInfo(float4 pos : SV_Position, float2 texcoords : TEXCOORD, out float4 Color : SV_Target0)
|
||
{ //float2 D = Depth_Info(texcoords);
|
||
Color = float4(Color_GS(tex2D(BackBuffer, texcoords)), 0);
|
||
}
|
||
//Bloom Fuction from Adyss Bloom Wanted a version of your code to live on Miss you man.
|
||
float4 Bloom(float2 Coord, float texsize, sampler2D InputTex, int Dir)
|
||
{
|
||
BloomData Bloom;
|
||
Bloom.Pixelsize = GetPixelSize(texsize);
|
||
Bloom.Offset = Bloom_Spread * 0.5 ;
|
||
|
||
for (int i = 1; i < BloomSamples; i++)
|
||
{
|
||
float2 D = Dir ? float2(Bloom.Offset * Bloom.Pixelsize.x, 0) : float2( 0, Bloom.Offset * Bloom.Pixelsize.y);
|
||
Bloom.Weight = pow(abs(BloomSamples - i), BloomCurve);
|
||
Bloom.Blur += tex2Dlod(InputTex, float4(Coord + D ,0,0)) * Bloom.Weight;
|
||
Bloom.Blur += tex2Dlod(InputTex, float4(Coord - D ,0,0)) * Bloom.Weight;
|
||
Bloom.Offset += Bloom_Spread ;
|
||
Bloom.WeightSum += Bloom.Weight;
|
||
}
|
||
|
||
return Bloom.Blur /= Bloom.WeightSum * 2;
|
||
}
|
||
|
||
float4 PS_BloomH_A(float4 pos : SV_Position, float2 Coord : TEXCOORD) : SV_Target
|
||
{ //Prepass
|
||
return Bloom(Coord, 2, SamplerCurrBB, 1);
|
||
}
|
||
|
||
float4 PS_BloomV_A(float4 pos : SV_Position, float2 Coord : TEXCOORD) : SV_Target
|
||
{
|
||
return Bloom(Coord, 2, TextureBloomH_A, 0);
|
||
}
|
||
|
||
float4 PS_BloomH_B(float4 pos : SV_Position, float2 Coord : TEXCOORD) : SV_Target
|
||
{
|
||
return Bloom(Coord, 8, TextureBloomV_A, 1);
|
||
}
|
||
|
||
float4 PS_BloomV_B(float4 pos : SV_Position, float2 Coord : TEXCOORD) : SV_Target
|
||
{
|
||
return Bloom(Coord, 8, TextureBloomH_B, 0);
|
||
}
|
||
|
||
float4 PS_BloomH_C(float4 pos : SV_Position, float2 Coord : TEXCOORD) : SV_Target
|
||
{
|
||
return Bloom(Coord, 16, TextureBloomV_B, 1);
|
||
}
|
||
|
||
float4 PS_BloomV_C(float4 pos : SV_Position, float2 Coord : TEXCOORD) : SV_Target
|
||
{
|
||
return Bloom(Coord, 16, TextureBloomH_C, 0);
|
||
}
|
||
|
||
float4 Final_Bloom(float4 pos : SV_Position, float2 texcoords : TEXCOORD) : SV_Target
|
||
{
|
||
float3 LP = tex2D(BackBuffer, texcoords).rgb;
|
||
float4 Bloom = SimpleBlur(TextureBloomH_A, texcoords, GetPixelSize(2)).rgba;
|
||
Bloom += SimpleBlur(TextureBloomV_A, texcoords, GetPixelSize(2)).rgba;
|
||
Bloom += SimpleBlur(TextureBloomH_B, texcoords, GetPixelSize(4)).rgba;
|
||
Bloom += SimpleBlur(TextureBloomV_B, texcoords, GetPixelSize(4)).rgba;
|
||
Bloom += SimpleBlur(TextureBloomH_C, texcoords, GetPixelSize(8)).rgba;
|
||
Bloom += SimpleBlur(TextureBloomV_C, texcoords, GetPixelSize(8)).rgba;
|
||
Bloom *= lerp(0,10,Bloom_Intensity.x) / 6; // Luma Preserving Blending Not used........
|
||
return float4(lerp(Bloom.rgb, max(Bloom.rgb - LP, 0.0), 0),0);
|
||
}
|
||
|
||
float3 Green_Blue( float interpolant )
|
||
{
|
||
if( interpolant < 0.5 )
|
||
return float3(0.0, 1.0, 2.0 * interpolant);
|
||
else
|
||
return float3(0.0, 2.0 - 2.0 * interpolant, 1.0 );
|
||
}
|
||
|
||
float3 Red_Green( float interpolant )
|
||
{
|
||
if( interpolant < 0.5 )
|
||
return float3(1.0, 2.0 * interpolant, 0.0);
|
||
else
|
||
return float3(2.0 - 2.0 * interpolant, 1.0, 0.0 );
|
||
}
|
||
|
||
float3 FHeat( float interpolant )
|
||
{
|
||
float invertedInterpolant = interpolant;
|
||
if( invertedInterpolant < 0.5 )
|
||
{
|
||
float remappedFirstHalf = 1.0 - 2.0 * invertedInterpolant;
|
||
return Green_Blue( remappedFirstHalf );
|
||
}
|
||
else
|
||
{
|
||
float remappedSecondHalf = 2.0 - 2.0 * invertedInterpolant;
|
||
return Red_Green( remappedSecondHalf );
|
||
}
|
||
}
|
||
|
||
float3 HeatMap( float interpolant )
|
||
{
|
||
if( interpolant < 1.0 / 6.0 )
|
||
{
|
||
float firstSegmentInterpolant = 6.0 * interpolant;
|
||
return ( 1.0 - firstSegmentInterpolant ) * float3(0.0, 0.0, 0.0) + firstSegmentInterpolant * float3(0.0, 0.0, 1.0);
|
||
}
|
||
else if( interpolant < 5.0 / 6.0 )
|
||
{
|
||
float midInterpolant = 0.25 * ( 6.0 * interpolant - 1.0 );
|
||
return FHeat( midInterpolant );
|
||
}
|
||
else
|
||
{
|
||
float lastSegmentInterpolant = 6.0 * interpolant - 5.0;
|
||
return ( 1.0 - lastSegmentInterpolant ) * float3(1.0, 0.0, 0.0) + lastSegmentInterpolant * float3(1.0, 1.0, 1.0);
|
||
}
|
||
}
|
||
|
||
float Scale(float val,float max,float min) //Scale to 0 - 1
|
||
{
|
||
return (val - min) / (max - min);
|
||
}
|
||
|
||
void GN(inout float Noise,float2 TC,float seed)
|
||
{
|
||
Noise = frac(tan(distance(TC*((seed+10)+PHI), float2(PHI, PI)))*SQ2);
|
||
}
|
||
|
||
float4 HDROut(float2 texcoords)
|
||
{ float4 Out, Bloom = SimpleBlur(TextureBloom, texcoords, GetPixelSize(1)).rgba;
|
||
float2 TC = 10 * texcoords.xy - 5;
|
||
float AL = Auto_Luma().y, Ex;
|
||
|
||
if(Auto_Exposure >= 1)
|
||
Ex = Exp;
|
||
else
|
||
Ex = lerp(0,2.5,Scale(Exp, 4, -4));
|
||
|
||
float NC = Bloom_Intensity.y;//BI_Brightness = lerp(1,0.01,Bloom_Intensity.y)
|
||
|
||
if(Auto_Bloom == 1 || Auto_Bloom == 4 || Auto_Bloom == 5)
|
||
NC *= max(0.25,Auto_Luma().x);
|
||
|
||
float3 Noise, iFast, iReinhard, iReinhardLuma, Color = tex2D(BackBuffer, texcoords).rgb;
|
||
// Goldern Noise RGB Dither
|
||
GN( Noise.r, TC, 1 );
|
||
GN( Noise.g, TC, 2 );
|
||
GN( Noise.b, TC, 3 );
|
||
float3 SS = smoothstep( 0.0, 0.1, Bloom.rgb );
|
||
SS *= lerp(0.0,0.1,saturate(Dither_Bloom));
|
||
Bloom.rgb = saturate( Bloom.rgb + Noise * SS );
|
||
|
||
//Bloom should be applied before Tonemapping as otherwise all high ranges will be lost. Also can used as "resolve." But, I allow for both.
|
||
Bloom.rgb = lerp( 0.0, Bloom.rgb, saturate(NC));
|
||
//Bloom_B = lerp( 0.0, (( Bloom.rgb - 0 ) / ( BI_Brightness - 0)), saturate(NC));
|
||
//Bloom.rgb = lerp(Bloom_A,Bloom_B,Bloom.w);
|
||
|
||
if(Tonemappers >= 1)
|
||
Color = lerp(Luma(Color),Color,Saturate);
|
||
// Do inital de-gamma of the game image to ensure we're operating in the correct colour range.
|
||
if( Gamma > 1. )
|
||
Color = pow(abs(Color),Gamma);
|
||
//Bloom Befor Inverse ToneMapper
|
||
if(!Bloom_BA_iToneMapper)
|
||
Color += Bloom.rgb;
|
||
//Evil bad Negitive colors be gone by the wind of dev....
|
||
Color = max(0,Color);
|
||
//HDR Map
|
||
if(Inv_Tonemappers == 1)
|
||
Color = inv_Tonemapper(float4(Color,1-HDR_BP), 0);
|
||
else if(Inv_Tonemappers == 2)
|
||
Color = inv_Tonemapper(float4(Color,1-HDR_BP), 2);
|
||
else if(Inv_Tonemappers == 3)
|
||
Color = inv_Tonemapper(float4(Color,1-HDR_BP), 1);
|
||
//Bloom After Inverse ToneMapper
|
||
if (Bloom_BA_iToneMapper)
|
||
Color += Bloom.rgb;
|
||
//Tone map all the things
|
||
if(Auto_Exposure >= 1)
|
||
Ex = CalcExposedColor(AL,Ex,GreyValue);
|
||
else //Using the optimized tonemapper by Jim Hejl and Richard Burgess-Dawson 0.148 for the GreyValue works for me. https://imgflip.com/i/oos2z But, I will alow for this to be adjusted.
|
||
Ex = Ex;
|
||
|
||
if(Tonemappers == 0)
|
||
Color = TimothyTonemapper(Color,Ex);
|
||
else if (Tonemappers == 1)
|
||
Color = ACESFitted(Color,Ex);
|
||
//removed for now because of bug.
|
||
#if Flare_A
|
||
//Color += tex2D(SamplerFlare, texcoords).rgb;
|
||
#endif
|
||
|
||
#if Flare_B
|
||
//Color += tex2D(SamplerLensFlare, texcoords).rgb;
|
||
#endif
|
||
|
||
#if HDR_Toggle
|
||
// Do ST2084 curve
|
||
Color = ApplyPQ(Color);
|
||
#else
|
||
// Do the post-tonemapping gamma correction
|
||
if( Gamma > 1. )
|
||
Color = pow(abs(Color),rcp(2.2));
|
||
#endif
|
||
|
||
//float2 D = Depth_Info(texcoords);
|
||
float MD = 0;
|
||
if(Tonemappers >= 1)
|
||
Color = (Color - 0.5) * (Contrast) + 0.5;
|
||
|
||
if (Debug_View == 0)
|
||
Out = float4(Color, 1.);
|
||
else if(Debug_View == 1)
|
||
Out = Bloom;
|
||
else if(Debug_View == 2)
|
||
Out = texcoords.y < 0.975 ? HeatMap(Luma( Color )): HeatMap(texcoords.x);
|
||
//else
|
||
//Out = lerp(D.y,float3(D.y,0.5,D.y),MD) ;
|
||
//May need to dither.......
|
||
texcoords.x = texcoords.x * 0.75 + 0.125;//* 0.5 + 0.25;
|
||
texcoords *= 1.0 - float2(texcoords.x,texcoords.y);
|
||
float vignette = texcoords.x * texcoords.y * 15.0, Mfactor = pow(smoothstep(0,1,vignette), Auto_Luma().y * 2.0);
|
||
if(Auto_Exposure > 1)
|
||
vignette = lerp(1,lerp(0,1,saturate(Mfactor)),Auto_Luma().z);
|
||
else
|
||
vignette = 1;
|
||
|
||
return float4(Out.rgb * vignette,1.0);
|
||
}
|
||
|
||
float PS_StoreInfo(float4 pos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
|
||
{
|
||
return tex2D(SamplerTA,texcoord).x;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////Logo/////////////////////////////////////////////////////////////////////////
|
||
float4 Out(float4 position : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
|
||
{
|
||
float PosX = 0.9525f*BUFFER_WIDTH*pix.x,PosY = 0.975f*BUFFER_HEIGHT*pix.y;
|
||
float3 Color = HDROut(texcoord).rgb;
|
||
return float4(Color,1.0);
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////ReShade.fxh/////////////////////////////////////////////////////////////
|
||
|
||
// Vertex shader generating a triangle covering the entire screen
|
||
void PostProcessVS(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD)
|
||
{
|
||
texcoord.x = (id == 2) ? 2.0 : 0.0;
|
||
texcoord.y = (id == 1) ? 2.0 : 0.0;
|
||
position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
||
}
|
||
|
||
//*Rendering passes*//
|
||
technique Blooming_HDR
|
||
{
|
||
pass Store_Info
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_StoreInfo;
|
||
RenderTarget = texStored;
|
||
}
|
||
pass Current_Info
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_CurrentInfo;
|
||
RenderTarget0 = texCurrColor;
|
||
}
|
||
pass BloomH_A
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_BloomH_A;
|
||
RenderTarget = BloomTexH_A;
|
||
}
|
||
pass BloomV_A
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_BloomV_A;
|
||
RenderTarget = BloomTexV_A;
|
||
}
|
||
pass BloomV_B
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_BloomH_B;
|
||
RenderTarget = BloomTexH_B;
|
||
}
|
||
pass BloomV_B
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_BloomV_B;
|
||
RenderTarget = BloomTexV_B;
|
||
}
|
||
pass BloomV_C
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_BloomH_C;
|
||
RenderTarget = BloomTexH_C;
|
||
}
|
||
pass BloomV_C
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_BloomV_C;
|
||
RenderTarget = BloomTexV_C;
|
||
}
|
||
pass Bloom
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = Final_Bloom;
|
||
RenderTarget = BloomTex;
|
||
}
|
||
pass Downsampler
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = Downsample;
|
||
RenderTarget = texDS;
|
||
}
|
||
pass Temporal_Adaptation
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = PS_Temporal_Adaptation;
|
||
RenderTarget = texTA;
|
||
}
|
||
pass HDROut
|
||
{
|
||
VertexShader = PostProcessVS;
|
||
PixelShader = Out;
|
||
#if SRGB
|
||
SRGBWriteEnable = true;
|
||
#endif
|
||
}
|
||
|
||
}
|