Welcome, Guest.
Username: Password: Remember me

TOPIC: Grey gamma

Grey gamma 2 months 1 week ago #1

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 = 10.0;
> = 2.0;

uniform float Gamma_Highs < __UNIFORM_DRAG_FLOAT1
	ui_min = -1.0; ui_max = 10.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 = 7.0;
> = 1.0;

uniform bool Split <> = false;

uniform bool Flip_split <> = false;

uniform float Split_position < __UNIFORM_SLIDER_FLOAT1
	ui_min = 0; ui_max =1;
	ui_tooltip = "0 is on the far left, 1 on the far right.";
> = 0.5;

#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;

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);
color.rgb=lerp(c1.rgb,c2.rgb,color.rgb);

float4 c3=(texcoord.x>=Split_position*Split)?color:colorOrig;
float4 c4=(texcoord.x<=Split_position*Split)?color:colorOrig;

float4 c5=(Flip_split==1 && Split==1)?c4:c3;

float divLine = abs(texcoord.x - Split_position) < BUFFER_RCP_WIDTH;
c5 =(Split==0)?c5: c5*(1.0 - divLine); //invert divline

c5.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):c5.rgb;

c5.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):c5.rgb;

float4 res =float4(c5.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);
						

}


c5.rgb=res.rgb;


return c5;

}

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.

The .hlsl version is here.
Last Edit: 2 weeks 1 day ago by crabshank. Reason: Modded DrawText header
The administrator has disabled public write access.
The following user(s) said Thank You: Wicked Sick, jas01, turgor128, Faustus86

Grey gamma 2 months 1 week ago #2

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 administrator has disabled public write access.
The following user(s) said Thank You: Wicked Sick, crabshank

Grey gamma 2 months 1 week ago #3

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: 2 months 1 week ago by crabshank.
The administrator has disabled public write access.

Grey gamma 2 months 1 week ago #4

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: 2 months 1 week ago by jas01. Reason: .
The administrator has disabled public write access.
The following user(s) said Thank You: crabshank

Grey gamma 2 months 6 days ago #5

Optimised ^
The administrator has disabled public write access.

Grey gamma 1 month 2 days ago #6

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 administrator has disabled public write access.
The following user(s) said Thank You: jas01

Grey gamma 1 month 13 hours ago #7

UPDATE: Added 2D input. I have also changed the UI for the gamma inputs back to drags.
The administrator has disabled public write access.