Sign In

crabshank

User Group
Trusted Members
Join date
18-Oct-2018
Last activity
2-Dec-2018
Posts
2

Post History

Post
#1250040
Topic
Curves (based on G'MIC) and HSV dither hlsl
Time

Since I thought that the Curves function in G’MIC (GIMP) was very good for colour mapping, I wanted to use it for video in some way. So I created this code that lets you remap RGB and HSV values. It just does straight line interpolation, not curves.

sampler s0 : register(s0);
float4 p0 :  register(c0);
float4 p1 :  register(c1);

#define width   (p0[0])
#define height  (p0[1])
#define counter (p0[2])
#define clock   (p0[3])
#define one_over_width  (p1[0])
#define one_over_height (p1[1])


float3 rgb2hsv(float3 c)
{
    float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
    float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
 
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}


float3 hsv2rgb(float3 c)
{
    float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
//Source: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl

//Bounds for interpolation//
static float r_x_b[2]={0,1};static float r_y_b[2]={0,1};static float g_x_b[2]={0,1};static float g_y_b[2]={0,1};static float b_x_b[2]={0,1};static float b_y_b[2]={0,1};static float h_x_b[2]={0,1};static float h_y_b[2]={0,1};static float s_x_b[2]={0,1};static float s_y_b[2]={0,1};static float v_x_b[2]={0,1};static float v_y_b[2]={0,1};

#define red_points 3

static float2 r[red_points] = {
0, 0,    // row 1; x,y
128,128,
255,255
};


#define green_points 3

static float2 g[green_points] = {
0, 0,    // row 1; x,y
128,128,
255,255
};

#define blue_points 3

static float2 b[blue_points] = {
0, 0,    // row 1; x,y
128,128,
255,255
};


static float rotate_hues = 0; //-360 to 360

#define hue_points 7

static float2 h[hue_points] = {
0, 0,    // row 1; x,y
10,10,
120,128,
185,183,
294,302,
302,310,
360,360
};

#define sat_points 3

static float2 s[sat_points] = {
0, 0,    // row 1; x,y
69,80,
100,100
};

#define val_points 4

static float2 v[val_points]= {
0, 0,    // row 1; x,y
35,34,
77,84,
100,100
};


float red_map(float red){int i=0;int exact=0;for (i=0; i<red_points; i++) {if (r[i][0]/255 == red ){red=r[i][1]/255;exact=1;break;}else if (r[i][0]/255 < red && r[i][0]/255>r_x_b[0]){r_x_b[0]=r[i][0]/255;r_y_b[0]=r[i][1]/255;}else if(r[i][0]/255 > red && r[i][0]/255<r_x_b[1]){r_x_b[1]=r[i][0]/255;r_y_b[1]=r[i][1]/255;}}if(exact=0){red=red;}else{red=r_y_b[0] + (red-r_x_b[0])*((r_y_b[1]-r_y_b[0])/(r_x_b[1]-r_x_b[0]));}return red;}

float green_map(float green){int i=0;int exact=0;for (i=0; i<green_points; i++) {if (g[i][0]/255 == green ){green=g[i][1]/255;exact=1;break;}else if (g[i][0]/255 < green && g[i][0]/255>g_x_b[0]){g_x_b[0]=g[i][0]/255;g_y_b[0]=g[i][1]/255;}else if(g[i][0]/255 > green && g[i][0]/255<g_x_b[1]){g_x_b[1]=g[i][0]/255;g_y_b[1]=g[i][1]/255;}}if(exact=0){green=green;}else{green=g_y_b[0] + (green-g_x_b[0])*((g_y_b[1]-g_y_b[0])/(g_x_b[1]-g_x_b[0]));}return green;}

float blue_map(float blue){int i=0;int exact=0;for (i=0; i<blue_points; i++) {if (b[i][0]/255 == blue ){blue=b[i][1]/255;exact=1;break;}else if (b[i][0]/255 < blue && b[i][0]/255>b_x_b[0]){b_x_b[0]=b[i][0]/255;b_y_b[0]=b[i][1]/255;}else if(b[i][0]/255 > blue && b[i][0]/255<b_x_b[1]){b_x_b[1]=b[i][0]/255;b_y_b[1]=b[i][1]/255;}}if(exact=0){blue=blue;}else{blue=b_y_b[0] + (blue-b_x_b[0])*((b_y_b[1]-b_y_b[0])/(b_x_b[1]-b_x_b[0]));}return blue;}

float hue_rotate(float hue, float rot){rot*=pow(360,-1); float r=hue+rot; if (r<0){return 1+rot;}else if(r>1){return 0+rot;}else{return r;}}     
                                                                                                 
float hue_map(float hue) { int i = 0; int exact = 0; for (i = 0; i < hue_points; i++) { if (h[i][0] / 360 == hue) { hue = h[i][1] / 360; exact = 1; break; } else if (h[i][0] / 360 < hue && h[i][0] / 360 > h_x_b[0]) { h_x_b[0] = h[i][0] / 360; h_y_b[0] = h[i][1] / 360; } else if (h[i][0] / 360 > hue && h[i][0] / 360 < h_x_b[1]) { h_x_b[1] = h[i][0] / 360; h_y_b[1] = h[i][1] / 360; } } if (exact = 0) { hue = hue; } else { hue = h_y_b[0] + (hue - h_x_b[0]) * ((h_y_b[1] - h_y_b[0]) / (h_x_b[1] - h_x_b[0])); } return hue; }

float sat_map(float sat) { int i = 0; int exact = 0; for (i = 0; i < sat_points; i++) { if (s[i][0] / 100 == sat) { sat = s[i][1] / 100; exact = 1; break; } else if (s[i][0] / 100 < sat && s[i][0] / 100 > s_x_b[0]) { s_x_b[0] = s[i][0] / 100; s_y_b[0] = s[i][1] / 100; } else if (s[i][0] / 100 > sat && s[i][0] / 100 < s_x_b[1]) { s_x_b[1] = s[i][0] / 100; s_y_b[1] = s[i][1] / 100; } } if (exact = 0) { sat = sat; } else { sat = s_y_b[0] + (sat - s_x_b[0]) * ((s_y_b[1] - s_y_b[0]) / (s_x_b[1] - s_x_b[0])); } return sat; }

float val_map(float val) { int i = 0; int exact = 0;  for (i = 0; i < val_points; i++) { if (v[i][0] / 100 == val) { val = v[i][1] / 100; exact = 1; break; } else if (v[i][0] / 100 < val && v[i][0] / 100 > v_x_b[0]) { v_x_b[0] = v[i][0] / 100; v_y_b[0] = v[i][1] / 100; } else if (v[i][0] / 100 > val && v[i][0] / 100 < v_x_b[1]) { v_x_b[1] = v[i][0] / 100; v_y_b[1] = v[i][1] / 100; } } if (exact = 0) { val = val; } else { val = v_y_b[0] + (val - v_x_b[0]) * ((v_y_b[1] - v_y_b[0]) / (v_x_b[1] - v_x_b[0])); } return val; }

float4 main(float2 tex : TEXCOORD0) : COLOR {
	float4 c0 = tex2D(s0, tex);

//c0.r=red_map(c0.r);		//red
//c0.g=green_map(c0.g);	//green
//c0.b=blue_map(c0.b);	//blue


float3 colorHSV= rgb2hsv(c0.rgb);
//colorHSV.x=hue_rotate(colorHSV.x,rotate_hues); c0.rgb=hsv2rgb(colorHSV); colorHSV= rgb2hsv(c0.rgb); //hue rotate
colorHSV.x=hue_map(colorHSV.x); c0.rgb=hsv2rgb(colorHSV); colorHSV= rgb2hsv(c0.rgb); //hue
colorHSV.y=sat_map(colorHSV.y); c0.rgb=hsv2rgb(colorHSV); colorHSV= rgb2hsv(c0.rgb); //sat
colorHSV.z=val_map(colorHSV.z); c0.rgb=hsv2rgb(colorHSV); colorHSV= rgb2hsv(c0.rgb); //val
	return c0;
}

Here’s the HSV dither:

// $MinimumShaderProfile: ps_3_0


/* ---  Defining Constants --- */
#define myTex2D(s,p) tex2D(s,p)

#ifndef s0
  sampler s0 : register(s0);
  #define s1 s0
//sampler s1 : register(s1);

  float4 p0 : register(c0);
  float4 p1 : register(c1);

//  #define width (p0[0])
//  #define height (p0[1])
//  #define counter (p0[2])
//  #define clock (p0[3])
//  #define px (p1[0]) //one_over_width 
//  #define py (p1[1]) //one_over_height

  #define px (p1.x) //one_over_width 
  #define py (p1.y) //one_over_height
  
  #define screen_size float2(p0.x,p0.y)

  #define pixel float2(px,py)

//#define pxy float2(p1.xy)

//#define PI acos(-1)
#endif

// Author: Michael Pohoreski
// Copyright: Copyleft 2012 :-)
float random( float2 p )
{
  // We need irrationals for pseudo randomness.
  // Most (all?) known transcendental numbers will (generally) work.
  const float2 r = float2(
    23.1406926327792690,  // e^pi (Gelfond's constant)
     2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant)
  return frac( cos( fmod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );  
}



float3 rgb2hsv(float3 c)
{
    float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
    float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
 
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}


float3 hsv2rgb(float3 c)
{
    float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
} 
//Source: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl



float3 h_dither(float3 colorHSV,float2 tex,float rnd){
 // float dither_bit  = 8.0; 

float rand=(2*ceil((rnd+1)*random(float2(tex.x*colorHSV.x,tex.y*colorHSV.x))))-2-rnd; //-rnd to rnd

     //shift the halue by dither_shift
colorHSV.x= saturate(colorHSV.x+rand/100);
 float3 color = hsv2rgb(colorHSV);

   return color;
}


float3 s_dither(float3 colorHSV,float2 tex,float rnd){
 // float dither_bit  = 8.0; 

float rand=(2*ceil((rnd+1)*random(float2(tex.x*colorHSV.y,tex.y*colorHSV.y))))-2-rnd; //-rnd to rnd

     //shift the value by dither_shift
colorHSV.y= saturate(colorHSV.y+(rand/10));

 float3 color = hsv2rgb(colorHSV);

   return color;
}


float3 v_dither(float3 colorHSV,float2 tex,float rnd){
 // float dither_bit  = 8.0; 

float rand=(2*ceil((rnd+1)*random(float2(tex.x*colorHSV.z,tex.y*colorHSV.z))))-2-rnd; //-rnd to rnd

     //shift the value by dither_shift
colorHSV.z= saturate(colorHSV.z+(rand/100));

 float3 color = hsv2rgb(colorHSV);

   return color;
}

/* --- Main --- */

float4 main(float2 tex : TEXCOORD0) : COLOR {
	float4 c0 = tex2D(s0, tex);

  
float3 colorHSV= rgb2hsv(c0);
//c0.rgb=h_dither(colorHSV,tex,2); colorHSV= rgb2hsv(c0);


//c0.rgb=s_dither(colorHSV,tex,1); colorHSV= rgb2hsv(c0);


//c0.rgb =v_dither(colorHSV,tex,5); //colorHSV= rgb2hsv(c0);  NOT NECESSARY AS LAST

	return c0;

}