Color blending code

Ah ha, a missing piece

e class="onebox allowlistedgeneric" data-onebox-src="https://blog.daveeddy.com/2014/07/01/red-yellow-and-blue/">
blog.daveeddy.com

The above links to JS code that implements RYB
(Red Yellow Blue) to RGB (and vice versa).

Implemented as RYB Color Wheel

RYB is what people expect (I mix red and yellow paint and get orange, yellow and blue to get green, red and blue to get purple…)

Time to write some more library code. Imagine a display that has dripping R Y B dots that mix to form colors.

Yes yes, these are RGB lights, they don’t work that way … But we can dream in paint. (Ref. What Dreams May Come)

Updated
I ended up optimizing/reducing the code (got rid of the matrix array), but the cubic interpolating (“biased (non-linear) interpolation”) is a killer. In the example below, it’s 17fps vs 87fps, all due to the math.
Granted, I am also converting 0..1 (angle, and to a limited extent, brightness) into 3 0..1 values (for R Y B). Warning - I heavily optimized, reducing places where I could see results would be zeros to actual zeros, rather than do the math.

Updated - see v2 on RYB colors act like paint

Obsolete code - see v2 - RYB color wheel compared to RGB/HSV on the PB
export var wheeltype, brightness

export function sliderWheelType(v){
  wheeltype = floor(v+.5)
}

export function sliderBrightness(v){
  brightness = v
}

export function beforeRender(delta) {
 t1 = time(.15)
 resetTransform()
 translate(-.5, -.5)
 rotate(t1 * PI2)
}

export function render2D(index,x,y) {
  a = mod(atan2(y,x)/PI2,1)
  if (wheeltype == 0) {
    rybwheel(a)
  } else {
    hsvwheel(a)
  }
}

function hsvwheel(a) {
    hsv(a, 1, brightness)
}

function rybwheel(a){
  v = clamp(brightness,.5,1)
  i = floor(a * 6)
  f = a * 6 - i
  q = v * (1 - f)
  t = v * f

  if (i == 0) {
    r_ = v; g_ = t; b_ = 0
  } else if (i == 1) {
    r_ = q; g_ = v; b_ = 0
  } else if (i == 2) {
    r_ = 0; g_ = v; b_ = t
  } else if (i == 3) {
    r_ = 0; g_ = q; b_ = v
  } else if (i == 4) {
    r_ = t; g_ = 0; b_ = v
  } else if (i == 5) {
    r_ = v; g_ = 0; b_ = q
  }
  
  ryb(r_,g_,b_)
}

function cubicInt(t, A, B){
  return A + (t * t * (3 - 2 * t)) * (B - A);
}

function getR(iR, iY, iB) {  // red
  x0 = cubicInt(iB, 1, .163);
  x1 = cubicInt(iB, 1, 0);
  x2 = cubicInt(iB, 1, .5);
  x3 = cubicInt(iB, 1, .2);
  y0 = cubicInt(iY, x0, x1);
  y1 = cubicInt(iY, x2, x3);
  return cubicInt(iR, y0, y1);
}

function getG(iR, iY, iB) {  // green
  x0 = cubicInt(iB, 1, .373);
  x1 = cubicInt(iB, 1, .66);
  x3 = cubicInt(iB, .5, .094);
  y0 = cubicInt(iY, x0, x1);
  y1 = cubicInt(iY, 0, x3);
  return cubicInt(iR, y0, y1);
}

function getB(iR, iY, iB) {  // blue
  x0 = cubicInt(iB, 1, .6);
  x1 = cubicInt(iB, 0, .2);
  x2 = cubicInt(iB, 0, .5);
  y0 = cubicInt(iY, x0, x1);
  y1 = cubicInt(iY, x2, 0);
  return cubicInt(iR, y0, y1);
}

function ryb(R,Y,B) {
      rgb(getR(R, Y, B), getG(R, Y, B), getB(R, Y, B))
}

One more update:

Note to myself:

YUV is also interesting:

The Y′UV model defines a color space in terms of one luma component (Y′) and two chrominance components, called U (blue projection) and V (red projection) respectively.

Which means the color space is 2D, unlike HSV (hue is 1D, though pieces of the color change are in the SV), and RGB/RYB (3D).
Seems like worth playing with, as another interesting way to represent color, for neat patterns.

Also, just realized this thread didn’t link to
this blending thread with code

Ooh and one more color space: HSI
Good description and algo for conversion

A few more bits to save:

Code for RGBW conversion

More on HSI