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

Time:11-10

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.

CodePudding user response:

You could use a Shader Graph 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 );

CodePudding user response:

If i understand well what you want is not the max value, intead you want to know what texture is actually the one with max value, so i came with this...

A thing about divisions is that if both numbers are the same it always equals to one. And that also means that if the dividend is smaller than the divisor it will always return <1 and if the divisor is the smaller one it will return >1. Keep in mind 0 on the divisor.

With that I think you can get rid of the max() and use just 4 divisions and 4 floors possibly some control of 0 and ∞ cases.

  • Related