Search Unity

[SOLVED] Get the closest vertex position in frag function

Discussion in 'Shaders' started by Romaleks360, Apr 5, 2020.

  1. Romaleks360

    Romaleks360

    Joined:
    Sep 9, 2017
    Posts:
    72
    Hello everyone! I want to write a shader for the LineRenderer, that will discard some area around each point/vertex. I think that for this purpose my shader should take a non-interpolated vertex position and compare it with the interpolated one. Somehow I managed to do it, but there's an issue. For some reason, I expected the frag function to get v2f data from the closest vertex, but it seems that the vert function runs once for a triangle, and all the pixels of this triangle will get this one vertex data.

    My questions:
    1. Am I right? From which vertex does frag function get its v2f struct?
    2. Is there a way to accomplish my goal? How do I get the closest vertex position in frag function?

    Picture 1 is describing the final result I want to get, pictures 2 and 3 are demonstrating my current shader result.

    Code (CSharp):
    1.  
    2. Shader "Unlit/Lines Unlit"
    3. {
    4.     Properties
    5.     {
    6.         _CutDistance ("Cut Distance", Float) = 2
    7.     }
    8.  
    9.     SubShader
    10.     {
    11.         Lighting Off
    12.         ZWrite Off
    13.         ZTest Always
    14.         Tags {"Queue" = "Overlay" }
    15.         Pass
    16.         {
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.             //#include "UnityCG.cginc"
    21.  
    22.             struct appdata_t {
    23.                 float4 vertex : POSITION;
    24.                 fixed4 color : COLOR;
    25.             };
    26.  
    27.             struct v2f {
    28.                 float4 vertex : SV_POSITION;
    29.                 fixed4 color : COLOR;
    30.                 float3 pos1 : TEXCOORD2;
    31.                 nointerpolation float3 pos2 : TEXCOORD3;
    32.             };
    33.  
    34.             v2f vert(appdata_t v)
    35.             {
    36.                 v2f o;
    37.                 o.vertex = UnityObjectToClipPos(v.vertex);
    38.                 o.color = v.color;
    39.                 o.pos1 = v.vertex;
    40.                 o.pos2 = v.vertex;
    41.                 return o;
    42.             }
    43.  
    44.  
    45.             half _CutDistance;
    46.  
    47.             fixed4 frag(v2f i) : SV_Target
    48.             {
    49.                 clip(distance(i.pos1, i.pos2) - _CutDistance);
    50.  
    51.                 return i.color;
    52.             }
    53.  
    54.             ENDCG
    55.         }
    56.     }
    57. }
    58.  
    59.  
     

    Attached Files:

    • 1.png
      1.png
      File size:
      8.8 KB
      Views:
      468
    • 2.png
      2.png
      File size:
      42.2 KB
      Views:
      466
    • 3.png
      3.png
      File size:
      204.5 KB
      Views:
      451
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    From all 3 vertices of the triangle at once for normally interpolated values, or for nointerpolation it is from the invoking vertex of the triangle, which is usually the first vertex of the triangle as defined by the triangle array, but may change depending on the device to the last vertex. The position of the vertex is irrelevant for which one is used. So, yes, you are correct the entire triangle only gets a single vertex’s position.

    If you want to get all 3 vertex positions for each triangle you have to encode that information into the vertex data manually, which you can’t do with the line renderer and a straight vertex fragment shader. Indeed, the invoking vertex is different for every triangle with the line renderer, so your plan isn’t really plausible.

    One option would be to use geometry shaders instead, which would let you get all 3 vertex positions and pass them to the fragment shader without needing to do anything special to generate your own mesh. Honestly it still won’t look like your target example, since that is checking the distance to the line point and not to the vertex points. It’ll be better than what you currently get, but not by much.

    The best solution is to not use a shader based or even line renderer based solution. Rather you’d probably be better serviced by using stretched quads, or otherwise generating the mesh you want manually.
     
  3. Romaleks360

    Romaleks360

    Joined:
    Sep 9, 2017
    Posts:
    72
    I was waiting for your reply. You made it clear to me, thank you for this and for all the shader consultation you are doing here, on unity forums. I often read your posts when looking for answers, and it really helps! Will mark this thread as solved.