Programmably adjust a Sprite-Color's „darkness and lightness“

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By pferft

Hi everyone,
this is my hundredth question! : D

I have a completely white Sprite Color-modulated to orange:

func _ready():
	modulate = Color(1, 0.5, 0)

I could put a black copy of the Sprite on top of it and then, for example, have it set 10, 20, 30… % transparent for different levels of darkening (or the other way around a white one for brightening (or “pale-ing”, it you like) - up until 0 % transparency for a complete black or white coverage respectively).

But is there any way to directly darken („blacken“) or lighten („whiten“) that colored Sprite like that in code (without needing the black and white copies on top)?

Could you modulate it to a darker orange?

SteveSmith | 2023-03-01 16:31

Decreasing the RGB’s R and G values would darken the orange, but in my case I’d need a different tweakable value to achieve the effect. Like values from a slider from 0 (black/dark) to 100 (white/bright) to be attached on top of the given RGB values in order to darken them or brighten them up.
I could imagine this might be doable with a shader, but I wouldn’t know how and I’d like to know if there are other ways as well…

pferft | 2023-03-01 16:42

Replying to my own post for sharing my solution.

Two HSliders: one for defining a color (HSliderColor) and the other one (HSliderBrightness) to brighten/darken that color. In this scenario the HSliderColor affects itself (my pure white Grabber-Sprite shows the results).

What I wanted is the HSliderBrightness to start left “completely dark” (black), gradually losing darkness moving right until reaching the middle position where the selected color stays untouched. Further to the right then “lightness” should increase until reaching “complete brightness” (white).

extends HSliderColor

var selected_color = 1
var selected_brightness = 1
var selected_darkness = 1
# (initial values to avoid crashing...)

func _on_HSliderColor_value_changed(value): # (it's colorizing itself...)

	selected_color = value # to take color down into darkness/brightness function
	var color = Color.from_hsv(value, selected_brightness, selected_darkness, 1)
	modulate = Color(color)


func _on_HSliderBrightness_value_changed(value):

	if value <= 0.5: # calculate useful darkness-value:
		var calc_darkness_value = value * 2
		var darkness = Color.from_hsv(selected_color, 1, calc_darkness_value, 1)
		modulate = Color(darkness)
		selected_darkness = calc_darkness_value # to take darkness up into color-function
		selected_brightness = 1 # just so things look right

	if value > 0.5: # calculate useful brightness-value:
		var calc_brightness_value = 1 - ((value - 0.5) * 2)
		var brightness = Color.from_hsv(selected_color, calc_brightness_value, 1, 1)
		modulate = Color(brightness)
		selected_brightness = calc_brightness_value # to take brightness up into color-function
		selected_darkness = 1 # just so things look right

The idea is to double the values below 0.5 in order to cover the whole dark-range from 0.0 to 1.0 by reaching the middle position, as well as doing the same for the bright range starting from 0.5 (and “turn them around” for increasing in the right direction…).

Thanks again to Wakatta for offering the crucial hint!

pferft | 2023-03-02 17:54

:bust_in_silhouette: Reply From: Wakatta

Adjust the HSV (Hue, Saturation, Value)

Hue

  • The color adjustment of the 3, Think of it as a color wheel from 0 to 360 degrees

Saturation

  • Adjust the grey portion of the color

Value

  • aka brightness or the intensity of the color

most likely adjusting both the H & V components should be it

#example
func _ready():
    var color = Color(1, 0.5, 0)
    color.s = 0.5
    color.v = 0.5
    modulate = color

You can use the HSV option in any color selector of Godot’s inspector, toggling the values to get an idea of how it works and what you want

Unfortunately your example throws the error
Invalid set index ‘hv’ (on base: ‘Color’) with value of type ‘int’.

But your hint is spot on! HSV seems to be the way to do this.

var selected_color
    
func _on_HSlider_value_changed(value):
	var color = Color.from_hsv(value, 1, 1, 1)
	modulate = Color(color)

	selected_color = color

This way a slider nicely changes the Sprite’s color gradually through the whole rainbow…

Looking into this I also found the possibilities with Color darkened and Color lightened to be very promising.

A different slider could deliver other values I could put into place in order to change the selected color’s lightness.

var selected_color
var selected_brightness
var selected_darkness
    
func _on_HSlider_value_changed(value):
	var color = Color.from_hsv(value, selected_brightness, selected_darkness, 1)
	modulate = Color(color)

	selected_color = color

func _on_HSliderBrightness_value_changed(value):
	if value == 0.3:
		selected_brightness = selected_color.lightened(0.3)
	if value == 0.7:
		selected_darkness = selected_color.darkened(0.7)

Or something like this, for example (didn’t test this one).

A problem could be that after changing the values of the “New” slider, selected_color would inherit the new variables and “start” with wrong values…
But I’ll see where this leads. Thank you very much for your suggestions!

EDIT:

Actually, this seems to show some effect as well:

func _on_HSlider_value_changed(value):

	var color = Color.from_hsv(value, selected_brightness, selected_darkness, 1)
	modulate = Color(color)
	selected_color = value



func _on_HSliderBrightness_value_changed(value):

	if value <= 0.5:
		var darkness = Color.from_hsv(selected_color, 1, value, 1)
		modulate = Color(darkness)
		selected_darkness = value

	if value > 0.5:
		var brightness = Color.from_hsv(selected_color, value, 1, 1)
		modulate = Color(brightness)
		selected_brightness = value

So a second Slider deals with the brightness and darkness of a selected color.
My example isn’t ideal of course, it would be perfect if the slider would start completely dark left-most with select_darkness 0 reaching 1 in the middle where selected_brightness starts at 0 until reaching 1 right-most.
That would offer the full graduation range from dark/black to bright/white.

pferft | 2023-03-01 23:02

Wow chamo you took my meager suggestion and went full supernova with it.
Good on you mate.

The hv was a bad habit of mine from shader languange. Happens when you code in multiple languages from time to time so apologies.

Wakatta | 2023-03-03 12:04

Apology accepted ; )
Meager? Obviously the ignition spark I just needed! I wish you a great weekend!

pferft | 2023-03-03 15:59