Extended Levels (W\B point ) + Histogram port
- v00d00m4n
- Topic Author
Tired to wait for when Marty will release Lightroom shader, so i used old sweetFX levels and upgraded it and found old forgotten histogram shader and ported it to reshade 3 to achieve my goals and fully imitate Photoshop, Gimp and Paint.net kind of levels editing.
Now you have both input and output levels, gamma, everything separate for each color channel, plus some anti-clipping measure (but not so good, I forgot most of curve related math and hope someone could help me to s-curve into 0-255 range everything that gets beyond it and clipped, by using confirurable curve start start and end points.
So lets say I have 16-235 expanded to 0-255, since I its linear function, ill have values 0-16 appear expanded to -18-0 and values 235--255 expanded as 255-278, what I want, is set break point like 5 for black and 250 for white, and while everything in-between should be kep linear, since these points all values from 5 to -18 for black point should be smoothly curved into 5-0 range, and for white point values 250-278 should be smoothly curved to 250-255 range.
Since these points 5 and 250 should be edited in real time for each channel and end points 0 and 255 non constant and chould change with Ouput Level values, formula should be dynamic. I see it as 2nd step after linear function (to keep in corrections intact), with 2 if else functions where range 5-250 should be kept as is, and ranges -18-5 and 250-278 (again these are not constants, keep that in mind!) should be processed by two opposite curve formulas what will smoothly pack these ranges to output range.
My problem - these formulas and I don't remember much of hlsl syntax and don't know reshade syntax specifics to implement it properly.
Also, would be nice if someone could explain me how can I draw graph (y as output, x as input colors, on half transparent BG just like in histogram shader) on screen to visualize line and curve I'm actually getting for better debugging ?
As for histogram - it works like charm, should be loaded after levels to let you see color distribution. There is only one UI value, that for some reason gives me error during compilation, texture2d don't like int iResolution for some reason but #define works fine
Please keep comments, where I explain problem, In shader, i need to rise awareness of tonemap problem in modern games from lazy devs.this shader pack it just a temporary solution to improper white and black points and I hope that more people would notice problem and would force devs to fix it natively
save as: Levels.fx (you can safely replace old one with this updated version)
/**
* Levels version 1.6
* by Christian Cann Schuldt Jensen ~ CeeJay.dk
* updated to 1.3+ by Kirill Yarovoy ~ v00d00m4n
*
* Allows you to set a new black and a white level.
* This increases contrast, but clips any colors outside the new range to either black or white
* and so some details in the shadows or highlights can be lost.
*
* The shader is very useful for expanding the 16-235 TV range to 0-255 PC range.
* You might need it if you're playing a game meant to display on a TV with an emulator that does not do this.
* But it's also a quick and easy way to uniformly increase the contrast of an image.
*
* -- Version 1.0 --
* First release
* -- Version 1.1 --
* Optimized to only use 1 instruction (down from 2 - a 100% performance increase :) )
* -- Version 1.2 --
* Added the ability to highlight clipping regions of the image with #define HighlightClipping 1
*
* -- Version 1.3 --
* Added inddependant RGB channel levels that allow to fix impropely balanced console specific color space.
*
* Most of modern Xbox One \ PS4 ports has white point around 233 222 211 instead of TV 235 235 235
* which can be seen and aproximated by analyzing histograms of hundreds of hudless screenshots of modern games
* including big titles such as GTAV, Witcher 3, Watch_Dogs, most of UE4 based titles and so on.
*
* Most of these games lacking true balanced white and black colors and looks like if you play on very old and dusty display.
* This problem could be related to improper usage and settings of popular FILMIC shader, introduced in Uncharted 2.
*
* I used to prebake static luts to restore color balance, but doing so in image editors was slow, so once i discovered
* that Reshade 3 has RGB UI settings i decided that dynamic in-game correction would be more productive, so i updated this
* old shader to correct color mess in game. I can spot white oddities wiht my naked eyes, but i suggest to combine this shader
* with Ganossa Histogram shader, loaded after levels for this, but you need to update it for Rehade 3 and get it here:
* https://github.com/crosire/reshade-shaders/blob/382b28f33034809e52513332ca36398e72563e10/ReShade/Shaders/Ganossa/Histogram.fx
*
* -- Version 1.4 --
* Added ability to upshift color range before expanding it. Needed to fix stupid Ubisoft mistake in Watch Dogs 2 where they
* somehow downshifted color range.
*
* -- Version 1.5 --
* Changed formulas to allow gamma and output range controls.
*
* -- Version 1.6 --
* Added ACES curve, to avoid clipping.
*/
// Settings
uniform float3 InputBlackPoint <
ui_type = "color";
ui_tooltip = "The black point is the new black - literally. Everything darker than this will become completely black.";
> = float3(16/255.0f, 18/255.0f, 20/255.0f);
uniform float3 InputWhitePoint <
ui_type = "color";
ui_tooltip = "The new white point. Everything brighter than this becomes completely white";
> = float3(233/255.0f, 222/255.0f, 211/255.0f);
uniform float3 InputGamma <
ui_type = "drag";
ui_min = 0.33f; ui_max = 3.00f;
ui_label = "RGB Gamma";
ui_tooltip = "Adjust midtones for Red, Green and Blue.";
> = float3(1.00f,1.00f,1.00f);
uniform float3 OutputBlackPoint <
ui_type = "color";
ui_tooltip = "The black point is the new black - literally. Everything darker than this will become completely black.";
> = float3(0/255.0f, 0/255.0f, 0/255.0f);
uniform float3 OutputWhitePoint <
ui_type = "color";
ui_tooltip = "The new white point. Everything brighter than this becomes completely white";
> = float3(255/255.0f, 255/255.0f, 255/255.0f);
uniform float3 ColorRangeShift <
ui_type = "color";
ui_tooltip = "Some games like Watch Dogs 2 has color range 16-235 downshifted to 0-219, so this option was added to upshift color range before expanding it. RGB value entered here will be just added to default color value. Negative values impossible at the moment in game, but can be added, in shader if downshifting needed. 0 disables shifting.";
> = float3(0/255.0f, 0/255.0f, 0/255.0f);
uniform int ColorRangeShiftSwitch <
ui_type = "drag";
ui_min = -1; ui_max = 1;
ui_tooltip = "Workaround for lack of negative color values in Reshade UI: -1 to downshift, 1 to upshift, 0 to disable";
> = 0;
uniform bool AvoidClipping <
ui_tooltip = "Avoids the pixels that clip.";
> = false;
uniform bool HighlightClipping <
ui_tooltip = "Colors between the two points will be stretched, which increases contrast, but details above and below the points are lost (this is called clipping). Highlight the pixels that clip. Yellow = Some details lost in the highlights, Red = All details lost in the highlights, Cyan = Some details lost in the shadows, Blue = All details lost in the shadows.";
> = false;
// Helper functions
#include "ReShade.fxh"
float3 ACESFilmRec2020( float3 x )
{
float a = 15.8f;
float b = 2.12f;
float c = 1.2f;
float d = 5.92f;
float e = 1.9f;
x = x * 0.49f; // Restores luminance
return ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e );
}
// Main function
float3 LevelsPass(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
float3 InputColor = tex2D(ReShade::BackBuffer, texcoord).rgb;
//float3 black_point_float = InputBlackPoint; // / 255.0f;
//float3 white_point_float = InputWhitePoint == BlackPoint ? (1.0f / 0.000000001f) : (1.0f / (WhitePoint - BlackPoint)); // Avoid division by zero if the white and black point are the same
//color = (color + (ColorRangeShift * ColorRangeShiftSwitch)) * white_point_float - (black_point_float * white_point_float); //old formula
//float3 OutputColor = (((InputColor + (ColorRangeShift * ColorRangeShiftSwitch)) - black_point_float) * white_point_float); // optimized
float3 OutputColor = pow(((InputColor + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
if (AvoidClipping == true)
{
OutputColor = ACESFilmRec2020(OutputColor);
}
if (HighlightClipping == true)
{
float3 ClippedColor;
ClippedColor = any(OutputColor > saturate(OutputColor)) // any colors whiter than white?
? float3(1.0, 1.0, 0.0)
: OutputColor;
ClippedColor = all(OutputColor > saturate(OutputColor)) // all colors whiter than white?
? float3(1.0, 0.0, 0.0)
: ClippedColor;
ClippedColor = any(OutputColor < saturate(OutputColor)) // any colors blacker than black?
? float3(0.0, 1.0, 1.0)
: ClippedColor;
ClippedColor = all(OutputColor < saturate(OutputColor)) // all colors blacker than black?
? float3(0.0, 0.0, 1.0)
: ClippedColor;
OutputColor = ClippedColor;
}
return OutputColor;
}
technique Levels
{
pass
{
VertexShader = PostProcessVS;
PixelShader = LevelsPass;
}
}
save as Histogram.fx
/**
* Copyright (C) 2015-2016 Ganossa (mediehawk@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software with restriction, including without limitation the rights to
* use and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following conditions:
*
* The above copyright notice and the permission notices (this and below) shall
* be included in all copies or substantial portions of the Software.
*
* Permission needs to be specifically granted by the author of the software to any
* person obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to copy, modify, merge, publish, distribute, and/or
* sublicense the Software, and subject to the following conditions:
*
* The above copyright notice and the permission notices (this and above) shall
* be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Ported to Reshade 3 by v00d00m4n
////-------------//
///**HISTOGRAM**///
//-------------////
//#define USE_HISTOGRAM 1 //[Histogram] //-Histogram effect
//>Histogram Settings<\\
//#define bHistoMix 0 //[1:0] //-Mixes the colors in the histogram
uniform bool bHistoMix <
ui_tooltip = "Mixes the colors in the histogram.";
> = true;
#define iResolution 200 //[32:253] //-Adjust sample resolution (effects performance)
/* uniform int iResolution <
ui_type = "drag";
ui_min = 32; ui_max = 1024;
ui_tooltip = "Adjust sample resolution (effects performance)";
> = 200;
*/ // Why does not it work?
//#define iVerticalScale 100 //[1:100] //-CS scale
uniform int iVerticalScale <
ui_type = "drag";
ui_min = 0; ui_max = 100;
ui_tooltip = "CS scale";
> = 25;
//#define iHorizontalScale 4 //[1:4] //-CS scale
uniform int iHorizontalScale <
ui_type = "drag";
ui_min = 1; ui_max = 10;
ui_tooltip = "CS scale";
> = 4;
//#define Histogram_ToggleKey RESHADE_TOGGLE_KEY //[undef] //-Toggle key for Histogram
//#include EFFECT_CONFIG(Ganossa)
//#if USE_HISTOGRAM
//#pragma message "Histogram by Ganossa\n"
#include "ReShade.fxh"
//namespace Ganossa
//{
texture2D detectIntTex { Width = iResolution; Height = iResolution; Format = RGBA32F; };
sampler2D detectIntColor { Texture = detectIntTex; };
texture2D detectLowTex { Width = 256; Height = 1; Format = RGBA16F; };
sampler2D detectLowColor { Texture = detectLowTex; };
void PS_Histogram_DetectInt(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 detectInt : SV_Target)
{
detectInt = tex2D(ReShade::BackBuffer,texcoord);
}
void PS_Histogram_DetectLow(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 detectLow : SV_Target)
{
detectLow = float4(0,0,0,0);
float bucket = trunc(texcoord.x * 256f);
[fastopt][loop]
for (float i = 0.0; i <= 1; i+=1f/iResolution)
{ [fastopt][loop]
for ( float j = 0.0; j <= 1; j+=1f/iResolution )
{
float3 level = trunc(tex2D(detectIntColor,float2(j,i)).xyz*256f);
detectLow.xyz += (level == bucket);
}
}
detectLow.xyz /= float(iResolution*iResolution)/iVerticalScale;
}
float4 PS_Histogram_Display(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target0
{
float3 data = tex2D(detectLowColor,texcoord.x*iHorizontalScale).xyz;
float3 orig = tex2D(ReShade::BackBuffer,texcoord).xyz;
float4 hg = float4(0,0,0,1);
if(texcoord.x < (1./iHorizontalScale-BUFFER_RCP_WIDTH)) {
//#if bHistoMix
if (bHistoMix)
{
if(texcoord.y > 1-data.x) hg += float4(1,0,0,0);
if(texcoord.y > 1-data.y) hg += float4(0,1,0,0);
if(texcoord.y > 1-data.z) hg += float4(0,0,1,0);
if(max(hg.x,max(hg.y,hg.z)) == 0) hg = float4(orig,0)*0.5;
//#else
} else {
if(texcoord.y < 0.33) { if(texcoord.y+0.66 > 1-data.x ) hg += float4(1,0,0,0); else hg = float4(orig,0)*0.5; }
if(texcoord.y < 0.66 && texcoord.y > 0.33) { if(texcoord.y+0.33 > 1-data.y) hg += float4(0,1,0,0); else hg = float4(orig,0)*0.5; }
if(texcoord.y > 0.66) { if(texcoord.y > 1-data.z) hg += float4(0,0,1,0); else hg = float4(orig,0)*0.5; }
//#endif
}
} else hg = float4(orig,0);
return hg;
}
technique Histogram
{
pass Histogram_DetectInt
{
VertexShader = PostProcessVS;
PixelShader = PS_Histogram_DetectInt;
RenderTarget = detectIntTex;
}
pass Histogram_DetectLow
{
VertexShader = PostProcessVS;
PixelShader = PS_Histogram_DetectLow;
RenderTarget = detectLowTex;
}
pass Histogram_Display
{
VertexShader = PostProcessVS;
PixelShader = PS_Histogram_Display;
}
}
//}
//#endif
// #include EFFECT_CONFIG_UNDEF(Ganossa)
Watch how it helps to fix screwed colors of Watch Dogs 2:
.
Update:
Forgot to share port of more recent version for Media Player Classic, which would be helpful for fixing ugly color grading in movies.
/**
* Levels version 1.6.6 MPC Edition lite
* Original version by Christian Cann Schuldt Jensen ~ CeeJay.dk
* Updated to 1.3+ by Kirill Yarovoy ~ v00d00m4n
*
* Allows you to set a new black and a white level.
* This increases contrast, but clips any colors outside the new range to either black or white
* and so some details in the shadows or highlights can be lost.
*
* The shader is very useful for expanding the 16-235 TV range to 0-255 PC range.
* You might need it if you're playing a game meant to display on a TV with an emulator that does not do this.
* But it's also a quick and easy way to uniformly increase the contrast of an image.
*
* -- Version 1.0 --
* First release
* -- Version 1.1 --
* Optimized to only use 1 instruction (down from 2 - a 100% performance increase :) )
* -- Version 1.2 --
* Added the ability to highlight clipping regions of the image with #define HighlightClipping 1
*
* -- Version 1.3 --
* Added inddependant RGB channel levels that allow to fix impropely balanced console specific color space.
*
* Most of modern Xbox One \ PS4 ports has white point around 233 222 211 instead of TV 235 235 235
* which can be seen and aproximated by analyzing histograms of hundreds of hudless screenshots of modern games
* including big titles such as GTAV, Witcher 3, Watch_Dogs, most of UE4 based titles and so on.
*
* Most of these games lacking true balanced white and black colors and looks like if you play on very old and dusty display.
* This problem could be related to improper usage and settings of popular FILMIC shader, introduced in Uncharted 2.
*
* I used to prebake static luts to restore color balance, but doing so in image editors was slow, so once i discovered
* that Reshade 3 has RGB UI settings i decided that dynamic in-game correction would be more productive, so i updated this
* old shader to correct color mess in game. I can spot white oddities wiht my naked eyes, but i suggest to combine this shader
* with Ganossa Histogram shader, loaded after levels for this, but you need to update it for Rehade 3 and get it here:
* https://github.com/crosire/reshade-shaders/blob/382b28f33034809e52513332ca36398e72563e10/ReShade/Shaders/Ganossa/Histogram.fx
*
* -- Version 1.4 --
* Added ability to upshift color range before expanding it. Needed to fix stupid Ubisoft mistake in Watch Dogs 2 where they
* somehow downshifted color range.
*
* -- Version 1.5 --
* Changed formulas to allow gamma and output range controls.
*
* -- Version 1.6 --
* Added ACES curve, to avoid clipping.
*
* -- Version 1.6.5 --
* Ported for MPC, cleaned out broken and debug stuff.
*
* -- Version 1.6.6 --
* Made ACES useful and configurable.
*/
// Settings
// #define InputBlackPoint float3(16/255.0f, 18/255.0f, 20/255.0f) //the thing 2011
//#define InputWhitePoint float3(233/255.0f, 222/255.0f, 211/255.0f) // generic value for modern games like GTAV and Witcher 3
//#define InputWhitePoint float3(233/255.0f, 222/255.0f, 222/255.0f) // the thing 2011
//#define InputWhitePoint float3(184/255.0f, 182/255.0f, 164/255.0f) // blade runner 2049
#define InputBlackPoint float3(16/255.0f, 16/255.0f, 16/255.0f)
#define InputWhitePoint float3(235/255.0f, 235/255.0f, 235/255.0f)
#define InputGamma float3(1.0f,1.0f,1.0f)
#define OutputBlackPoint float3(0/255.0f, 0/255.0f, 0/255.0f)
#define OutputWhitePoint float3(255/255.0f, 255/255.0f, 255/255.0f)
#define ColorRangeShift float3(0/255.0f, 0/255.0f, 0/255.0f)
#define ColorRangeShiftSwitch 0
#define ACESLuminancePercentage 98
#define ACEScurve 1
#define LevelsEnabled 1
sampler BackBuffer : register(s0);
// Helper function
float3 ACESFilmRec2020( float3 x )
{
float a = 15.8f;
float b = 2.12f;
float c = 1.2f;
float d = 5.92f;
float e = 1.9f;
x = x * ACESLuminancePercentage * 0.005; // Restores luminance
return ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e );
}
// Main function
float4 main(float2 texcoord : TEXCOORD0) : COLOR
{
float3 InputColor = tex2D(BackBuffer, texcoord).rgb;
float3 OutputColor;
if (LevelsEnabled == true)
{
OutputColor = pow(((InputColor + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
} else {
OutputColor = InputColor;
}
if (ACEScurve == true)
{
OutputColor = ACESFilmRec2020(OutputColor);
}
return float4(OutputColor, 1.0);
}
ACES here works like some sort of HDR color look simulator and sorta like TV > PC color range expander.
Here few shots of how that works in MPC in movies:
screenshotcomparison.com/comparison/130740/picture:0
screenshotcomparison.com/comparison/130740/picture:1
Original vs Shader:
Here is the little tutorial of how to find correct values:
1) Find source of light or well lit objects in game or movie that should have while color in theory (like clouds at mid day in games like GTA 5 or Witcher 3), make a hudless creenshot or remove (by cropping or stetching nearby areas) any hud in editor
2.A) in Use in game histogram and set black and white levels so that 1st side peaks could reach borders of historgram for each color
2. Use Paint.net or Gimp, open LEVELS tool, press one AUTO LEVELS, that manualy tweak black and white levels slider to a 1st peak points. Don't Set Slider to where color just starts, set it where 1st peak gets about half up. Copy 0-255 range values into reshade UI or add them to INI (keep in mind that reshade stores 0-1 range, so you have to do 1/255*your_value).
2.C) Manually pick the brightest point of screenshot that suppose to be white but is not, do same for darkest point (better do it at night or indoor screenshots), repeat rest of actions from 2.B
Please Log in or Create an account to join the conversation.
- XIIICaesar
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
Also while many people cant explain it, they can notice when highlights are not white, this is what people usually call dimmed or washed out colors. Because it feels unnatural it feels less realistic, this is why its important to keep correct RGB balance in white point, so that white is white an black is black. Many AAA devs don't understand that, especially those who does porting to PC and don't care about color range difference.
I still have no idea why balance usually 233 222 211 instead of standard 235 235 235, I cant find specs of Xbox One and PS4 to check if theory is right and that internal color range of some of these consoles is screwed and they reduce green and blue range, which looks fine on console, but looks too redish on PC.
Btw, I'm finishing testing and about to release version 1.7 with linear anti-clipping.
Please Log in or Create an account to join the conversation.
- hunt1hunt
can you updata adaptive-fog to reshade3.0?
reshade.me/forum/shader-presentation/198...-effect-adaptive-fog
very very good fog
Please Log in or Create an account to join the conversation.
- WalterDasTrevas
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
reshade.me/forum/shader-presentation/198...t-adaptive-fog#20766
had no time to test and implement UI but ill get back to that later.
Please Log in or Create an account to join the conversation.
- hunt1hunt
Please Log in or Create an account to join the conversation.
- Genrix
imgur.com/MxrzUi0
Loading after levels or before them - nothing changes.
I tried to use Reshade 3.0,4 and 3.0.7.
Whats happened?
ps. Спасибо за шейдер.
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
Please Log in or Create an account to join the conversation.
- Estebanium
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
Please Log in or Create an account to join the conversation.
- dawidezzo
"Btw, I'm finishing testing and about to release version 1.7 with linear anti-clipping."
Does this version exist? Download option for any new version would be appreciated
Cheers!
Edit1: Voodooman I have 3 important Q for You:
1.When I make screen which format is optimal: BMP or PNG, something else or it is not important?
2.Which graphic settings in game should I choose? I ask because I notice that, for example, bloom and other postprocess effects probably affect the result. I am not sure for 100%
3.On Nvidia CP Full RBG for hdmi/DP is correct as I understand, right?
Please answer and help me a little when you find moments
Please Log in or Create an account to join the conversation.
- SavvyKraken
Games like GTA5 and Farcry always seemed to look more vibrant compared to the likes of Fallout NV and Kotor2, and I could never put my finger on the reason why; never would I have guessed that the colors were just poorly calibrated..
Ironically, I could never get histogram to work so I had to work manually, but your tutorial was so well explained so it was all I needed.
Please Log in or Create an account to join the conversation.
- Crystrex
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
Damn, i got to look if it works with 4 now, and i also got to remember which of my games had the latest version of it, i got to update what i posted here, its not the latest one.
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
1 - png
2 - whatever you like, but i prefer to turn off anything that does not look realistic, until turning it off breaks something or makes game look duller and flatter
3 - right, also in games where reshade is no option use this combo - FULL on video card and LIMITED on tv\display, this should make games look like console versions.
This code has unfinished and broken remains of 1.7 commented, in case someone wants to correct and finish them, but it think its only part of code and here was a portion which was deleted by my head sleeping on keyboard
/**
* Levels version 1.8
* by Christian Cann Schuldt Jensen ~ CeeJay.dk
* updated to 1.3+ by Kirill Yarovoy ~ v00d00m4n
*
* Allows you to set a new black and a white level.
* This increases contrast, but clips any colors outside the new range to either black or white
* and so some details in the shadows or highlights can be lost.
*
* The shader is very useful for expanding the 16-235 TV range to 0-255 PC range.
* You might need it if you're playing a game meant to display on a TV with an emulator that does not do this.
* But it's also a quick and easy way to uniformly increase the contrast of an image.
*
* -- Version 1.0 --
* First release
* -- Version 1.1 --
* Optimized to only use 1 instruction (down from 2 - a 100% performance increase :) )
* -- Version 1.2 --
* Added the ability to highlight clipping regions of the image with #define HighlightClipping 1
*
* -- Version 1.3 --
* Added independant RGB channel levels that allow to fix impropely balanced console specific color space.
*
* Most of modern Xbox One \ PS4 ports has white point around 233 222 211 instead of TV 235 235 235
* which can be seen and aproximated by analyzing histograms of hundreds of hudless screenshots of modern games
* including big titles such as GTAV, Witcher 3, Watch_Dogs, most of UE4 based titles and so on.
*
* Most of these games lacking true balanced white and black colors and looks like if you play on very old and dusty display.
* This problem could be related to improper usage and settings of popular FILMIC shader, introduced in Uncharted 2.
*
* I used to prebake static luts to restore color balance, but doing so in image editors was slow, so once i discovered
* that Reshade 3 has RGB UI settings i decided that dynamic in-game correction would be more productive, so i updated this
* old shader to correct color mess in game. I can spot white oddities wiht my naked eyes, but i suggest to combine this shader
* with Ganossa Histogram shader, loaded after levels for this, but you need to update it for Rehade 3 and get it here:
* https://github.com/crosire/reshade-shaders/blob/382b28f33034809e52513332ca36398e72563e10/ReShade/Shaders/Ganossa/Histogram.fx
*
* -- Version 1.4 --
* Added ability to upshift color range before expanding it. Needed to fix stupid Ubisoft mistake in Watch Dogs 2 where they
* somehow downshifted color range.
*
* -- Version 1.5 --
* Changed formulas to allow gamma and output range controls.
*
* -- Version 1.6 --
* Added ACES curve, to avoid clipping.
*
* -- Version 1.7 --
* Removed ACES and added linear Z-curve to avoid clipping. Optional Alt calculation added.
*
* -- Version 1.8
* Previous version features was broken when i was sleepy, than i did not touch this shader for months and forgot what i did there.
* So, i commented messed up code in hope to fix it later, and reintroduced ACES in useful way.
*/
#include "ReShade.fxh"
static const float PI = 3.141592653589793238462643383279f;
// Settings
uniform bool EnableLevels <
ui_tooltip = "Enable or Disable Levels for TV <> PC or custome color range";
> = true;
uniform float3 InputBlackPoint <
ui_type = "color";
ui_tooltip = "The black point is the new black - literally. Everything darker than this will become completely black.";
> = float3(16/255.0f, 18/255.0f, 20/255.0f);
uniform float3 InputWhitePoint <
ui_type = "color";
ui_tooltip = "The new white point. Everything brighter than this becomes completely white";
> = float3(233/255.0f, 222/255.0f, 211/255.0f);
uniform float3 InputGamma <
ui_type = "drag";
ui_min = 0.001f; ui_max = 10.00f; step = 0.001f;
ui_label = "RGB Gamma";
ui_tooltip = "Adjust midtones for Red, Green and Blue.";
> = float3(1.00f,1.00f,1.00f);
uniform float3 OutputBlackPoint <
ui_type = "color";
ui_tooltip = "The black point is the new black - literally. Everything darker than this will become completely black.";
> = float3(0/255.0f, 0/255.0f, 0/255.0f);
uniform float3 OutputWhitePoint <
ui_type = "color";
ui_tooltip = "The new white point. Everything brighter than this becomes completely white";
> = float3(255/255.0f, 255/255.0f, 255/255.0f);
// Anti clipping measures
/*
uniform float3 MinBlackPoint <
ui_type = "color";
ui_min = 0.0f; ui_max = 0.5f;
ui_tooltip = "If avoid clipping enabled this is the percentage break point relative to Output black. Anything lower than this will be compressed to fit into output range.";
> = float3(16/255.0f, 18/255.0f, 20/255.0f);
uniform float3 MinWhitePoint <
ui_type = "color";
ui_min = 0.5f; ui_max = 1.0f;
ui_tooltip = "If avoid clipping enabled this is the percentage white point relative to Output white. Anything higher than this will be compressed to fit into output range.";
> = float3(233/255.0f/1.1f, 222/255.0f/1.1f, 211/255.0f/1.1f);
*/
uniform float3 ColorRangeShift <
ui_type = "color";
ui_tooltip = "Some games like Watch Dogs 2 has color range 16-235 downshifted to 0-219, so this option was added to upshift color range before expanding it. RGB value entered here will be just added to default color value. Negative values impossible at the moment in game, but can be added, in shader if downshifting needed. 0 disables shifting.";
> = float3(0/255.0f, 0/255.0f, 0/255.0f);
uniform int ColorRangeShiftSwitch <
ui_type = "drag";
ui_min = -1; ui_max = 1;
ui_tooltip = "Workaround for lack of negative color values in Reshade UI: -1 to downshift, 1 to upshift, 0 to disable";
> = 0;
/*
uniform bool AvoidClipping <
ui_tooltip = "Avoid pixels clip.";
> = false;
uniform bool AvoidClippingWhite <
ui_tooltip = "Avoid white pixels clip.";
> = false;
uniform bool AvoidClippingBlack <
ui_tooltip = "Avoid black pixels clip.";
> = false;
uniform bool SmoothCurve <
ui_tooltip = "Improves contrast";
> = true;
*/
uniform bool ACEScurve <
ui_tooltip = "Enable or Disable ACES for improved contrast and luminance";
> = false;
uniform int3 ACESLuminancePercentage <
ui_type = "drag";
ui_min = 75; ui_max = 175; step = 1;
ui_tooltip = "Percentage of ACES Luminance. Can be used to avoid some color clipping.";
> = int3(100,100,100);
uniform bool HighlightClipping <
ui_tooltip = "Colors between the two points will stretched, which increases contrast, but details above and below the points are lost (this is called clipping).\n0 Highlight the pixels that clip. Red = Some details are lost in the highlights, Yellow = All details are lost in the highlights, Blue = Some details are lost in the shadows, Cyan = All details are lost in the shadows.";
> = false;
// Helper functions
float3 ACESFilmRec2020( float3 x )
{
float a = 15.8f;
float b = 2.12f;
float c = 1.2f;
float d = 5.92f;
float e = 1.9f;
x = x * ACESLuminancePercentage * 0.005f; // Restores luminance
return ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e );
}
/*
float3 Smooth(float3 color, float3 inputwhitepoint, float3 inputblackpoint)
{
//color =
return clamp((color - inputblackpoint)/(inputwhitepoint - inputblackpoint), 0.0, 1.0);
//return pow(sin(PI * 0.5 * color),2);
}
*/
/*
float Curve(float x, float centerX, float centerY)
{
if (centerX > 0 && centerX < 1 && centerY > 0 && centerY < 1)
{
if (x < 0.5)
{
return 0-pow(sin(PI * ((0-x)/4*(0-centerX))),2)*2*(0-centerY);
} else if (x > 0.5)
{
return 1-pow(sin(PI * ((1-x)/4*(1-centerX))),2)*2*(1-centerY);
} else
{
return x;
}
} else
{
return x;
}
}
*/
//RGB input levels
float3 InputLevels(float3 color, float3 inputwhitepoint, float3 inputblackpoint)
{
return color = (color - inputblackpoint)/(inputwhitepoint - inputblackpoint);
//return pow(sin(PI * 0.5 * color),2);
}
//RGB output levels
float3 Outputlevels(float3 color, float3 outputwhitepoint, float3 outputblackpoint)
{
return color * (outputwhitepoint - outputblackpoint) + outputblackpoint;
}
//1 channel input level
float InputLevel(float color, float inputwhitepoint, float inputblackpoint)
{
return (color - inputblackpoint)/(inputwhitepoint - inputblackpoint);
}
//1 channel output level
float Outputlevel(float color, float outputwhitepoint, float outputblackpoint)
{
return color * (outputwhitepoint - outputblackpoint) + outputblackpoint;
}
// Main function
float3 LevelsPass(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
float3 InputColor = tex2D(ReShade::BackBuffer, texcoord).rgb;
float3 OutputColor = InputColor;
// outPixel = (pow(((inPixel * 255.0) - inBlack) / (inWhite - inBlack), inGamma) * (outWhite - outBlack) + outBlack) / 255.0; // Nvidia reference formula
/*
if (EnableLevels == true)
{
OutputColor = Outputlevels(pow(InputLevels(OutputColor + (ColorRangeShift * ColorRangeShiftSwitch), InputWhitePoint, InputBlackPoint), InputGamma), OutputWhitePoint, OutputBlackPoint);
/*
if (AvoidClipping == true)
{
//float3 OutputMaxBlackPoint = pow(((0 + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
//float3 OutputMaxWhitePoint = pow(((1 + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
if (AvoidClippingWhite == true)
{
//White
float3 OutputMaxWhitePoint;
float3 OutputMinWhitePoint;
// doest not give smooth gradient :-(
OutputMaxWhitePoint = Outputlevels(pow(InputLevels(OutputWhitePoint + (ColorRangeShift * ColorRangeShiftSwitch), InputWhitePoint, InputBlackPoint), InputGamma), OutputWhitePoint, OutputBlackPoint);
OutputMinWhitePoint = Outputlevels(pow(InputLevels(InputWhitePoint + (ColorRangeShift * ColorRangeShiftSwitch), InputWhitePoint, InputBlackPoint), InputGamma), OutputWhitePoint, OutputBlackPoint);
OutputColor.r = (OutputColor.r >= OutputMinWhitePoint.r)
? Curve( InputColor.r, MinWhitePoint.r, OutputMinWhitePoint.r)
//? Outputlevel( InputLevel( OutputColor.r, OutputMaxWhitePoint.r, OutputMinWhitePoint.r ), OutputWhitePoint.r, OutputMinWhitePoint.r)
: OutputColor.r;
OutputColor.g = (OutputColor.g >= OutputMinWhitePoint.g)
? Curve( InputColor.g, MinWhitePoint.g, OutputMinWhitePoint.g)
//? Outputlevel( InputLevel( OutputColor.g, OutputMaxWhitePoint.g, OutputMinWhitePoint.g ), OutputWhitePoint.g, OutputMinWhitePoint.g)
: OutputColor.g;
OutputColor.b = (OutputColor.b >= OutputMinWhitePoint.b)
? Curve( InputColor.b, MinWhitePoint.b, OutputMinWhitePoint.b)
//? Outputlevel( InputLevel( OutputColor.b, OutputMaxWhitePoint.b, OutputMinWhitePoint.b ), OutputWhitePoint.b, OutputMinWhitePoint.b)
: OutputColor.b;
}
if (AvoidClippingBlack == true)
{
//Black
float3 OutputMaxBlackPoint;
float3 OutputMinBlackPoint;
float3 OutputMinBlackPointY;
OutputMaxBlackPoint = pow(((0 + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
OutputMinBlackPoint = MinBlackPoint;
OutputMinBlackPointY = pow(((OutputMinBlackPoint + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
OutputColor.r = (OutputColor.r <= OutputMinBlackPoint.r)
? Curve(OutputMinBlackPoint.r,OutputMinBlackPointY.r,((OutputColor.r - OutputMaxBlackPoint.r)/(OutputMinBlackPoint.r - OutputMaxBlackPoint.r)) * (OutputMinBlackPoint.r - OutputBlackPoint.r) + OutputBlackPoint.r)
: OutputColor.r;
OutputColor.g = (OutputColor.g <= OutputMinBlackPoint.g)
? Curve(OutputMinBlackPoint.g,OutputMinBlackPointY.g,((OutputColor.g - OutputMaxBlackPoint.g)/(OutputMinBlackPoint.g - OutputMaxBlackPoint.g)) * (OutputMinBlackPoint.g - OutputBlackPoint.g) + OutputBlackPoint.g)
: OutputColor.g;
OutputColor.b = (OutputColor.b <= OutputMinBlackPoint.b)
? Curve(OutputMinBlackPoint.b,OutputMinBlackPointY.b,((OutputColor.b - OutputMaxBlackPoint.b)/(OutputMinBlackPoint.b - OutputMaxBlackPoint.b)) * (OutputMinBlackPoint.b - OutputBlackPoint.b) + OutputBlackPoint.b)
: OutputColor.b;
}
}
//
}
*/
if (EnableLevels == true)
{
OutputColor = pow(((InputColor + (ColorRangeShift * ColorRangeShiftSwitch)) - InputBlackPoint)/(InputWhitePoint - InputBlackPoint) , InputGamma) * (OutputWhitePoint - OutputBlackPoint) + OutputBlackPoint;
} else {
OutputColor = InputColor;
}
if (ACEScurve == true)
{
OutputColor = ACESFilmRec2020(OutputColor);
}
if (HighlightClipping == true)
{
float3 ClippedColor;
ClippedColor = any(OutputColor > saturate(OutputColor)) // any colors whiter than white?
? float3(1.0, 1.0, 0.0)
: OutputColor;
ClippedColor = all(OutputColor > saturate(OutputColor)) // all colors whiter than white?
? float3(1.0, 0.0, 0.0)
: ClippedColor;
ClippedColor = any(OutputColor < saturate(OutputColor)) // any colors blacker than black?
? float3(0.0, 1.0, 1.0)
: ClippedColor;
ClippedColor = all(OutputColor < saturate(OutputColor)) // all colors blacker than black?
? float3(0.0, 0.0, 1.0)
: ClippedColor;
OutputColor = ClippedColor;
}
return OutputColor;
}
technique Levels
{
pass
{
VertexShader = PostProcessVS;
PixelShader = LevelsPass;
}
}
/*
for visualisation
https://www.desmos.com/calculator
\frac{\left(x-\frac{16}{255}\right)}{\left(\frac{233}{255}-\frac{16}{255}\ \right)}\cdot \left(\frac{255}{255}-0\right)+0
\left(\frac{\left(\left(\frac{\left(x-\frac{16}{255}\right)}{\left(\frac{233}{255}-\frac{16}{255}\ \right)}\cdot \left(\frac{255}{255}-0\right)+0\right)-\frac{250}{255}\right)}{\left(\left(\frac{\left(1-\frac{16}{255}\right)}{\left(\frac{233}{255}-\frac{16}{255}\ \right)}\cdot \left(\frac{255}{255}-0\right)+0\right)-\frac{250}{255}\ \right)}\cdot \left(\frac{255}{255}-\frac{250}{255}\right)+\frac{250}{255}\right)
\left(\frac{\left(\left(\frac{\left(x-\frac{16}{255}\right)}{\left(\frac{233}{255}-\frac{16}{255}\ \right)}\cdot \left(\frac{255}{255}-0\right)+0\right)-\left(\frac{\left(0-\frac{16}{255}\right)}{\left(\frac{233}{255}-\frac{16}{255}\ \right)}\cdot \left(\frac{255}{255}-0\right)+0\right)\right)}{\left(\frac{5}{255}-\left(\frac{\left(0-\frac{16}{255}\right)}{\left(\frac{233}{255}-\frac{16}{255}\ \right)}\cdot \left(\frac{255}{255}-0\right)+0\right)\right)}\cdot \left(\frac{5}{255}-\frac{0}{255}\right)+0\right)
//
//this is for x,y<0.5
\left(\sin (\pi *\left(-\frac{x}{4\cdot 0.1352}\right))^2\right)\cdot 2\cdot 0.0782
\left(\sin (\pi *\left(-\frac{x}{4\cdot [black point curve break\center] x}\right))^2\right)\cdot 2\cdot [black point curve break\center] y
//this is for x,y>0.5
1-\left(\sin (\pi *\left(-\frac{1-x}{4\cdot \left(1-0.8528\right)}\right))^2\right)\cdot 2\cdot \left(1-0.9137\right)
1-\left(\sin (\pi *\left(-\frac{1-x}{4\cdot \left(1-[white point curve break\center] x\right)}\right))^2\right)\cdot 2\cdot \left(1-[white point curve break\center] y\right)
*/
Please Log in or Create an account to join the conversation.
- aaronth07
Please Log in or Create an account to join the conversation.
- v00d00m4n
- Topic Author
Please Log in or Create an account to join the conversation.
- xristosv
Please Log in or Create an account to join the conversation.