One way to do this is to use a fixed number of linear gradient stops. For example, you could have two float4
values which define the position and value for four individual stops:
cbuffer CB0
{
float4 sp; // stop positions
float4 sv; // stop values
}
float4 main(float2 coord : COORD) : SV_TARGET
{
float x = coord.x;
float v = 0;
if(x < sp.x) v = sv.x;
else if(x < sp.y) v = lerp(sv.x, sv.y, (x - sp.x) / (sp.y - sp.x));
else if(x < sp.z) v = lerp(sv.y, sv.z, (x - sp.y) / (sp.z - sp.y));
else if(x < sp.w) v = lerp(sv.z, sv.w, (x - sp.z) / (sp.w - sp.z));
else v = sv.w;
return float4(v,v,v,1);
}
Example remappings are below, using increasing values greater than 1 for unused stops to avoid division by zero in the shader. This won't affect the result, as the lerp
will snap to the lower value anyway.
Remap1: sp = {0,0.45,0.55,1}; sv = {0,0,1,1};
Remap2: sp = {0,0.1,1,2}; sv = {0,1,1,1};
Remap3: sp = {0,0.9,1,2}; sv = {0,0,1,1};
Remap4: sp = {0,1,2,3}; sv = {0,0.5,1,1};
Of course you could use a different number of stops if you need them depending on the complexity of your gradient.