Grey gamma

  • crabshank
  • Topic Author
More
4 years 8 months ago - 4 years 1 month ago #1 by crabshank Grey gamma was created by crabshank
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):

#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
More
4 years 8 months ago #2 by Marty McFly Replied by Marty McFly on topic Grey gamma
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!
The following user(s) said Thank You: Wicked Sick, crabshank

Please Log in or Create an account to join the conversation.

  • crabshank
  • Topic Author
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.
Last edit: 4 years 8 months ago by crabshank.

Please Log in or Create an account to join the conversation.

  • jas01
More
4 years 8 months ago - 4 years 8 months ago #4 by jas01 Replied by jas01 on topic Grey gamma

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
More
4 years 8 months ago #5 by crabshank Replied by crabshank on topic Grey gamma
Optimised ^

Please Log in or Create an account to join the conversation.

  • crabshank
  • Topic Author
More
4 years 6 months ago #6 by crabshank Replied by crabshank on topic Grey gamma
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.
The following user(s) said Thank You: jas01

Please Log in or Create an account to join the conversation.

  • crabshank
  • Topic Author
More
4 years 6 months ago #7 by crabshank Replied by crabshank on topic Grey gamma
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
More
4 years 3 months ago #8 by crabshank Replied by crabshank on topic Grey gamma
Version without debugging added.

Please Log in or Create an account to join the conversation.

  • crabshank
  • Topic Author
More
4 years 1 month ago #9 by crabshank Replied by crabshank on topic Grey gamma
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
More
4 years 3 days ago #10 by aaronth07 Replied by aaronth07 on topic Grey gamma
Great work!

Please Log in or Create an account to join the conversation.

We use cookies
We use cookies on our website. Some of them are essential for the operation of the forum. You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.