Creating a duotone gradient in a GLSL shader

Shan Shui sea, mountain and boat sprites with four different coloured duotone gradients applied

This tutorial will show you how to create a duotone gradient in a GLSL shader.

I will be using this Shan Shui style sprite I created in Aseprite.

Shan Shui mountain, sea and boat sprite

Step 1: Get pixel colour

Get the current pixel colour.

vec4 pixel = texture(textureUnit, texCoord);

Step 2: Convert to greyscale

Convert the pixel colour to greyscale.

const vec3 GREY_WEIGHTS = vec3(0.299f, 0.587f, 0.114f);
vec3 greyscalePixel = vec3(dot(pixel.rgb, GREY_WEIGHTS));
Greyscale Shan Shui mountain, sea and boat sprite

Step 3: Gradient

Determine the gradient direction using the texture coordinates. The texture coordinates are in the range of 0 to 1, and are used to create a greyscale gradient. This code will make a vertical gradient with the highlight starting at the top, and ending with the shadow at the bottom of the sprite.

float g = 1.0f - texCoord.y;

This is what we would get if we outputted the current gradient to the screen.

fragColour.rgb = vec3(g);
Vertical greyscale gradient

Step 4: Overlay

You will need to select two colours and pass them into the shader. I called the colours shadow and highlight.

uniform vec3 shadow;
uniform vec3 highlight;

Overlay the greyscale pixel with the mix of the shadow and highlight colours. The amount of highlight vs shadow is determined by the greyscale gradient value.

fragColour.rgb = Overlay(greyscalePixel, mix(shadow, highlight, g));

Here are the overlay functions, more information here.

float Overlay(float a, float b)
{
if(a < 0.5f) return 2.0f * a * b;
return 1.0f - 2.0f * (1.0f - a) * (1.0f - b);
}

vec3 Overlay(vec3 a, vec3 b)
{
float red = Overlay(a.r, b.r);
float green = Overlay(a.g, b.g);
float blue = Overlay(a.b, b.b);
return vec3(red, green, blue);
}

Step 5: Set pixel alpha

Finally set the output alpha to value of the current pixel alpha.

fragColour.a = pixel.a;

Feel free to experiment with different colours and gradients.

Shan Shui mountain, sea and boat sprite with yellow and blue duotone gradient applied
Shan Shui mountain, sea and boat sprite with cyan and red duotone gradient applied
Shan Shui mountain, sea and boat sprite with green and purple duotone gradient applied

Thank you for reading this tutorial, I hope you found it useful!

See this tutorial for how to create a duotone gradient in GIMP.

4 responses to “Creating a duotone gradient in a GLSL shader”

  1. Used a lot of gradients in my work I just go about it in a different approach. warps the mind sometimes thinking what it has to be before the gradient is applied, like having to blow out the lights or darks (over sat) so it’s muted in the after.

    As a former military training instructor I will say your instructions are well presented. thanks for your support of my project!
    ttfn sm101

    Liked by 1 person

    • Thanks for your comment, and your military service. Your content looks great also! It must be challenging to display portrait images on a landscape website background. I’ve been sticking to landscape and square images intentionally for my posts. I am sure you could write some interesting tutorials (if you had the time). Changing the image settings before applying the gradient definitely makes a difference.

      Liked by 1 person

      • In the beginning my work started with requests from friends for some custom wallpapers for their telegram chats and various banners for rumble content. I design mostly for mobile phones and tabs because most my people are professional telecom and the phone is where they are most of the time. So getting full view for some may require expanding but, expansion is a principle of our lives, if your not expanding your probably dead inside..

        Liked by 1 person

Leave a comment

Blog at WordPress.com.