Search Unity

Flat shading quads

Discussion in 'Shaders' started by Wordsonplay, Dec 20, 2013.

  1. Wordsonplay

    Wordsonplay

    Joined:
    Apr 29, 2013
    Posts:
    21
    I'm trying to draw a voronoi diagram using a shader. I do this by creating a collection of quads, each centred at a point in the diagram. The shader below uses the the depth buffer to turn each quad into a cone, which creates the voronoi effect.

    That much works but what I want to do next is to colour each voronoi cell by sampling the colour of a texture at that point in space. I tried doing this by setting gl_FrontColor in the vertex shader but the gl_Color variable in the fragment shader is interpolated between the four vertices of the quad which is not what I want. I want the whole cell to be flat shaded based on the colour of the centre point.

    Ideally, I'd be using a point sprite for this but I understand they aren't working correctly in current versions of Unity (or has this been fixed?)

    Any suggestions how to solve this problem?

    Code (csharp):
    1.  
    2. Shader "Custom/Voronoi" {
    3.     Properties {
    4.          _MainTex ("RGBA Texture Image", 2D) = "white" {}
    5.     }
    6.     SubShader {
    7.         Pass {
    8.             Cull Off
    9.             GLSLPROGRAM
    10.            
    11.             uniform sampler2D _MainTex;    
    12.  
    13.             #ifdef VERTEX
    14.             void main() {
    15.                 gl_TexCoord[0] = gl_MultiTexCoord0;
    16.                 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    17.                
    18.                 // sample the texture at the vertex location
    19.                 gl_FrontColor = texture2D(_MainTex, gl_Vertex.xy);
    20.             }
    21.  
    22.             #endif
    23.  
    24.  
    25.             #ifdef FRAGMENT
    26.  
    27.             void main() {
    28.                 // find the distance to the middle of the quad
    29.                 vec2 v = 2. * gl_TexCoord[0].xy - 1.;  
    30.                 float dist = length(v);
    31.                
    32.                 // make the quad circular by discarding
    33.                 // fragments more that 1 away from the centre
    34.                 if (dist > 1.) {
    35.                     discard;
    36.                 }
    37.  
    38.                 // make a cone by setting the depth equal to the distance
    39.                 gl_FragDepth = dist;
    40.                
    41.                 // set the colour -- this doesn't work how I want
    42.                 gl_FragColor = gl_Color;
    43.                
    44.             }
    45.            
    46.             #endif
    47.  
    48.             ENDGLSL
    49.         }
    50.     }
    51. }
    52.  
     
  2. Wordsonplay

    Wordsonplay

    Joined:
    Apr 29, 2013
    Posts:
    21
    Here is an example of the kind of output I am trying to achieve.
    $example.png
     
  3. Wordsonplay

    Wordsonplay

    Joined:
    Apr 29, 2013
    Posts:
    21
    My hacky solution: set the normals of the quad to point towards the centre point. Then do
    Code (csharp):
    1.  
    2.             #ifdef VERTEX
    3.             void main() {
    4.                 gl_TexCoord[0] = gl_MultiTexCoord0;
    5.                 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    6.                
    7.                 // sample the texture at the centre of the quad
    8.                 vec2 st = gl_Vertex.xy + gl_Normal.xy;
    9.                 gl_FrontColor = texture2D(_MainTex, st);
    10.             }
    11.  
    12.             #endif
    13.  
    That way all four vertices end up with the same colour, so interpolation has no effect.