Parametric Linear RGB Dimmer
This shader allows for parametric dimming of individual RGB channels, providing control over the intensity of red, green, and blue values. The effect can be restricted to specific regions of the element using a height-based parameter, allowing for dynamic on/off transitions. This shader has a parameter to apply only to visible areas as well, making it perfect for overlays
Originally designed to simulate a “missing HP” effect for character portraits, inspired by classic cRPGs like Baldur’s Gate 1 & 2, the shader visually represents depleted health in a clear and striking manner.
Additional features, such as rotation and region-reversal options, were added to increase versatility, making the shader adaptable to a wide variety of use cases, including diagonal and horizontal effects.
Shader code
shader_type canvas_item;
// Parameters to control the damping factors for red, green, and blue channels
uniform float red_factor : hint_range(0.0, 1.0) = 1.0;
uniform float green_factor : hint_range(0.0, 1.0) = 1.0;
uniform float blue_factor : hint_range(0.0, 1.0) = 1.0;
// Parameter to control the alpha factor
uniform float alpha_factor : hint_range(0.0, 1.0) = 1.0;
// Parameter to control the height percentage of the shader effect
uniform float height_percent : hint_range(0.0, 100.0) = 50.0;
// Boolean to reverse the order of height influence
uniform bool reverse_order = false;
// Boolean to apply rotation to the height parameter
uniform bool apply_rotation = false;
// Boolean to affect only visible (fully opaque) pixels
uniform bool affect_only_visible = false;
// Rotation angle in radians (applied if apply_rotation is true)
uniform float rotation_angle : hint_range(0.0, 6.28319) = 0.0; // 0 to 2*PI
void fragment() {
// If `affect_only_visible` is true and alpha is less than 1, do nothing.
if (affect_only_visible && COLOR.a < 1.0) {
// COLOR remains unchanged.
} else {
// Calculate the UV based on the local space of the element
vec2 uv = UV;
// Apply rotation if the flag is enabled
if (apply_rotation) {
float cos_angle = cos(rotation_angle);
float sin_angle = sin(rotation_angle);
uv = vec2(
uv.x * cos_angle - uv.y * sin_angle,
uv.x * sin_angle + uv.y * cos_angle
);
}
float relative_height = uv.y;
// Convert height_percent to a normalized value (0.0 to 1.0)
float height_threshold = height_percent / 100.0;
// Reverse the order if the reverse_order flag is set
if (reverse_order) {
relative_height = 1.0 - relative_height;
}
// Apply the shader only if the fragment is within the specified height range
if (relative_height <= height_threshold) {
// Reduce the red, green, and blue channels by their respective factors
COLOR.rgb = vec3(COLOR.r * red_factor, COLOR.g * green_factor, COLOR.b * blue_factor);
// Adjust the alpha channel
COLOR.a *= alpha_factor;
} else {
// Keep the original color below the height threshold
COLOR = texture(TEXTURE, UV);
}
}
}