RGB Rainbow colours

Just starting out? Need help? Post your questions and find answers here.
User avatar
matalog
Enthusiast
Enthusiast
Posts: 305
Joined: Tue Sep 05, 2017 10:07 am

RGB Rainbow colours

Post by matalog »

I use this method of mixing colours to get decent gradients of most colours, but I noticed it's far from perfect cycling of all colours. There is very little red in the mix and no noticable yellow.

Any tips to get a better mix of all colours, or even a more balanced traditional set of rainbow colours?

Code: Select all

#width=1800
#height=900
OpenWindow(0,0,0,#width,#height,"Window")
CreateImage(0,#width,#height)
ImageGadget(0,0,0,#width,#height,ImageID(0))
StartDrawing(ImageOutput(0))
Global.i r,g,b
Box(0,0,#width,#height,#Black)
For x=0 To #width-1
    r=128+Round((128-0.5)*Sin((2*#PI)/#width*x+(2*#PI)/360*0),#PB_Round_Down)
    g=128+Round((128-0.5)*Sin((2*#PI)/#width*x+(2*#PI)/360*120),#PB_Round_Down)
    b=128+Round((128-0.5)*Sin((2*#PI)/#width*x+(2*#PI)/360*240),#PB_Round_Down)
Line(x,0,1,#height-700,RGB(r,g,b))
Circle(x,500-r,10,#Red)
Circle(x,500-g,10,#Green)
Circle(x,500-b,10,#Blue)
Next
StopDrawing()
SetGadgetState(0,ImageID(0))
Repeat
Repeat
                                       
    Event = WindowEvent()
    Select Event 
      Case #PB_Event_Gadget
        If EventGadget() = 0
          End
        EndIf
      Case #PB_Event_CloseWindow
        End 
    EndSelect
  Until Event = 0
  Until Event = #PB_Event_CloseWindow
  
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: RGB Rainbow colours

Post by STARGÅTE »

You can try to use HSV(Hue, Saturation, Value):

Code: Select all

Procedure.l HSV(Hue.f, Saturation.f, Value.f)
	Protected H.i = Int(Hue/60)
	Protected f.f = (Hue/60-H)
	Protected S.f = Saturation/100
	If S > 1.0 : S = 1.0 : ElseIf S < 0.0 : S = 0.0 : EndIf
	Protected V.f = Value * 2.55
	If V > 255 : V = 255 : ElseIf V < 0 : V = 0 : EndIf
	Protected p.i = V * (1-S)
	Protected q.i = V * (1-S*f)
	Protected t.i = V * (1-S*(1-f))
	Select H
		Case 1 : ProcedureReturn RGB(q,V,p)
		Case 2 : ProcedureReturn RGB(p,V,t)
		Case 3 : ProcedureReturn RGB(p,q,V)  
		Case 4 : ProcedureReturn RGB(t,p,V)
		Case 5 : ProcedureReturn RGB(V,p,q)  
		Default : ProcedureReturn RGB(V,t,p)
	EndSelect
EndProcedure

Code: Select all

#width=1800
#height=900
OpenWindow(0,0,0,#width,#height,"Window")
CreateImage(0,#width,#height)
ImageGadget(0,0,0,#width,#height,ImageID(0))
StartDrawing(ImageOutput(0))
Global.i r,g,b
Box(0,0,#width,#height,#Black)
For x=0 To #width-1
    r=Red(HSV(360*x/#width, 100, 255))
    g=Green(HSV(360*x/#width, 100, 255))
    b=Blue(HSV(360*x/#width, 100, 255))
Line(x,0,1,#height-700,RGB(r,g,b))
Circle(x,500-r,10,#Red)
Circle(x,500-g,10,#Green)
Circle(x,500-b,10,#Blue)
Next
StopDrawing()
SetGadgetState(0,ImageID(0))
Repeat
Repeat
                                       
    Event = WindowEvent()
    Select Event 
      Case #PB_Event_Gadget
        If EventGadget() = 0
          End
        EndIf
      Case #PB_Event_CloseWindow
        End 
    EndSelect
  Until Event = 0
  Until Event = #PB_Event_CloseWindow
However, if you really want the "rainbow colors", in the sense of wavelength and color, this topic becomes more complicated:
https://en.wikipedia.org/wiki/Color_model
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
matalog
Enthusiast
Enthusiast
Posts: 305
Joined: Tue Sep 05, 2017 10:07 am

Re: RGB Rainbow colours

Post by matalog »

That is definitely a lot more balanced, thanks for sharing it. The gradients don't seem so smooth around the peaks at Yellow, Cyan and Magenta though.
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: RGB Rainbow colours

Post by STARGÅTE »

Try:

Code: Select all

Procedure.l HSV(Hue.f, Saturation.f, Value.f)
	Protected H.i = Int(Hue/60)
	Protected f.f = 1-Pow(Cos((Hue/60-H)*#PI/2), 2)
	Protected S.f = Saturation/100
	If S > 1.0 : S = 1.0 : ElseIf S < 0.0 : S = 0.0 : EndIf
	Protected V.f = Value * 2.55
	If V > 255 : V = 255 : ElseIf V < 0 : V = 0 : EndIf
	Protected p.i = V * (1-S)
	Protected q.i = V * (1-S*f)
	Protected t.i = V * (1-S*(1-f))
	Select H
		Case 1 : ProcedureReturn RGB(q,V,p)
		Case 2 : ProcedureReturn RGB(p,V,t)
		Case 3 : ProcedureReturn RGB(p,q,V)  
		Case 4 : ProcedureReturn RGB(t,p,V)
		Case 5 : ProcedureReturn RGB(V,p,q)  
		Default : ProcedureReturn RGB(V,t,p)
	EndSelect
EndProcedure
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
matalog
Enthusiast
Enthusiast
Posts: 305
Joined: Tue Sep 05, 2017 10:07 am

Re: RGB Rainbow colours

Post by matalog »

Yeah, that's great, much better. For me, the range of colours is perfect, it is just a tiny bit not smooth enough in the very centre of the 3 colours I mentioned.

I probably started this, but if we anyone is leaving this open for a long time, then change line 44 to

Code: Select all

Event = WaitWindowEvent()
instead of

Code: Select all

    Event = WindowEvent()
AZJIO
Addict
Addict
Posts: 2226
Joined: Sun May 14, 2017 1:48 am

Re: RGB Rainbow colours

Post by AZJIO »

Code: Select all

Global Dim arr_rgb(2)
Global Dim arr_hsb(2)

Procedure hsb_to_rgb()
	Protected sector
	Protected.f ff, pp, qq, tt
	Protected.f Dim af_rgb(2) ; создаём массивы в которых числа будут в диапазоне 0-1
	Protected.f Dim af_hsb(2)
	; Protected Dim arr_rgb(2)

	af_hsb(2) = arr_hsb(2) / 100

	If arr_hsb(1) = 0 ; если серый, то одно значение всем
		arr_rgb(0) = Round(af_hsb(2) * 255, #PB_Round_Nearest)
		arr_rgb(1) = arr_rgb(0)
		arr_rgb(2) = arr_rgb(0)
		; ProcedureReturn arr_rgb
	EndIf

	While arr_hsb(0) >= 360 ; если тон задан большим запредельным числом, то
		arr_hsb(0) - 360
	Wend

	af_hsb(1) = arr_hsb(1) / 100
	af_hsb(0) = arr_hsb(0) / 60
	; sector = Int(arr_hsb(0))
	sector = Round(af_hsb(0), #PB_Round_Down)

	ff = af_hsb(0) - sector
	pp = af_hsb(2) * (1 - af_hsb(1))
	qq = af_hsb(2) * (1 - af_hsb(1) * ff)
	tt = af_hsb(2) * (1 - af_hsb(1) * (1 - ff))

	Select sector
		Case 0
			af_rgb(0) = af_hsb(2)
			af_rgb(1) = tt
			af_rgb(2) = pp
		Case 1
			af_rgb(0) = qq
			af_rgb(1) = af_hsb(2)
			af_rgb(2) = pp
		Case 2
			af_rgb(0) = pp
			af_rgb(1) = af_hsb(2)
			af_rgb(2) = tt
		Case 3
			af_rgb(0) = pp
			af_rgb(1) = qq
			af_rgb(2) = af_hsb(2)
		Case 4
			af_rgb(0) = tt
			af_rgb(1) = pp
			af_rgb(2) = af_hsb(2)
		Default
			af_rgb(0) = af_hsb(2)
			af_rgb(1) = pp
			af_rgb(2) = qq
	EndSelect

	; RGB
	arr_rgb(0) = Round(af_rgb(0) * 255, #PB_Round_Nearest)
	arr_rgb(1) = Round(af_rgb(1) * 255, #PB_Round_Nearest)
	arr_rgb(2) = Round(af_rgb(2) * 255, #PB_Round_Nearest)

	; BGR
	; arr_rgb(2)=Round(af_rgb(0)*255, #PB_Round_Nearest)
	; arr_rgb(1)=Round(af_rgb(1)*255, #PB_Round_Nearest)
	; arr_rgb(0)=Round(af_rgb(2)*255, #PB_Round_Nearest)

	; ProcedureReturn arr_rgb
EndProcedure

#width = 1275
#height = 900
OpenWindow(0, 0, 0, #width, #height, "Window")
CreateImage(0, #width, #height)
ImageGadget(0, 0, 0, #width, #height, ImageID(0))
StartDrawing(ImageOutput(0))
Global.i r, g, b, z

arr_hsb(1) = 100
arr_hsb(2) = 100
Box(0, 0, #width, #height, #Black)
For x = 0 To #width - 1
; 	arr_hsb(0) = 360 * x / #width
	arr_hsb(0) = 360 * x / #width + 100
	
	; 	smoothing (delete if not needed)
; 	darkening bright areas
	z = arr_hsb(0) % 60
	If z > 30
		z = Abs(z - 60)
	EndIf
; 	arr_hsb(2) = 70 + z
	arr_hsb(2) = 85 + z/2
	; 	arr_hsb(2) = 90 + z/3
	
; 	Lightening dark parts
	z = (arr_hsb(0) + 0) % 60
	If z > 30
		z = Abs(z - 60)
	EndIf
	arr_hsb(1) = 70 + z
; 	Debug arr_hsb(1)
; 	the end of smoothing
	
	hsb_to_rgb()
; 	Line(x, 0, 1, #height - 700, RGB(arr_rgb(0), arr_rgb(1), arr_rgb(2)))
	Line(#width - x, 0, 1, #height - 700, RGB(arr_rgb(0), arr_rgb(1), arr_rgb(2)))
	Circle(x * 3.5, Sin(Radian(x) + Radian(180)) * 120 + 500, 10, #Red)
	Circle(x * 3.5, Sin(Radian(x) + Radian(300)) * 120 + 500, 10, #Green)
	Circle(x * 3.5, Sin(Radian(x) + Radian(60)) * 120 + 500, 10, #Blue)
Next
StopDrawing()
SetGadgetState(0, ImageID(0))
Repeat
	Repeat

		Event = WindowEvent()
		Select Event
			Case #PB_Event_Gadget
				If EventGadget() = 0
					End
				EndIf
			Case #PB_Event_CloseWindow
				End
		EndSelect
	Until Event = 0
Until Event = #PB_Event_CloseWindow
Olli
Addict
Addict
Posts: 1266
Joined: Wed May 27, 2020 12:26 pm

Re: RGB Rainbow colours

Post by Olli »

Let's imagine,
x is the red color;
y is the green color, and
z is the blue color.

What you would need is a cube cut in two parts. The triangle drawn by this cut, goes through the three sides : red, green and blue.
Post Reply