Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Optimised Hue shift function in GLSL
vec3 hueShift( vec3 color, float hueAdjust ){
const vec3 kRGBToYPrime = vec3 (0.299, 0.587, 0.114);
const vec3 kRGBToI = vec3 (0.596, -0.275, -0.321);
const vec3 kRGBToQ = vec3 (0.212, -0.523, 0.311);
const vec3 kYIQToR = vec3 (1.0, 0.956, 0.621);
const vec3 kYIQToG = vec3 (1.0, -0.272, -0.647);
const vec3 kYIQToB = vec3 (1.0, -1.107, 1.704);
float YPrime = dot (color, kRGBToYPrime);
float I = dot (color, kRGBToI);
float Q = dot (color, kRGBToQ);
float hue = atan (Q, I);
float chroma = sqrt (I * I + Q * Q);
hue += hueAdjust;
Q = chroma * sin (hue);
I = chroma * cos (hue);
vec3 yIQ = vec3 (YPrime, I, Q);
return vec3( dot (yIQ, kYIQToR), dot (yIQ, kYIQToG), dot (yIQ, kYIQToB) );
}
@janpaul123
Copy link

janpaul123 commented Nov 26, 2020

@RichardBray
Copy link

RichardBray commented Nov 27, 2020

@janpaul123 Thanks that makes more sense. But yeah I still can't figure out how that formula was reached.

@tarikbarri
Copy link

tarikbarri commented Jan 22, 2021

Thank you so much for this! Contrary to what you seem to think though, your original function produces much more natural looking/beautiful results than the cheaper hueshift function provided by @viruseg. Of course it depends on context whether or not that's needed, but I for one deeply appreciate it!
EDIT but, I believe this is a faster implementation ->

vec2 rotate2(vec2 v, float fi) {
return v*mat2(cos(fi), -sin(fi), sin(fi), cos(fi));
}

// YIQ color rotation/hue shift
vec3 hueShiftYIQ(vec3 rgb, float hs) {
float rotAngle = hs*-6.28318530718;
const mat3 rgb2yiq = mat3(0.299, 0.596, 0.211,
0.587, -0.274, -0.523,
0.114, -0.322, 0.312);
const mat3 yiq2rgb = mat3(1, 1, 1,
0.956, -0.272, -1.106,
0.621, -0.647, 1.703);
vec3 yiq = rgb2yiq * rgb;
yiq.yz *= rot(rotAngle);
return yiq2rgb * yiq;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment