Creating a hue shift shader

wooden dock hue shifted

Learn how to create a hue shift shader using the GLSL programming language and the YIQ colour space.

Introduction

For this tutorial I am going to port the YIQ algorithm from this GameMaker tutorial to GLSL. I picked the YIQ version because I think it looks the best. But the tutorial also shows you how to create an HSV version and a Rodrigues’ rotation formula version.

I will use this beautiful wooden dock image for the tutorial.

wooden dock
Wooden dock

YIQ

Define a matrix to convert a RGB colour to YIQ.

const mat3 YIQ_CONVERT = mat3(
	0.299, 0.596, 0.211,
	0.587, -0.274, -0.523,
	0.114, -0.322, 0.312
);

Next define a function which uses the matrix.

vec3 ToYIQ(vec3 colour)
{
	return YIQ_CONVERT * colour;
}

RGB

Define a matrix which converts YIQ back to RGB.

const mat3 RGB_CONVERT = mat3(
	1.0, 1.0, 1.0,
	0.956, -0.272, -1.106,
	0.621, -0.647, 1.703
);

Next define a function which uses the matrix.

vec3 ToRGB(vec3 colour)
{
	return RGB_CONVERT * colour;
}

Shift uniform

Create a uniform called shift. The expected input is radians in the range of 0 to 2PI.

uniform float shift = 0.0f;

Hue Shift

Create a hue shift function which will use the two colour conversion functions we created.

vec3 HueShift(vec3 colour)
{
	vec3 yiq = ToYIQ(colour);

	mat2 rotMatrix = mat2(
		cos(shift), -sin(shift),
		sin(shift), cos(shift)
	);
	yiq.yz *= rotMatrix;

	return ToRGB(yiq);
}

First convert the RGB value to YIQ.

vec3 yiq = ToYIQ(colour);

Next define a rotation matrix using the shift uniform we pass in. This will control the hue shift. Multiply the rotation matrix against two of the YIQ components.

	mat2 rotMatrix = mat2(
		cos(shift), -sin(shift),
		sin(shift), cos(shift)
	);
	yiq.yz *= rotMatrix;

Lastly convert back to RGB, and return the result!

return ToRGB(yiq);

Output

Set the fragment output colour to the current texture colour inside the shader main function. Then pass the RGB part into the hue shift function we created earlier. The result of the function will change the hue of the texture colour.

void main()
{
	fragColour = texture(textureUnit, texCoord);
	fragColour.rgb = HueShift(fragColour.rgb);
}

Set shift

Set the shift uniform outside of the shader. You can use the current time in seconds, modulus and 2PI to make the hue shift value loop around.

const float shift = std::fmodf(timeSeconds, TWO_PI);
hueShiftShader->Uniform1f("shift", shift);

Final result

Wooden dock hue shifted

Conclusion

Thank you for reading this tutorial. Let me know in the comments section if you enjoyed it, or have any questions!

8 responses to “Creating a hue shift shader”

Leave a reply to signalman Cancel reply