Search Unity

low poly uv lerping

Discussion in 'Shaders' started by chantey, Feb 9, 2018.

  1. chantey

    chantey

    Joined:
    Mar 5, 2017
    Posts:
    49
    Maybe theres a simple answer but this one has me stumped.
    I'm creating a mesh in c# with a 'pizza' shape i.e. first vertex is in center and the rest are evenly spaced around it at some radius.
    The 'U' value is set to 0 in the center and 1 in all of the edge vertices.
    I have a simple unlit shader which will lerp between two colors based on the u value.

    So I'm looking for a smooth lerp but it seems that along the edges of the triangles this value remains 0.
    Note that with a many sided polygon this effect is hardly noticeable.


    The shader im using:
    Code (CSharp):
    1. Shader "Custom/UShader"
    2. {
    3.     Properties
    4.     {
    5. _ColorU0 ("Color U-0", Color) = (1,1,1,1)
    6. _ColorU1 ("Color U-1", Color) = (0,0,0,1)
    7.     }
    8.     SubShader
    9.     {
    10.         Pass
    11.         {
    12.             CGPROGRAM
    13.             #pragma vertex vert
    14.             #pragma fragment frag
    15.             #include "UnityCG.cginc"
    16.  
    17.             struct appdata
    18.             {
    19.                 float4 vertex : POSITION;
    20.                 float2 uv : TEXCOORD0;
    21.             };
    22.  
    23.             struct v2f
    24.             {
    25.                 float2 uv : TEXCOORD0;
    26.                 float4 vertex : SV_POSITION;
    27.             };
    28.            
    29.             v2f vert (appdata v)
    30.             {
    31.                 v2f o;
    32.                 o.vertex = UnityObjectToClipPos(v.vertex);
    33.                 o.uv = v.uv;
    34.                 return o;
    35.             }
    36.            
    37.             fixed4 _ColorU0;
    38.             fixed4 _ColorU1;
    39.  
    40.             fixed4 frag (v2f i) : SV_Target
    41.             {
    42.                 fixed4 colU = lerp(_ColorU0,_ColorU1,i.uv.x);
    43.                 return colU;
    44.             }
    45.             ENDCG
    46.         }
    47.     }
    48. }
    49.  
     

    Attached Files:

  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Nope, this is just an optical illusion. The resulting image is correct, but the human brain is really good at noticing patterns, and in this case it's seeing two linear gradients with different directions and making the edge appear more prominent.

    You could reduce the effect of this by modifying the curve of the i.uv.x by how close it is to a corner, probably using i.uv.y. Alternate the uv.y between 0.0 and 1.0 and then do abs(i.uv.y * 2.0 - 1.0). Then do some kind of pow on the i.uv.x, and potentially the resulting i.uv.y. How much is going to be different for ever corner.

    fixed4 col = lerp(_Color0, _Color1, pow(i.uv.x, lerp(1.0, 0.75, abs(i.uv.y * 2.0 - 1.0)));
     
  3. chantey

    chantey

    Joined:
    Mar 5, 2017
    Posts:
    49
    right thats interesting, ill give it a go.
     
  4. chantey

    chantey

    Joined:
    Mar 5, 2017
    Posts:
    49
    So I spent a bit last night playing with exponentials and couldnt really get my head around it.

    Then dead set i woke up at 5am with a new idea, just use vertex positions and pythagoras theorem
    The image is of a polygon with a radius of 1

    Screen Shot 2018-02-12 at 6.13.40 am.png

    Code (CSharp):
    1. Shader "Custom/RadialShader"
    2. {
    3.     Properties
    4.     {
    5.         _ColCenter ("Center Color", Color) = (0,0,0,1)
    6.         _ColEdge ("Edge Color", Color) = (1,1,1,1)
    7.  
    8.     }
    9.     SubShader
    10.     {
    11.  
    12.         Pass
    13.         {
    14.             CGPROGRAM
    15.             #pragma vertex vert
    16.             #pragma fragment frag
    17.            
    18.             #include "UnityCG.cginc"
    19.  
    20.             struct appdata
    21.             {
    22.                 float4 vertex : POSITION;
    23.                 float2 uv : TEXCOORD0;
    24.             };
    25.  
    26.             struct v2f
    27.             {
    28.                 float2 uv : TEXCOORD0;
    29.                 float4 objPos : TEXCOORD1;
    30.                 float4 vertex : SV_POSITION;
    31.             };
    32.  
    33.             v2f vert (appdata v)
    34.             {
    35.                 v2f o;
    36.                 o.vertex = UnityObjectToClipPos(v.vertex);
    37.                 o.objPos = v.vertex;
    38.                 o.uv = v.uv;
    39.                 return o;
    40.             }
    41.            
    42.             fixed4 _ColCenter;
    43.             fixed4 _ColEdge;
    44.  
    45.             fixed4 frag (v2f i) : SV_Target
    46.             {
    47.                 //c2 = a2 + b2      
    48.                 float a = i.objPos.x;
    49.                 float b = abs(i.objPos.y);
    50.                 float c = sqrt(pow(a,2)+pow(b,2));
    51.                 return lerp(_ColCenter,_ColEdge,c);
    52.             }
    53.             ENDCG
    54.         }
    55.     }
    56. }
    57.  
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Ah, if all you wanted was a perfect circular gradient regardless of the polygon shape, then yes, Pythagorean theorem works.

    The faster GPU-ized version of which would be.

    float c = sqrt(dot(i.objPos.xy, i.objPos.xy));

    You can also just use the built in length function to do the same thing.

    float c = length(i.objPos.xy);

    It's better to store the objPos.xy in UVs though, as batching will alter the mesh's vertex positions as seen by the shader.