Search code examples
hlsl

Gradient-generating shader with arbitrary color components


The task is: shader takes in a constant color, then generates pixel colors according to their positions by replacing two of four color components (RGBA) with texture coordinates. With hardcoded component set it will be like:

float4 inputColor : register(c0);

float4 main(float2 uv : TEXCOORD) : COLOR
{    
  float4 color = 0;

  color.a = inputColor.a;
  color.r = inputColor.r;
  color.g = uv.x;
  color.b = uv.y;

  return color;
}

Now I'd like to pass in a parameter(s) specifying which components should be replaced with uv.x and uv.y. Let's say inputColor has -1 and -2 in these components. Or there are uint xIndex and yIndex parameters specifying positions in vector4 to be replaced. HLSL does not allow "color[xIndex] = uv.x".

Currently I've done that in ugly way with a bunch of if-else. But I feel like there is some cross-product or matrix multiplication solution. Any ideas?


Solution

  • You could work with two additional vectors as channelmasks. It works like indexing, but with vector operators.

    float4 inputColor : register(c0);
    float4 uvx_mask : register(c1); //e.g. (0,0,1,0)
    float4 uvy_mask : register(c2); // e.g. (0,0,0,1)
    
    float4 main(float2 uv : TEXCOORD) : COLOR
    {    
      float4 color = 0;
    
      // replacing uvx channel with uv.x
      color = lerp(inputColor, uv.x * uvx_mask, uvx_mask); 
      // replacing uvy channel with uv.y
      color = lerp(color , uv.y * uvy_mask, uvy_mask);
    
      return color; //in this example (inputColor.r, inputColor.g, uv.x, uv.y)
    }
    

    If you need even the last bit of performance you could work alternative with the preprocessor (#define, #ifdef) to build the right code on demand.