Search Unity

Customize Multiple Colors On Material

Discussion in 'Shaders' started by Fariel, Dec 30, 2015.

  1. Fariel

    Fariel

    Joined:
    Feb 9, 2013
    Posts:
    29
    How would I go about customizing multiple colors on a material? The best example I can think of is something akin to Halo's customization options -- You can set a primary color and a secondary color. Are those separate models, separate textures? I'm honestly not sure at all how that works.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    This is a somewhat complicated topic, though the solutions aren't actually that complicated in of themselves. One way to do this is to use multiple materials on a model and change a tint color on each material. From a content creation side this is a single model, but internally each material becomes it's own model that gets rendered separately. You can also do it by having lots of different textures with all possible combinations but this is needlessly wasteful.

    The easiest way to do it, and how most games handle it, is by using a mask texture where two color channels of a texture are used as masks to modify the underlying texture color, usually with a simple multiply.
     
    Fariel likes this.
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    _TintColorA ("Tint Color A", Color) = (1, 1, 1, 1)
    _TintColorB ("Tint Color B", Color) = (1, 1, 1, 1)
    _TintMask ("Tint Mask", 2D) = "black"

    ...

    fixed4 albedo = tex2D(_MainTex, i.uv);
    fixed4 mask = tex2D(_TintMask, i.uv);
    fixed maskA = mask.r; // red channel is the first mask
    fixed maskB = mask.g; // green channel is the second mask
    fixed3 tint = fixed3(1.0, 1.0, 1.0);
    tint = lerp(tint, _TintColorB, maskB);
    tint = lerp(tint, _TintColorA, maskA);
    albedo.rgb *= tint;
     
    nxrighthere and Fariel like this.
  4. Fariel

    Fariel

    Joined:
    Feb 9, 2013
    Posts:
    29
    After a while of playing around with it, I managed to figure it out with your help. Writing shaders always feels like the highest level of sorcery. I can't guarantee that this is any kind of well-written code, but here is the full shader based on what bgolus suggested for anyone who stumbles upon this:
    Code (Shader):
    1. Shader "Custom/DualColorMask" {
    2.     Properties {
    3.         //_Color ("Color", Color) = (1,1,1,1)
    4.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    5.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    6.         _Metallic ("Metallic", Range(0,1)) = 0.0
    7.         _TintColorA("Tint Color A", Color) = (1, 1, 1, 1)
    8.         _TintColorB("Tint Color B", Color) = (1, 1, 1, 1)
    9.         _TintMask("Tint Mask", 2D) = "black"
    10.     }
    11.     SubShader {
    12.         Tags { "RenderType"="Opaque" }
    13.         LOD 200
    14.      
    15.         CGPROGRAM
    16.         // Physically based Standard lighting model, and enable shadows on all light types
    17.         #pragma surface surf Standard fullforwardshadows
    18.  
    19.         // Use shader model 3.0 target, to get nicer looking lighting
    20.         #pragma target 3.0
    21.  
    22.         sampler2D _MainTex;
    23.         sampler2D _TintMask;
    24.  
    25.         struct Input {
    26.             float2 uv_MainTex;
    27.             float2 uv_TintMask;
    28.         };
    29.  
    30.         half _Glossiness;
    31.         half _Metallic;
    32.         fixed4 _Color;
    33.         fixed4 _TintColorA;
    34.         fixed4 _TintColorB;
    35.  
    36.         void surf (Input IN, inout SurfaceOutputStandard o) {
    37.             // Albedo comes from a texture tinted by color
    38.             //fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    39.  
    40.             fixed4 albedo = tex2D(_MainTex, IN.uv_MainTex);
    41.             fixed4 mask = tex2D(_TintMask, IN.uv_TintMask);
    42.             fixed maskA = mask.r; // red channel is the first mask
    43.             fixed maskB = mask.g; // green channel is the second mask
    44.             fixed3 tint = fixed3(1.0, 1.0, 1.0);
    45.             tint = lerp(tint, _TintColorB, maskB);
    46.             tint = lerp(tint, _TintColorA, maskA);
    47.             albedo.rgb *= tint;
    48.  
    49.  
    50.             o.Albedo = albedo.rgb;
    51.             // Metallic and smoothness come from slider variables
    52.             o.Metallic = _Metallic;
    53.             o.Smoothness = _Glossiness;
    54.             o.Alpha = albedo.a;
    55.         }
    56.         ENDCG
    57.     }
    58.     FallBack "Diffuse"
    59. }
    60.  
    This works similar to a regular material. You apply your texture, but you also have a "tint mask" image to apply as well. To make a tint mask, you start with a black image (the tint mask ignores black). Your first color on the tint mask will be red, and your second color will be green. Drop the mask in to the material and change the colors -- everything green and red will be changed according to what color you set.
     
    nxrighthere likes this.