Color curves

This shader adjusts colors with curves, similar to the filter found in art/photo editing software such as Krita and GIMP. Supports RGB, Red, Green, Blue, Alpha, Hue, Saturation and Value channels. It takes a CurveTexture as a uniform sampler2D for each channel.

NOTE: This shader only works as intended using the GLES2 renderer. On GLES3, the result is an entirely white texture. To fix this, simply replace all of the `.a`s to `.r`s in the texture() functions. I have not tested this shader on Godot 4 yet.

Artwork in the cover image is made by Erevoid, with Pixelorama.

Shader code
shader_type canvas_item;

// CurveTexture(s)
uniform sampler2D rgb_curve;
uniform sampler2D red_curve;
uniform sampler2D green_curve;
uniform sampler2D blue_curve;
uniform sampler2D alpha_curve;
uniform sampler2D hue_curve;
uniform sampler2D sat_curve;
uniform sampler2D value_curve;

vec3 rgb2hsb(vec3 c) {
	vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
	vec4 p = mix(vec4(, K.wz),
				vec4(, K.xy),
				step(c.b, c.g));
	vec4 q = mix(vec4(p.xyw, c.r),
				vec4(c.r, p.yzx),
				step(p.x, c.r));
	float d = q.x - min(q.w, q.y);
	float e = 1.0e-10;
	return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
				d / (q.x + e),

vec3 hsb2rgb(vec3 c)
	vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
	vec3 p = abs(fract( + * 6.0 - K.www);
	return c.z * mix(, clamp(p -, 0.0, 1.0), c.y);

void fragment() {
	COLOR = texture(TEXTURE, UV);

	float red_curve_color = texture(red_curve, vec2(COLOR.r, 0.0)).a;
	float green_curve_color = texture(green_curve, vec2(COLOR.g, 0.0)).a;
	float blue_curve_color = texture(blue_curve, vec2(COLOR.b, 0.0)).a;
	float alpha_curve_color = texture(alpha_curve, vec2(COLOR.a, 0.0)).a;
	COLOR.r = red_curve_color;
	COLOR.g = green_curve_color;
	COLOR.b = blue_curve_color;
	COLOR.a = alpha_curve_color;
	vec3 hsb = rgb2hsb(COLOR.rgb);
	float hue_curve_color = texture(hue_curve, vec2(hsb.r, 0.0)).a;
	float sat_curve_color = texture(sat_curve, vec2(hsb.g, 0.0)).a;
	float value_curve_color = texture(value_curve, vec2(hsb.b, 0.0)).a;
	hsb.r = hue_curve_color;
	hsb.g = sat_curve_color;
	hsb.b = value_curve_color;

	COLOR.rgb = hsb2rgb(hsb);

	float rgb_curve_color_r = texture(rgb_curve, vec2(COLOR.r, 0.0)).a;
	float rgb_curve_color_g = texture(rgb_curve, vec2(COLOR.g, 0.0)).a;
	float rgb_curve_color_b = texture(rgb_curve, vec2(COLOR.b, 0.0)).a;
	COLOR.rgb = vec3(rgb_curve_color_r, rgb_curve_color_g, rgb_curve_color_b);
color adjustment, color correction, color curves, color filter, filter
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Overloaded

Linear Gradient

Related shaders

color splash (show only one color)

16 Bit Color (C64-Like) with Dither

Ultimate Gameboy (Color) Shader

Notify of

Newest Most Voted
Inline Feedbacks
View all comments
1 year ago

Thanks for making this shader!
Unfortunately, I cant get it to work on any texture (Sprite2D node).
Everything just shows up as white. Any instructions on how to use it?