algorithmunity-game-enginemathshadershader-graph

Set biggest channel of a pixel to 1 and all the other channels to 0


Suppose I have a texture, what I want to do is for each pixel, return only the biggest channel as 1 and the rest as 0.

For instance:

      |         INPUT           |      OUTPUT
------|-------------------------|-----------------
RGBA  |  (0.5, 0.3, 0.4, 0.3)   |   (1, 0, 0, 0)
RGBA  |  ( 0 , 0.8, 0.9,  1 )   |   (0, 0, 0, 1)

I'm using shader graph and I'm searching for an optimal approach to avoid using a lot of nodes.

My thought was taking the maximum m of all channels, then let each channel ci = (ci >= m), so the channel greater equal to m would be 1 and the rest would be 0, but I'm guessing there might be a better/more performant way.

PS: If there are 2 or more channels with the same value, the correctness doesn't matter, is a problem of the texture. It's possible to suppose there will always be a channel with biggest value.


Solution

  • One possible option would be to add a small custom function node.

    enter image description here

    float check = -1;
    if ( inputColour.x > check )
    {
      check = inputColour.x;
      outputColour = float4(1,0,0,0);
    }
    if ( inputColour.y > check )
    {
      check = inputColour.y;
      outputColour = float4(0,1,0,0);
    }
    if ( inputColour.z > check )
    {
      check = inputColour.z;
      outputColour = float4(0,0,1,0);
    }
    if ( inputColour.w > check )
    {
      outputColour = float4(0,0,0,1);
    }
    

    When the colour is closer to "red", the node produces:enter image description here

    But as the closer gets closer to "blue", the node produces:

    enter image description here


    EDIT

    Added in recognition of a better answer. As per @Daniel's comment, this code will produce the same results, but with NO if statements. AND it's easier to read! Win-win.

    float m = inputColour.x;
    m = max(m, inputColour.y);
    m = max(m, inputColour.z);
    m = max(m, inputColour.w);
    
    outputColour = float4 ( inputColour.x = inputColour.x >= m,
    inputColour.x = inputColour.y >= m,
    inputColour.x = inputColour.z >= m,
    inputColour.x = inputColour.w >= m );