xy Primaries Adjuster

  • Posts: 54
5 months 3 weeks ago - 2 weeks 5 days ago #1 by crabshank
After doing my white point shader I knew that the primaries defined the colour space too, but I hadn't got around to doing anything with them, until I made this shader. So, this one lets you change the primaries.


https://en.wikipedia.org/wiki/RGB_color_space

Just to demo, you could change the Red in RGB to an orange.

#include "ReShadeUI.fxh"

uniform float2 Red < __UNIFORM_DRAG_FLOAT2
	ui_min = 0.0; ui_step=0.000001; ui_max = 1.0;
> =float2(0.64,0.33);

uniform float2 Green < __UNIFORM_DRAG_FLOAT2
	ui_min = 0.0; ui_step=0.000001; ui_max = 1.0;
> =float2(0.3,0.6);

uniform float2 Blue < __UNIFORM_DRAG_FLOAT2
	ui_min = 0.0; ui_step=0.000001; ui_max = 1.0;
> =float2(0.15,0.06);

uniform bool Two_dimensional_input <> = false;

uniform int Two_dimensional_input_primary <__UNIFORM_COMBO_INT1
    ui_items = "Red\0Green\0Blue\0";
	> = 0;

uniform int Two_dimensional_input_type <__UNIFORM_COMBO_INT1
    ui_items = "Crosshairs on\0Crosshairs off\0Direct point-based\0";
	> = 0;

uniform float Two_dimensional_input_Range < __UNIFORM_SLIDER_FLOAT1
	ui_min = 2; ui_max = 0.0;
> = 1.89;

uniform bool Debug <> = false;

uniform int Debug_type <__UNIFORM_COMBO_INT1
    ui_items = "Distance from pure primary\0Colour bars\0";
	> = 0;

uniform float Debug_amplification < __UNIFORM_DRAG_FLOAT1
	ui_min = 0.0000001; ui_max =2;
	ui_tooltip = "A lower value exaggerates small differences more";
> = 0.5;
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"; >;

float3x3 invThreeByThreeMatrix(float3x3 mtx){

float el_A=mtx[1][1]*mtx[2][2]-mtx[1][2]*mtx[2][1];
float el_B=-(mtx[1][0]*mtx[2][2]-mtx[1][2]*mtx[2][0]);
float el_C=mtx[1][0]*mtx[2][1]-mtx[1][1]*mtx[2][0];
float el_D=-(mtx[0][1]*mtx[2][2]-mtx[0][2]*mtx[2][1]);
float el_E=mtx[0][0]*mtx[2][2]-mtx[0][2]*mtx[2][0];
float el_F=-(mtx[0][0]*mtx[2][1]-mtx[0][1]*mtx[2][0]);
float el_G=mtx[0][1]*mtx[1][2]-mtx[0][2]*mtx[1][1];
float el_H=-(mtx[0][0]*mtx[1][2]-mtx[0][2]*mtx[1][0]);
float el_I=mtx[0][0]*mtx[1][1]-mtx[0][1]*mtx[1][0];

float det=mtx[0][0]*el_A+mtx[0][1]*el_B+mtx[0][2]*el_C;

float invDet=1/det;

float3x3 outp=invDet*float3x3(el_A,el_D,el_G,
el_B,el_E,el_H,
el_C,el_F,el_I);

    return outp;
}

float3 Primaryconv(float2 red, float2 green, float2 blue, float3 XYZ){

float3 XYZ_r=float3(red.xy,1-red.x-red.y);
float3 XYZ_g=float3(green.xy,1-green.x-green.y);
float3 XYZ_b=float3(blue.xy,1-blue.x-blue.y);

float3x3 XYX_rgb=float3x3(XYZ_r.x,XYZ_g.x,XYZ_b.x,
XYZ_r.y,XYZ_g.y,XYZ_b.y,
XYZ_r.z,XYZ_g.z,XYZ_b.z);

float3x3 inv_XYZ_rgb=invThreeByThreeMatrix(XYX_rgb);

float3 s_XYZ=mul(inv_XYZ_rgb,float3(0.95047,1,1.08883));

float3x3 s_mat=float3x3(s_XYZ.x,0,0,
0,s_XYZ.y,0,
0,0,s_XYZ.z);

float3x3 inv_s_mat=invThreeByThreeMatrix(mul(XYX_rgb,s_mat));

float3 rgb=mul(inv_s_mat,XYZ);
rgb=( rgb > 0.00313066844250063 )?1.055 * pow(abs(rgb),1/2.4) - 0.055:12.92 *rgb;
return rgb;

}
//Source: http://www.ryanjuckett.com/programming/rgb-color-space-conversion/


float3 rgb2xyY(float3 rgb){

    float3 rgbNew=float3(rgb.r,rgb.g,rgb.b); 

	float3 XYZ;

	rgbNew=(rgbNew > 0.0404482362771082)?pow(abs((rgbNew+0.055)/1.055),2.4):rgbNew/12.92;

		XYZ.x = dot(float3(0.4124564,0.3575761, 0.1804375), rgbNew);
		XYZ.y = dot(float3(0.2126729,0.7151522,0.072175), rgbNew);
		XYZ.z = dot(float3(0.0193339,0.119192,0.9503041), rgbNew);

	float XYZtot=XYZ.x+XYZ.y+XYZ.z;
	
	float x=XYZ.x/XYZtot;
	float y=XYZ.y/XYZtot;
	
	return float3(x,y,XYZ.y);

}

//Source: https://stackoverflow.com/a/45263428; http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html


float3 rgb2XYZ(float3 rgb){

    float3 rgbNew=rgb; 

	float3 XYZ;

	rgbNew=(rgbNew > 0.0404482362771082)?pow(abs((rgbNew+0.055)/1.055),2.4):rgbNew/12.92;

		XYZ.x = dot(float3(0.4124564,0.3575761, 0.1804375), rgbNew);
		XYZ.y = dot(float3(0.2126729,0.7151522,0.072175), rgbNew);
		XYZ.z = dot(float3(0.0193339,0.119192,0.9503041), rgbNew);

	return XYZ;
}

//Source: https://stackoverflow.com/a/45263428; http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html


float4 PrimariesChangePass2D(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{

float4 c0 = tex2D(ReShade::BackBuffer, texcoord);

float2 Customxy;

float2 Red=Red;
float2 Green=Green;
float2 Blue=Blue;

[flatten]if(Two_dimensional_input_primary==0){
Customxy=Red;
}else if(Two_dimensional_input_primary==1){
Customxy=Green;
}else if(Two_dimensional_input_primary==2){
Customxy=Blue;
}

float x_Range=(BUFFER_WIDTH>=BUFFER_HEIGHT)?Two_dimensional_input_Range*(BUFFER_RCP_HEIGHT/BUFFER_RCP_WIDTH):Two_dimensional_input_Range;

float y_Range=(BUFFER_WIDTH>=BUFFER_HEIGHT)?Two_dimensional_input_Range:Two_dimensional_input_Range*(BUFFER_RCP_WIDTH/BUFFER_RCP_HEIGHT);

Customxy.x= ((Two_dimensional_input==1 && Debug_type==1 && buttondown==1)||(buttondown==0 && Two_dimensional_input==1))?  mousepoint.x*ReShade::PixelSize.x*((Customxy.x+0.5*x_Range)-(Customxy.x-0.5*x_Range))+(Customxy.x-0.5*x_Range):Customxy.x;

float xCoord_Pos=((Two_dimensional_input==1 && Debug_type==1 && buttondown==1)||(buttondown==1 && Two_dimensional_input==1))?(Customxy.x-(Customxy.x-0.5*x_Range))/((Customxy.x+0.5*x_Range)-(Customxy.x-0.5*x_Range)):mousepoint.x*ReShade::PixelSize.x;

Customxy.y= ((Two_dimensional_input==1 && Debug_type==1 && buttondown==1)||(buttondown==0 && Two_dimensional_input==1))?mousepoint.y*ReShade::PixelSize.y*((Customxy.y+0.5*y_Range)-(Customxy.y-0.5*y_Range))+(Customxy.y-0.5*y_Range):Customxy.y;

float yCoord_Pos=(buttondown==1 && Two_dimensional_input==1)?(Customxy.y-(Customxy.y-0.5*y_Range))/((Customxy.y+0.5*y_Range)-(Customxy.y-0.5*y_Range)):mousepoint.y*ReShade::PixelSize.y;

float4 c1=c0;

Customxy=(Two_dimensional_input==1 && Two_dimensional_input_type==2)?rgb2xyY(tex2D(ReShade::BackBuffer, mousepoint*ReShade::PixelSize).rgb).xy:Customxy;

[flatten]if(Two_dimensional_input==1 && Two_dimensional_input_primary==0){
Red=Customxy;
}else if(Two_dimensional_input==1 && Two_dimensional_input_primary==1){
Green=Customxy;
}else if(Two_dimensional_input==1 && Two_dimensional_input_primary==2){
Blue=Customxy;
}

c1.rgb=Primaryconv(Red,Green,Blue,rgb2XYZ(c0.rgb));

float3 dbgCol=float3(0,0,0);

[flatten]if(Debug==1){

dbgCol=(texcoord.x<=pow(3,-1))?float3(1,0,0):dbgCol;
dbgCol=(texcoord.x>pow(3,-1) && texcoord.x<=2*pow(3,-1))?float3(0,1,0):dbgCol;
dbgCol=(texcoord.x>2*pow(3,-1))?float3(0,0,1):dbgCol;

float2 OGxy=rgb2xyY(c0.rgb).xy;
float2 Currxy=rgb2xyY(c1.rgb).xy;

[flatten]if(Two_dimensional_input_primary==0){

[flatten]if(Debug_type==0){
c1.rgb=pow(min(1,sqrt(pow(0.64-Currxy.x,2)+pow(0.33-Currxy.y,2))),Debug_amplification);
c0.rgb=(Split==1)?pow(min(1,sqrt(pow(0.64-OGxy.x,2)+pow(0.33-OGxy.y,2))),Debug_amplification):c0.rgb;
}else{
c1.rgb=(buttondown==1)?c1.rgb:Primaryconv(Red,Green,Blue,rgb2XYZ(dbgCol));
c0.rgb=c1.rgb;
}

}else if(Two_dimensional_input_primary==1){

[flatten]if(Debug_type==0){
c1.rgb=pow(min(1,sqrt(pow(0.3-Currxy.x,2)+pow(0.6-Currxy.y,2))),Debug_amplification);
c0.rgb=(Split==1)?pow(min(1,sqrt(pow(0.3-OGxy.x,2)+pow(0.6-OGxy.y,2))),Debug_amplification):c0.rgb;
}else{
c1.rgb=(buttondown==1)?c1.rgb:Primaryconv(Red,Green,Blue,rgb2XYZ(dbgCol));
c0.rgb=c1.rgb;
}

}else if(Two_dimensional_input_primary==2){

[flatten]if(Debug_type==0){
c1.rgb=pow(min(1,sqrt(pow(0.15-Currxy.x,2)+pow(0.06-Currxy.y,2))),Debug_amplification);
c0.rgb=(Split==1)?pow(min(1,sqrt(pow(0.15-OGxy.x,2)+pow(0.06-OGxy.y,2))),Debug_amplification):c0.rgb;
}else{
c1.rgb=(buttondown==1)?c1.rgb:Primaryconv(Red,Green,Blue,rgb2XYZ(dbgCol));
c0.rgb=c1.rgb;
}

}
}

float4 c2=(texcoord.x>=Split_position*Split)?c1:c0;
float4 c3=(texcoord.x<=Split_position*Split)?c1:c0;

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

float divLine = abs(texcoord.x - Split_position) < BUFFER_RCP_WIDTH;
c4 =(Split==0 || (Debug==1 && Debug_type==1))?c4: c4*(1.0 - divLine); //invert divline

c4.rgb =(Two_dimensional_input==1 && Two_dimensional_input_type==0 && (abs(texcoord.x-xCoord_Pos)<BUFFER_RCP_WIDTH || abs(texcoord.y-yCoord_Pos)<BUFFER_RCP_HEIGHT))?float3(0.369,0.745,0):c4.rgb;

c4.rgb =((Two_dimensional_input==1 && Two_dimensional_input_type==1 && (abs(texcoord.x-xCoord_Pos)<3*BUFFER_RCP_WIDTH && abs(texcoord.y-yCoord_Pos)<3*BUFFER_RCP_HEIGHT))||(Two_dimensional_input==1 && buttondown==1 && Debug==1 && Debug_type==1)&& (abs(texcoord.x-mousepoint.x*ReShade::PixelSize.x)<3*BUFFER_RCP_WIDTH && abs(texcoord.y-mousepoint.y*ReShade::PixelSize.y)<3*BUFFER_RCP_HEIGHT) && Two_dimensional_input_type!=2)?float3(0.498,1,0):c4.rgb;

float4 res =float4(c4.rgb,0);

float textSize=25;

[flatten]if(Two_dimensional_input==1){
    DrawText_Digit(   DrawText_Shift(DrawText_Shift(float2(0.5*BUFFER_WIDTH,0), int2(-14, 0), textSize, 1), int2(8, 0), textSize, 1) , 
						textSize, 1, texcoord,  3, Customxy.x, res,0);
						
						    DrawText_Digit(   DrawText_Shift(DrawText_Shift(float2(0.5*BUFFER_WIDTH,0), int2(-5, 0), textSize, 1), int2(8, 0), textSize, 1) , 
						textSize, 1, texcoord,  3,  Customxy.y, res,0);
}

c4.rgb=res.rgb;

return c4;

}

technique xy_Primaries_2D
{
	pass
	{
		VertexShader = PostProcessVS;
		PixelShader = PrimariesChangePass2D;
	}
}

Version with no debug mode: here
Video shader version here
The following user(s) said Thank You: jas01, Cul, YF

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

  • Posts: 54
5 months 3 weeks ago #2 by crabshank
All my shaders that use my modded DrawText header have been updated, so make sure to grab the new versions.

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

  • Posts: 54
3 months 4 days ago #3 by crabshank
Added version with no debugging for more speed.

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

  • Posts: 54
2 weeks 5 days ago #4 by crabshank
UPDATE: Removed bloat.

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