1
\$\begingroup\$

I am trying to write a shader that takes multiple colors and applies them to a B&W texture. Now, 3 colors works just fine, but i will need 6 in order for this to function. If somebody could please explain how adding more colors would work or refer me to some documentation that would be appreciated!

What i have so far is the following (tex = B&W texture, _Middle = 0.5):

fixed4 c = lerp(_ColorA, _ColorB, tex.y / _Middle) * step(tex.y, _Middle);
c += lerp(_ColorB, _ColorC, (tex.y - _Middle) / (1 - _Middle)) * step(_Middle, tex.y);

Source: http://answers.unity3d.com/questions/1108472/3-color-linear-gradient-shader.html

\$\endgroup\$
  • 1
    \$\begingroup\$ Would it be acceptable to use a texture for that instead? Upload a texture of size 6×1 with each pixel being one of your colours, and sample it with linear interpolation. \$\endgroup\$ – sam hocevar Sep 19 '16 at 17:43
  • \$\begingroup\$ Well, im lerping here. I did get it to work with a larger picture (2048x1) and sample it. But that doesnt allow control of the colors (which is essential). Anyway, from what i understand from your suggestion the calculations required to use those 6 pixels would be roughly the same as 6 ShaderLab colors correct? Or am i missing something here? \$\endgroup\$ – Dennis Sep 19 '16 at 17:57
  • \$\begingroup\$ "That doesn't allow control of the colours" - sure it does! You can modify the texture's colours at runtime using the Texture2D SetPixels method or a RenderTexture. As you increase the complexity of your gradient, the shader math for combining n colours becomes more complicated (though using an array of colours instead of individual colour variables will help) - especially if you need it to antialias correctly at small sizes/glancing angles - while using a texture gives you freedom to modify the texture any way you want, with all the blending handled by the texture sampling hardware. \$\endgroup\$ – DMGregory Sep 19 '16 at 19:07
  • \$\begingroup\$ Oh, now that sounds interesting. So if i understand you correctly, i use SetPixels on a RenderTexture via a C# script (so no CG) and interpolate the colors. Then its a matter of using that texture for the shader, and apply the gradient to the B&W texture i use on my object? Because at the moment im fooling around with if-statements in my shader. But that is maybe a bit to harsh on resources, and seems to create random pixel problems. \$\endgroup\$ – Dennis Sep 19 '16 at 19:17
  • \$\begingroup\$ Almost. I (or another user) can elaborate in an answer a little later, but to summarise: you'd use either Texture2D.SetPixels or a RenderTexture, not both, depending on how you want to apply the colours (CPU-side for occasional changes, or GPU-side for something you're doing frequently). Depending on your setup, you may be able to just write the key colours you want to individual texels, and let the texture sampling hardware interpolate for you. You'd still need to write a shader to do the texture indirection, but it scales well to many types of gradients, rather than using custom versions \$\endgroup\$ – DMGregory Sep 19 '16 at 19:53
1
\$\begingroup\$

The following code creates a 4 color gradient texture and applies it to the shader. The code needs to be attached to the object that has the shader on it.


private Texture2D _tex; //Texture that will go into the shader
private Renderer _rend; //Renderer of the object

private void Awake () {
    _rend = this.GetComponent<Renderer> ();

    //create new texture, width == amount of colors
    _tex = new Texture2D (4, 1);  

    //Set each pixel to specified color (StarGradient is function below)
    _tex.SetPixels32 (StarGradient (
        new Color32 (255, 186, 0, 1), 
        new Color32 (224, 100, 45, 1), 
        new Color32 (118, 73, 41, 1), 
        new Color32 (60, 73, 55, 1))
    );
    _tex.filterMode = FilterMode.Trilinear;
    _tex.wrapMode = TextureWrapMode.Clamp;
    _tex.Apply ();

    //Pass _tex to the material
    _rend.material.SetTexture ("_RampTex", _tex);
}

//Returns a Color32 array of specified colors
private Color32[] StarGradient(Color32 a, Color32 b, Color32 c, Color32 d) {
    Color32[] _colors = new Color32[4];
    _colors [0] = a;
    _colors [1] = b;
    _colors [2] = c;
    _colors [3] = d;
    return _colors;
}

\$\endgroup\$
1
\$\begingroup\$

if any one still need it.

 Shader "Custom/Gradient_4Color" {
     Properties {
         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
         _ColorTop ("Top Color", Color) = (1,1,1,1)
         _ColorMidTop ("MidTop Color", Color) = (1,1,1,1)
         _ColorMidBot ("MidBot Color", Color) = (1,1,1,1)
         _ColorBot ("Bot Color", Color) = (1,1,1,1)
         _MiddleBot ("MiddleBot", Range(0.001, 0.999)) = 0.33
          _MiddleTop ("MiddleTop", Range(0.001, 0.999)) = 0.66
     }

     SubShader {
         Tags {"Queue"="Background"  "IgnoreProjector"="True"}
         LOD 100

         ZWrite On

         Pass {
         CGPROGRAM
         #pragma vertex vert  
         #pragma fragment frag
         #include "UnityCG.cginc"

         fixed4 _ColorTop;
         fixed4 _ColorMidTop;
         fixed4 _ColorMidBot;
         fixed4 _ColorBot;

          float  _MiddleBot;
          float  _MiddleTop;

         struct v2f {
             float4 pos : SV_POSITION;
             float4 texcoord : TEXCOORD0;
         };

         v2f vert (appdata_full v) {
             v2f o;
             o.pos = UnityObjectToClipPos (v.vertex);
             o.texcoord = v.texcoord;
             return o;
         }

         fixed4 frag (v2f i) : COLOR {

             fixed4 c = lerp(_ColorBot, _ColorMidBot, i.texcoord.y / _MiddleBot) * step(i.texcoord.y, _MiddleBot);
             c += lerp(_ColorMidBot, _ColorMidTop, (i.texcoord.y - _MiddleBot) /(_MiddleTop - _MiddleBot) ) * step(_MiddleBot,i.texcoord.y) * step(i.texcoord.y,_MiddleTop);
             c += lerp(_ColorMidTop, _ColorTop, (i.texcoord.y - _MiddleTop) / (1 - _MiddleTop)) * step(_MiddleTop, i.texcoord.y);
             c.a = 1;

             return c;
         }
         ENDCG
         }
     }
 }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.