unity-game-engineshadercgshaderlab

color ramp shader (cg / shaderlab)


I have a shader function which functions like the "color ramp" node in Blender3D. It takes as input a float between zero and one and outputs a color that is a blend of any number of colors in a specified order:

blender3D color ramp
blender3D color ramp

Here is my code:

fixed4 ColorRamp(float factor){
            float positions[5] = {_Pos0, _Pos1, _Pos2, _Pos3, _Pos4}; 
            fixed4 colors[5] = {_Color0, _Color1, _Color2, _Color3, _Color4}; 

            fixed4 outColor = _Color0;

            for(int i = 0; i <4; i++){

                if(factor >= positions[i] && factor <positions[i+1]){
                    fixed localFactor = (factor - positions[i])/(positions[i+1] - positions[i]);
                    outColor =  lerp(colors[i], colors[i+1], localFactor);
                }else if (factor > positions [_NumColors-1]){
                    outColor = colors[_NumColors -1];
                }
            }
            return outColor;
        }

It works. But it sucks, for a few reasons:

  1. the number of colors in the ramp are hardcoded. Adding a list of them in the Unity editor would be far better.
  2. if/else statements. I understand that these are terrible for performance and are to be avoided.
  3. the array of colors is declared in the function, which means a new array has to be created for every fragment (I think).

My main question is the first one: How can I change the number of colors in the ramp without having to edit a hardcoded value?


Solution

  • Brice is right. I can tell you straight away - nobody ever uses gradients of this type for shaders, simply because it offers virtually no advantages over just using a 1x128px color ramp texture. Use a lookup texture like this:

    fixed4 col = tex2D(_MainTex, i.uv); // Sample the input texture
    half lum = dot(col.rgb, fixed3(0.3, 0.59, 0.11)); // Color to luminosity
    col = tex2D(_LookUpTex, float2(lum, 0)); // Get value from color ramp
    

    If you want to create a handy inspector for the user, just generate a lookup texture from the gradient instead and assign it to the shader through script at OnValidate(). It is trivial to generate one by just evaluating the gradient at x/127.0 for each x between 0 and 127. Unity has a special Gradient class which gives you a gradient editor in the inspector when exposed.