Grey gamma
- crabshank
- Topic Author
Less
More
A simple one this time, just the gamma version of my grey S-curves:
Regular gamma:
Grey gamma:
Saturation is retained in the colours.
There is 2D input of high and low gammas (that are compatible with portrait displays):
UPDATE: Requires a modded DrawText header file as well, for the new 2D input (call it "DrawText_mod.fxh"!):
So the new aforementioned 2D input works when you toggle the 2D input tickbox and you move the mouse to change the current gamma values which are printed at the top of the frame. If you click the left mouse button, it will show the output at the low and high gamma points specified in the UI.
So, move the mouse to find your desired gamma co-ordinates and then set the drags in the UI accordingly.
Also, you can adjust the size of the range covered when you move the move across the screen with the slider in the UI, in 16:9 for example the range will automatically be larger for the width of the frame than its height.
Version without debug mode: here
The .hlsl version is here .
Regular gamma:
Grey gamma:
Saturation is retained in the colours.
There is 2D input of high and low gammas (that are compatible with portrait displays):
#include "ReShadeUI.fxh"
uniform int Gamma_type < __UNIFORM_COMBO_INT1
ui_items = "Grey gamma\0Regular Gamma\0";
> = 1;
uniform float Gamma_Lows < __UNIFORM_DRAG_FLOAT1
ui_min = -1.0; ui_max = 30.0;
> = 2.0;
uniform float Gamma_Highs < __UNIFORM_DRAG_FLOAT1
ui_min = -1.0; ui_max = 30.0;
> = 2.4;
uniform bool Two_dimensional_input <> = false;
uniform int Two_dimensional_input_type <__UNIFORM_COMBO_INT1
ui_items = "Crosshairs on\0Crosshairs off\0";
> = 0;
uniform float Gamma_Range < __UNIFORM_SLIDER_FLOAT1
ui_min = 0.0; ui_max = 30.0;
> = 7.0;
#include "ReShade.fxh"
#include "DrawText_mod.fxh"
uniform bool buttondown < source = "mousebutton"; keycode = 0; mode = ""; >;
uniform float2 mousepoint < source = "mousepoint"; >;
float4 GammaPass(float4 position : SV_Position, float2 texcoord : TEXCOORD0) : SV_Target
{
float4 colorOrig = tex2D(ReShade::BackBuffer, texcoord);
float4 color=colorOrig;
float OG_Y=dot(float3(0.2126729,0.7151522,0.072175), colorOrig.rgb);
color.rgb=(Gamma_type==1)?( color.rgb > 0.00313066844250063 )?1.055 * pow(abs(color.rgb),1/2.4) - 0.055:12.92 *color.rgb:color.rgb;
float4 c1=color;
float4 c2=color;
float colMax=max(color.r,max(color.g,color.b));
float Gamma_Lows_Range=(BUFFER_WIDTH>=BUFFER_HEIGHT)?Gamma_Range*(BUFFER_RCP_HEIGHT/BUFFER_RCP_WIDTH):Gamma_Range;
float Gamma_Highs_Range=(BUFFER_WIDTH>=BUFFER_HEIGHT)?Gamma_Range:Gamma_Range*(BUFFER_RCP_WIDTH/BUFFER_RCP_HEIGHT);
float Gamma_Lows= (buttondown==0 && Two_dimensional_input==1)? mousepoint.x*ReShade::PixelSize.x*((Gamma_Lows+0.5*Gamma_Lows_Range)-(Gamma_Lows-0.5*Gamma_Lows_Range))+(Gamma_Lows-0.5*Gamma_Lows_Range):Gamma_Lows;
float Gamma_Lows_Pos=(buttondown==1 && Two_dimensional_input==1)?(Gamma_Lows-(Gamma_Lows-0.5*Gamma_Lows_Range))/((Gamma_Lows+0.5*Gamma_Lows_Range)-(Gamma_Lows-0.5*Gamma_Lows_Range)):mousepoint.x*ReShade::PixelSize.x;
float Gamma_Highs= (buttondown==0 && Two_dimensional_input==1)?mousepoint.y*ReShade::PixelSize.y*((Gamma_Highs+0.5*Gamma_Highs_Range)-(Gamma_Highs-0.5*Gamma_Highs_Range))+(Gamma_Highs-0.5*Gamma_Highs_Range):Gamma_Highs;
float Gamma_Highs_Pos=(buttondown==1 && Two_dimensional_input==1)?(Gamma_Highs-(Gamma_Highs-0.5*Gamma_Highs_Range))/((Gamma_Highs+0.5*Gamma_Highs_Range)-(Gamma_Highs-0.5*Gamma_Highs_Range)):mousepoint.y*ReShade::PixelSize.y;
c1.rgb=(Gamma_type==0)?saturate(pow(abs(colMax),Gamma_Lows)*(color.rgb/colMax)):pow(abs(color.rgb),Gamma_Lows);
c2.rgb=(Gamma_type==0)?saturate(pow(abs(colMax),Gamma_Highs)*(color.rgb/colMax)):pow(abs(color.rgb),Gamma_Highs);
float4 c3;
c3.rgb=lerp(c1.rgb,c2.rgb,color.rgb);
float out_Y=dot(float3(0.2126729,0.7151522,0.072175), c3.rgb);
c3.rgb=(OG_Y>out_Y)?colorOrig.rgb:c3.rgb;
c3.rgb =(Two_dimensional_input==1 && Two_dimensional_input_type==0 && (abs(texcoord.x-Gamma_Lows_Pos)<BUFFER_RCP_WIDTH || abs(texcoord.y-Gamma_Highs_Pos)<BUFFER_RCP_HEIGHT))?float3(0.369,0.745,0):c3.rgb;
c3.rgb =(Two_dimensional_input==1 && Two_dimensional_input_type==1 && (abs(texcoord.x-Gamma_Lows_Pos)<3*BUFFER_RCP_WIDTH && abs(texcoord.y-Gamma_Highs_Pos)<3*BUFFER_RCP_HEIGHT))?float3(0.498,1,0):c3.rgb;
float4 res =float4(c3.rgb,0);
float textSize=33;
[flatten]if(Two_dimensional_input==1){
DrawText_Digit(DrawText_Shift(DrawText_Shift(float2(0.5*BUFFER_WIDTH,0), int2(-9, 0), textSize, 1), int2(8, 0), textSize, 1) ,
textSize, 1, texcoord, 3,Gamma_Lows, res,1);
DrawText_Digit( DrawText_Shift(DrawText_Shift(float2(0.5*BUFFER_WIDTH,0), int2(-9, 1), textSize, 1), int2(8, 0), textSize, 1) ,
textSize, 1, texcoord, 3,Gamma_Highs, res,1);
}
c3.rgb=res.rgb;
return c3;
}
technique Grey_Gamma
{
pass
{
VertexShader = PostProcessVS;
PixelShader = GammaPass;
}
}
UPDATE: Requires a modded DrawText header file as well, for the new 2D input (call it "DrawText_mod.fxh"!):
//Original by kingeric1992, modded by crabshank 08/10/2019
#ifndef _DRAWTEXT_H_
#define _DRAWTEXT_H_
#define _DRAWTEXT_GRID_X 14.0
#define _DRAWTEXT_GRID_Y 7.0
///////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Available functions: //
// DrawText_String( offset, text size, xy ratio, input coord, string array, array size, output) //
// float2 offset = top left corner of string, screen hight pixel unit. //
// float text size = text size, screen hight pixel unit. //
// float xy ratio = xy ratio of text. //
// float2 input coord = current texture coord. //
// int string array = string data in float2 array format, ex: "Demo Text" //
// int String0[9] = { __D, __e, __m, __o, __Space, __T, __e, __x, __t}; //
// int string size = size of the string array. //
// float output = output. //
// //
// DrawText_Digit( offset, text size, xy ratio, input coord, precision after dot, data, output) //
// float2 offset = same as DrawText_String. //
// float text size = same as DrawText_String. //
// float xy ratio = same as DrawText_String. //
// float2 input coord = same as DrawText_String. //
// int precision = digits after dot. //
// float data = input float. //
// float output = output. //
// //
// float2 DrawText_Shift(shift, text size, xy ratio) //
// float2 shift = shift line(y) and column. //
// float text size = same as DrawText_String. //
// float xy ratio = same as DrawText_String. //
// //
///////////////////////////////////////////////////////////////////////////////////////////////////////
//Sample Usage
/*
float4 main_fragment( float4 position : POSITION,
float2 txcoord : TEXCOORD) : COLOR {
float res = 0.0;
int line0[9] = { __D, __e, __m, __o, __Space, __T, __e, __x, __t }; //Demo Text
int line1[15] = { __b, __y, __Space, __k, __i, __n, __g, __e, __r, __i, __c, __1, __9, __9, __2 }; //by kingeric1992
int line2[6] = { __S, __i, __z, __e, __Colon, __Space }; // Size: %d.
DrawText_String(float2(100.0 , 100.0), 32, 1, txcoord, line0, 9, res);
DrawText_String(float2(100.0 , 134.0), textSize, 1, txcoord, line1, 15, res);
DrawText_String(DrawText_Shift(float2(100.0 , 134.0), int2(0, 1), textSize, 1), 18, 1, txcoord, line2, 6, res);
DrawText_Digit(DrawText_Shift(DrawText_Shift(float2(100.0 , 134.0), int2(0, 1), textSize, 1), int2(8, 0), 18, 1),
18, 1, txcoord, 0, textSize, res);
return res;
}
*/
//Text display
//Character indexing
#define __Space 0 // (space)
#define __Exclam 1 // !
#define __Quote 2 // "
#define __Pound 3 // #
#define __Dollar 4 // $
#define __Percent 5 // %
#define __And 6 // &
#define __sQuote 7 // '
#define __rBrac_O 8 // (
#define __rBrac_C 9 // )
#define __Asterisk 10 // *
#define __Plus 11 // +
#define __Comma 12 // ,
#define __Minus 13 // -
#define __Dot 14 // .
#define __Slash 15 // /
#define __0 16 // 0
#define __1 17 // 1
#define __2 18 // 2
#define __3 19 // 3
#define __4 20 // 4
#define __5 21 // 5
#define __6 22 // 6
#define __7 23 // 7
#define __8 24 // 8
#define __9 25 // 9
#define __Colon 26 // :
#define __sColon 27 // ;
#define __Less 28 // <
#define __Equals 29 // =
#define __Greater 30 // >
#define __Question 31 // ?
#define __at 32 // @
#define __A 33 // A
#define __B 34 // B
#define __C 35 // C
#define __D 36 // D
#define __E 37 // E
#define __F 38 // F
#define __G 39 // G
#define __H 40 // H
#define __I 41 // I
#define __J 42 // J
#define __K 43 // K
#define __L 44 // L
#define __M 45 // M
#define __N 46 // N
#define __O 47 // O
#define __P 48 // P
#define __Q 49 // Q
#define __R 50 // R
#define __S 51 // S
#define __T 52 // T
#define __U 53 // U
#define __V 54 // V
#define __W 55 // W
#define __X 56 // X
#define __Y 57 // Y
#define __Z 58 // Z
#define __sBrac_O 59 // [
#define __Backslash 60 // \..
#define __sBrac_C 61 // ]
#define __Caret 62 // ^
#define __Underscore 63 // _
#define __Punc 64 // `
#define __a 65 // a
#define __b 66 // b
#define __c 67 // c
#define __d 68 // d
#define __e 69 // e
#define __f 70 // f
#define __g 71 // g
#define __h 72 // h
#define __i 73 // i
#define __j 74 // j
#define __k 75 // k
#define __l 76 // l
#define __m 77 // m
#define __n 78 // n
#define __o 79 // o
#define __p 80 // p
#define __q 81 // q
#define __r 82 // r
#define __s 83 // s
#define __t 84 // t
#define __u 85 // u
#define __v 86 // v
#define __w 87 // w
#define __x 88 // x
#define __y 89 // y
#define __z 90 // z
#define __cBrac_O 91 // {
#define __vBar 92 // |
#define __cBrac_C 93 // }
#define __Tilde 94 // ~
#define __tridot 95 // (...)
#define __empty0 96 // (null)
#define __empty1 97 // (null)
//Character indexing ends
texture Texttex < source = "FontAtlas.png"; > {
Width = 512;
Height = 512;
};
sampler samplerText {
Texture = Texttex;
};
//accomodate for undef array size.
#define DrawText_String( pos, size, ratio, tex, array, arrSize, output ) \
{ float text = 0.0; \
float2 uv = (tex * float2(BUFFER_WIDTH, BUFFER_HEIGHT) - pos) / size; \
uv.y = saturate(uv.y); \
uv.x *= ratio * 2.0; \
float id = array[int(trunc(uv.x))]; \
if(uv.x <= arrSize && uv.x >= 0.0) \
text = tex2D(samplerText, (frac(uv) + float2( id % 14.0, trunc(id / 14.0))) \
/ float2( _DRAWTEXT_GRID_X, _DRAWTEXT_GRID_Y) ).x; \
output += text; }
float2 DrawText_Shift( float2 pos, int2 shift, float size, float ratio ) {
return pos + size * shift * float2(0.5, 1.0) / ratio;
}
float mulTenIntPow(float number,float power){
float sign=(power>=0)?1:-1;
int pwr=uint(round(abs(power)));
[flatten]if(pwr>1){
for(int i=0; i<pwr;i++){
number=(sign==1)?number*10:number/10;
}
}else{
number=(sign==1)?number*10:number/10;
}
return number;
}
float rounder (float places,float number){
float sign=(number>=0)?1:-1;
int integer=int(round(mulTenIntPow(abs(number),places)));
return sign*(mulTenIntPow(float(round(integer)),-places));
}
void DrawText_Digit( float2 pos, float size, float ratio, float2 tex, int digit, float data, inout float4 res,float textGrey) {
int digits[13] = {
__0, __1, __2, __3, __4, __5, __6, __7, __8, __9, __Minus, __Space, __Dot
};
float2 uv = (tex * float2(BUFFER_WIDTH, BUFFER_HEIGHT) - pos) / size;
uv.y = saturate(uv.y);
uv.x *= ratio * 2.0;
data=rounder(digit,data);
float t = abs(data);
int numDigits = max(ceil(log2(t)/3.32192809),1);
//early exit:
if(uv.x <-numDigits-1 || uv.x > digit+1) return;
int index = 0;
[flatten]if(int(uv.x)==0){
index=round(trunc(frac(mulTenIntPow(t,-1))*10));
}else if(int(uv.x)<=-1){
index=round(trunc(frac(trunc(mulTenIntPow(t,uv.x))/10)*10));
}else if(int(uv.x)>=1){
index=round(frac(trunc(mulTenIntPow(t,int(uv.x)))/10)*10);
}
index=(int(uv.x)==0&&int(ceil(uv.x))==1)?12:index;
[flatten]if(int(uv.x)==-numDigits){
if(data>=0){
index=11;
}else{
index=10;
}
}
index=digits[int(index)];
res +=(textGrey*2-1)*tex2D(samplerText, (frac(uv) + float2( index % 14.0, trunc(index / 14.0))) /
float2( _DRAWTEXT_GRID_X, _DRAWTEXT_GRID_Y)).x;
}
#endif
So the new aforementioned 2D input works when you toggle the 2D input tickbox and you move the mouse to change the current gamma values which are printed at the top of the frame. If you click the left mouse button, it will show the output at the low and high gamma points specified in the UI.
So, move the mouse to find your desired gamma co-ordinates and then set the drags in the UI accordingly.
Also, you can adjust the size of the range covered when you move the move across the screen with the slider in the UI, in 16:9 for example the range will automatically be larger for the width of the frame than its height.
Version without debug mode: here
The .hlsl version is here .
Last edit: 4 years 1 month ago by crabshank. Reason: Changed to not allow black crush
The following user(s) said Thank You: Wicked Sick, jas01, Faustus86
Please Log in or Create an account to join the conversation.
- Marty McFly
Less
More
Rewrote the file to show some optimizations you can do:
pastebin.com/CkT2Rkz7
Basically first of all, ditch as many branches as you can. Using if/else to just assign one variable or early return is super slow, shaders don't have an early return, there are no jump operations, so it'll all end up being assigned to one register that's returned at the end. Ternary operator (the ? : operator of C languages) is much better suited for that as it doesn't branch, just a conditional assign.
Computing the max of all channels into a separate variable makes sure to compiler doesn't calculate it two times- it probably won't but making sure is better.
The splitscreen is a huge abomination with many branches and conditions which can be easily simplified using a bit of math. I made it so the width is always 2 pixels. Important to know that booleans don't exist in shaders, we only have integers and floats, and quite often, integers are also emulated, so keep all math in float as long as possible. I put a lot of comments in there to show you what I did, might want to do a revision and also consider that for your other shaders. Thing is, you might consider ditching the split altogether, because we already have a splitscreen shader iirc, and doing the calculation in every shader is straining performance.
Happy programming!
pastebin.com/CkT2Rkz7
Basically first of all, ditch as many branches as you can. Using if/else to just assign one variable or early return is super slow, shaders don't have an early return, there are no jump operations, so it'll all end up being assigned to one register that's returned at the end. Ternary operator (the ? : operator of C languages) is much better suited for that as it doesn't branch, just a conditional assign.
Computing the max of all channels into a separate variable makes sure to compiler doesn't calculate it two times- it probably won't but making sure is better.
The splitscreen is a huge abomination with many branches and conditions which can be easily simplified using a bit of math. I made it so the width is always 2 pixels. Important to know that booleans don't exist in shaders, we only have integers and floats, and quite often, integers are also emulated, so keep all math in float as long as possible. I put a lot of comments in there to show you what I did, might want to do a revision and also consider that for your other shaders. Thing is, you might consider ditching the split altogether, because we already have a splitscreen shader iirc, and doing the calculation in every shader is straining performance.
Happy programming!
The following user(s) said Thank You: Wicked Sick, crabshank
Please Log in or Create an account to join the conversation.
- crabshank
- Topic Author
Less
More
4 years 8 months ago - 4 years 8 months ago #3
by crabshank
Replied by crabshank on topic Grey gamma
Thanks a lot for the tips, I'll re-write my code as soon as I can.
EDIT: TBH, I didn't even know that the x=y>z construction was even a thing.
EDIT: TBH, I didn't even know that the x=y>z construction was even a thing.
Last edit: 4 years 8 months ago by crabshank.
Please Log in or Create an account to join the conversation.
- jas01
Less
More
Marty McFly wrote: Thing is, you might consider ditching the split altogether, because we already have a splitscreen shader iirc, and doing the calculation in every shader is straining performance.
Perhaps it's better for crabshank to release it as a separate thing? Being honest I prefer his version of this shader. Mixing them into one splitscreen could work as well (adding dynamic slider from his work to what we already have - if I'm right there is no such thing in it right now).
Last edit: 4 years 8 months ago by jas01. Reason: .
The following user(s) said Thank You: crabshank
Please Log in or Create an account to join the conversation.
- crabshank
- Topic Author
Less
More
- crabshank
- Topic Author
Less
More
UPDATE: I have added separate gamma values for highs and lows. I read that sRGB splices two separate gammas together, I though I should have my own version.
N.B. The updated version uses sliders instead of drag in the UI.
N.B. The updated version uses sliders instead of drag in the UI.
The following user(s) said Thank You: jas01
Please Log in or Create an account to join the conversation.
- crabshank
- Topic Author
Less
More
UPDATE: Added 2D input. I have also changed the UI for the gamma inputs back to drags.
Please Log in or Create an account to join the conversation.
- crabshank
- Topic Author
Less
More
- crabshank
- Topic Author
Less
More
UPDATE: New version does not allow black crush. And does Linear to sRGB conversion beforehand for best results, with the Regular Gamma setting.
Please Log in or Create an account to join the conversation.
- aaronth07
Less
More