Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to mix multiple colors in different proportions, not just 2 colors #6

Open
rider85 opened this issue Jun 29, 2023 · 5 comments

Comments

@rider85
Copy link

rider85 commented Jun 29, 2023

it would be awesome if I could play around with mixing multiple (2+) colors.
In fact I will try to implement it in the active project as soon as several colors are available.

Here are a few examples of implementation:

  1. Chroma-js: https://gka.github.io/chroma.js/#chroma-average
  2. Mixbox:
//   MULTI-COLOR MIXING
//
//      var z1 = mixbox.rgbToLatent(rgb1);
//      var z2 = mixbox.rgbToLatent(rgb2);
//      var z3 = mixbox.rgbToLatent(rgb3);
//
//      var zMix = new Array(mixbox.LATENT_SIZE);
//
//      for (var i = 0; i < zMix.length; i++) { // mix:
//          zMix[i] = (0.3*z1[i] +       // 30% of rgb1
//                     0.6*z2[i] +       // 60% of rgb2
//                     0.1*z3[i]);       // 10% of rgb3
//      }
//
//      var rgbMix = mixbox.latentToRgb(zMix);
@rvanwijnen
Copy link
Owner

When I find the time I will look in to this

@seguso
Copy link

seguso commented Feb 21, 2024

Hi, there, I have the same need: I need to translate this kind of thing:

mixbox_latent finalLat = 0.2 * latUp + 0.3 * latDown + 0.4 * latLeft + 0.1 * latRight;

The context would be

		vec3 up = ...
		vec3 down = ...
		vec3 left = ...
		vec3 right =...
		
		mixbox_latent latUp = mixbox_rgb_toLatent(up);
		mixbox_latent latDown = mixbox_rgb_toLatent(down);
		mixbox_latent latLeft = mixbox_rgb_toLatent(left);
		mixbox_latent latRight  = mixbox_rgb_toLatent(right);
		
                    mixbox_latent finalLat =  0.2  * latUp + 0.3  * latDown + 0.4  * latLeft + 0.1  * latRight;

                    vec3 colBg = mixbox_latent_to_rgb(finalLat);

Thanks!

@rvanwijnen
Copy link
Owner

It’s coming, I have this in my dev version.
No ETA though as I’m working on some other features before 3.0 will be released.

@eugene-khyst
Copy link

eugene-khyst commented Nov 9, 2024

Hi @rvanwijnen,

Thanks for this great library. It really helps to understand how to implement the Kubelka-Munk theory.

I'm trying to adapt the existing code to support mixing more than 2 colors.
The most complicated part is to adapt linear_to_concentration function to support more that two values.

function linear_to_concentration(l1, l2, t) {
    let t1 = l1 * (1 - t) ** 2;
    let t2 = l2 * t ** 2;

    return t2 / (t1 + t2);
  }

In the comment to #10 and comment to #13 you wrote:

Concerning the concentration function (you are referring to this function right?): the reason it's not linearly interpolating is because the luminance is needed for determining the correct concentrations, this ensures the color is perceptually evenly distributed between 0 and 1 where 0 is the first color and 1 is the second color.
This concentration function has been the hardest to figure out and took me a lot of time (although probably not unique I haven't seen this used anywhere else).

The Y value is not the Y tristimulus value but the CIE-XYZ Y value which is the luminance value.
The luminance is used for an even mix distribution between 0 (color 1) and 1 (color 2).
The concentration function creates a curve based on this luminance, you can't use a linear function.
This is the most important function in spectral.js and can't be omitted.

How did you come up with this solution?
$t^\prime=\frac{l_{2}t^{2}}{l_{1}\left(1-t\right)^{2}+l_{2}t^{2}}$

Maybe you can share some references?

The following function graph shows the difference between linear (y=x) and linear_to_concentration interpolation.

2 color interpolation function graph

2 color interpolation function graph

@eugene-khyst
Copy link

eugene-khyst commented Nov 9, 2024

It looks like the most practical way to mix 3 or more colors is iteratively. Each next color have to be mixed with the mixture of previous two colors.

Mix first two colors, then mix the resulting mixture with the third color, then mix the resulting mixture with the fourth color and so on.

Mix 3 colors in 1:1:1 ratio:

const colorMix12 = mix(color1, color2, 1/(1+1))
const finalMix = mix(colorMix12, color3, 1/(1+1+1))

This approach can be extended on any number of colors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants