Search Unity

Help making shader with 3 colors

Discussion in 'Shaders' started by Lars-Kristian, Aug 29, 2014.

  1. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    Hi dear forum.

    I want to write a shader that apply colors depending on surface normals. I other words if I have a cube I can make the top blue, front red and side yellow if I want. I am no expert at this, but i started of with the shader for visualizing normal's. I tried to modify it but I am stuck now. I manage to make grayscale colors work but not actual colors.

    Can someone help me? or point me in the right direction?


    Code (CSharp):
    1. Shader "Custom/3ColorShader" {
    2. Properties {
    3.         _TopColor ("Top Color", Color) = (1.0,1.0,1.0,1.0)
    4.         _FrontColor ("Front Color", Color) = (0.8,0.8,0.8,1.0)
    5.         _SideColor ("Side Color", Color) = (0.6,0.6,0.6,1.0)
    6.     }
    7. SubShader {
    8.     Pass {
    9.         Fog { Mode Off }
    10.         CGPROGRAM
    11.        
    12.         float4 _TopColor;
    13.         float4 _FrontColor;
    14.         float4 _SideColor;
    15.  
    16.         #pragma vertex vert
    17.         #pragma fragment frag
    18.         #include "UnityCG.cginc"
    19.  
    20.         // vertex input: position, normal
    21.         struct appdata {
    22.             float4 vertex : POSITION;
    23.             float3 normal : NORMAL;
    24.         };
    25.  
    26.         struct v2f {
    27.             float4 pos : SV_POSITION;
    28.             fixed4 color : COLOR;
    29.         };
    30.        
    31.         v2f vert (appdata v) {
    32.             v2f o;
    33.             o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    34.             o.color = float4(0, 0, 0, 1);
    35.             o.color.rgb += dot(v.normal, float3(-1, 0, 0) * _SideColor);
    36.             o.color.rgb += dot(v.normal, float3(0, 1, 0) * _TopColor);
    37.             o.color.rgb += dot(v.normal, float3(0, 0, 1) * _FrontColor);
    38.             return o;
    39.         }
    40.        
    41.         fixed4 frag (v2f i) : COLOR0 { return i.color; }
    42.         ENDCG
    43.     }
    44. }
    45. }
     
  2. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    You're currently including the colors in the dot product, which isn't correct. Besides that you probably want to make sure the total amount of "coloring" equals 1.
    Code (csharp):
    1.  
    2. o.color = float4(0, 0, 0, 1);
    3. float4 blending = abs(dot(v.normal, float3(1, 0, 0))); // Or abs(v.normal.x)
    4. blending.y = abs(dot(v.normal, float3(0, 1, 0))); // Or abs(v.normal.y)
    5. blending.z = abs(dot(v.normal, float3(0, 0, 1))); //  Or abs(v.normal.z)
    6. blending.w += blending.y + blending.z;
    7. blending /= blending.w;
    8. o.color.rgb += blending.x * _SideColor;
    9. o.color.rgb += blending.y * _TopColor;
    10. o.color.rgb += blending.z * _FrontColor;
    11.  
     
  3. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    Thanks. That makes perfect sense.

    Can you help me understand these lines?
    Code (CSharp):
    1. blending.w += blending.y + blending.z;
    2. blending /= blending.w;
     
  4. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Yes, that's the normalizing part. The w component already contains the same value as the x component. I add the y and z components and then divide everything by the w component. After that, w should equal 1. The sum of the x, y and z components should also equal 1.
     
  5. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    Excellent, thanks. :)