3
$\begingroup$

I am creating a color saturation node group in blender as an exercise. This is the code I'm trying to implement:

RGBtoHSV= function(color) {
    var r,g,b,h,s,v;
    r= color[0];
    g= color[1];
    b= color[2];
    min = Math.min( r, g, b );
    max = Math.max( r, g, b );


    v = max;
    delta = max - min;
    if( max != 0 )
        s = delta / max;        // s
    else {
        // r = g = b = 0        // s = 0, v is undefined
        s = 0;
        h = -1;
        return [h, s, undefined];
    }
    if( r === max )
        h = ( g - b ) / delta;      // between yellow & magenta
    else if( g === max )
        h = 2 + ( b - r ) / delta;  // between cyan & yellow
    else
        h = 4 + ( r - g ) / delta;  // between magenta & cyan
    h *= 60;                // degrees
    if( h < 0 )
        h += 360;
    if ( isNaN(h) )
        h = 0;
    return [h,s,v];
};

This is the part that I am struggling to implement:

    if( r === max )
    h = ( g - b ) / delta;      // between yellow & magenta
else if( g === max )
    h = 2 + ( b - r ) / delta;  // between cyan & yellow
else
    h = 4 + ( r - g ) / delta;  // between magenta & cyan

I am trying to figure out how to chain math comparison nodes in the right way but I am just stuck.

Here is the node group so-far (Updated):

Nodes

At the very end is where I am stuck. I'm not sure how to set up a three-way if/else node structure.

If r === max, else if g === max, else catch-all.

Any help would be hugely, hugely, appreciated!

$\endgroup$

3 Answers 3

6
$\begingroup$

Rewrite the code as

h1 =     (g - b) / delta;  // between yellow & magenta
h2 = 2 + (b - r) / delta;  // between cyan & yellow
h3 = 4 + (r - g) / delta;  // between magenta & cyan

h  = (r==max) * h1
h += (1 - (r==max)) * (g==max) * h2
h += (1 - (r==max)) * (1 - (g==max)) * h3

where (X==Y) means 1 if X and Y are equal, 0 if they're different (ie. what the "Compare" operation on a Math node does).

This is just a bunch of arithmetic operations, so it's straightforward, albeit laborious, to translate into nodes.

edit

Here's how I did it with nodes. This does

tmp = (g==max) ? h2 : h3;
h   = (r==max) ? h1 : tmp;

The If Then Else node can be done with a lerp

$\endgroup$
1
  • $\begingroup$ I seriously appreciate the help. I can kind of see where you're going with this, but I don't understand how to implement the bottom half. Why are you doing += operations instead of comparisons? I realize it's pretty laborious, but is there any way you could possibly put together a sample of how you would go about it? Pretty please? :) $\endgroup$
    – fmotion1
    Commented Feb 19, 2021 at 22:35
3
$\begingroup$

I have an answer here where I use Compare nodes to create a switch with a default case.

enter image description here

At this point I have to point out that there is overlap at the minima and maxima of these nodes, and the winner is dictated by the order of the MixRGB nodes.

For example, a value of .2 activates the code path of both the first and second Compare nodes, but the yellow color would win out.

$\endgroup$
3
$\begingroup$

An If is just a lerp (linear interpolation) with boolean (1 or 0) inputs. That's the easy way to think of it.

And a lerp is, currently, most easily implemented with map range node:

enter image description here

I've labelled value nodes with "ELSE" and "IF" to make it clear which is which. So what I'm doing here is saying, If UV.x > 0.5 then 1.0 else 0.0.

So let's look at one arm of your actual code:

 if( r === max )
     h = ( g - b ) / delta;      // between yellow & magenta
 else if( g === max )
     h = 2 + ( b - r ) / delta;  // between cyan & yellow
 else
     h = 4 + ( r - g ) / delta;  // between magenta & cyan

Now, let's rewrite that a bit, because the order of operations isn't particularly clear from the way that code is written:

 if( r === max ) {
     h = ( g - b ) / delta;      // between yellow & magenta
 }     
 else {
      if( g === max ) {
          h = 2 + ( b - r ) / delta;  // between cyan & yellow
      }
      else {
           h = 4 + ( r - g ) / delta;  // between magenta & cyan
      }
  }

With the reordering, we can see that our else if is really a nested if statement. Let's implement it in nodes:

enter image description here

Using labelled value nodes for our inputs, and assuming that === means equality comparison (I'm not familiar with that usage.) And our output is of course h, which is the only thing that snippet assigns.

$\endgroup$
3
  • $\begingroup$ I'm going to have to study your implementation. The solution I came up with is a lot more complex. This looks much more graceful. I really, really appreciate your help! If you wouldn't mind taking a look at another question of mine: blender.stackexchange.com/questions/212430/… I would really like to see how you would approach that as well. $\endgroup$
    – fmotion1
    Commented Feb 20, 2021 at 0:05
  • $\begingroup$ @Jay I took a quick look. Think about it this way: IF i = 1 then r=v ELSE IF i = 2 r = q ELSE if i = 3.... Operating in parallel with IF i = 1 then g= t.... It's going to be a complete mess, that's just something you're going to have to accept when trying to implement branching logic in nodes. $\endgroup$
    – Nathan
    Commented Feb 20, 2021 at 0:08
  • $\begingroup$ Thanks much for looking. I'm still just stuck. I understand that it's just a branching if/else construct. But the part that gets me is assigning multiple different values to the RGB outputs depending on the value of I. $\endgroup$
    – fmotion1
    Commented Feb 20, 2021 at 0:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .