Blending modes

A common and simple way to add, for example, two textures together is with the mix() function. However, this function only does a linear interpolation between the two images and does not offer very much control. What if you want to get fancier and do it as you would in an image program, like Photoshop’s blend modes. You can absolutely do that with some math. Here are a few blending mode functions you can use.

Blending modes functions
Multiply     a * b
Screen       1 - (1 - a) * (1 - b)
Darken       min(a, b) 
Lighten      max(a, b) 
Difference   abs(a - b) 
Exclusion    a + b - 2 * a * b 
Overlay      a < 0.5 ? (2.0 * a * b) : (1.0 - 2.0 * (1.0 - a) * (1.0 - b)) 
Hard light   b < 0.5 ? (2.0 * a * b) : (1.0 - 2.0 * (1.0 - a) * (1.0 - b)) 
Soft light   b < 0.5 ? (2.0 * a * b + a * a * (1.0 - 2.0 * b)) : (sqrt(a) * (2.0 * b - 1.0) + (2.0 * a) * (1.0 - b)) 
Color dodge  a / (1.0 - b)
Linear dodge a + b
Burn         1.0 - (1 - a) / b
Linear burn  a + b - 1.0

Godot ready functions

Here are the blending modes above as functions ready to use in Godot. They all work by taking in texture/value base and blend and returning the blended result.

Multiply

vec4 multiply(vec4 base, vec4 blend){
	return base * blend;
}

Screen

vec4 screen(vec4 base, vec4 blend){
	return 1.0 - (1.0 - base) * (1.0 - blend);
}

Darken

vec4 darken(vec4 base, vec4 blend){
	return min(base, blend);
}

Lighten

vec4 lighten(vec4 base, vec4 blend){
	return max(base, blend);
}

Difference

vec4 difference(vec4 base, vec4 blend){
	return abs(base, blend);
}

Exclusion

vec4 exclusion(vec4 base, vec4 blend){
	return base + blend - 2.0 * base * blend;
}

Overlay

vec4 overlay(vec4 base, vec4 blend){
	vec4 limit = step(0.5, base);
	return mix(2.0 * base * blend, 1.0 - 2.0 * (1.0 - base) * (1.0 - blend), limit);
}

Hard light

vec4 hard_light(vec4 base, vec4 blend){
	vec4 limit = step(0.5, blend);
	return mix(2.0 * base * blend, 1.0 - 2.0 * (1.0 - base) * (1.0 - blend), limit);
}

Soft light

vec4 soft_light(vec4 base, vec4 blend){
	vec4 limit = step(0.5, blend);
	return mix(2.0 * base * blend + base * base * (1.0 - 2.0 * blend), sqrt(base) * (2.0 * blend - 1.0) + (2.0 * base) * (1.0 - blend), limit);
}

Color dodge

vec4 color_dodge(vec4 base, vec4 blend){
	return base / (1.0 - blend);
}

Linear dodge

vec4 linear_dodge(vec4 base, vec4 blend){
{
	return base + blend;
}

Color burn

vec4 color_burn(vec4 base, vec4 blend){
	return 1.0 - (1.0 - base) / blend;
}

Linear burn

vec4 linear_burn (vec4 base, vec4 blend)
{
	return base + blend - 1.0;
}