Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Possible to set variable in vertex shader and read it in all frag?

Discussion in 'Shaders' started by Henning_Justare, Jun 20, 2016.

  1. Henning_Justare

    Henning_Justare

    Joined:
    Nov 10, 2014
    Posts:
    21
    CanvasRendere doesn't support MaterialPropertyBlocks, so I don't see any other option, than to try to encode information/data in the mesh vertices, as to avoid having a new material, for each instance of Image/CanvasRendere, in my GUI layout.

    So I'm trying to set a variable within vert to decode the data, and use it in frag, but haven't had any success :(

    I want to set a variable (testData in the example shader below) and use it for all frag's.
    Setting testData =v.vertex.y; in vert doesn't seam to have any effect on the value in frag

    Is this possible or can I encode data for each shader in another way?

    Thanks.

    Code (CSharp):
    1. Shader "My/Color"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (1,1,1,1)
    6.     }
    7.  
    8.         SubShader
    9.     {
    10.         Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
    11.         Blend SrcAlpha OneMinusSrcAlpha
    12.         pass
    13.         {
    14.             ZTest Always
    15.             ZWrite off
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.             #include "UnityCG.cginc"
    20.  
    21.             fixed4 _Color;
    22.             float testData;
    23.  
    24.             struct appdata {
    25.                 float4 vertex : POSITION;
    26.                 float4 texCoord  : TEXCOORD0;
    27.             };
    28.  
    29.             struct v2f {
    30.                 float4 vertex : POSITION;
    31.                 float4 texCoord  : TEXCOORD0;
    32.             };
    33.  
    34.             v2f vert(appdata v) {
    35.                 v2f o;
    36.  
    37.                 if (v.vertex.x > 990 && v.vertex.x < 1010)
    38.                 {
    39.                     testData =v.vertex.y;
    40.                 }
    41.  
    42.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    43.                 o.texCoord = v.texCoord;
    44.  
    45.                 return o;
    46.             }
    47.  
    48.             fixed4 frag(v2f i) : COLOR
    49.             {
    50.                 return _Color * testData;
    51.             }
    52.             ENDCG
    53.         }
    54.     }
    55. }
    56.  
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,248
    There's no actual link between the vertex shader and the fragment shader from a GPU perspective. They're in a single file for Unity to make it easier to deal with, but on the GPU they are separate "things" and each run of them is a unique instance (ie: each vertex, each pixel, and each frame know nothing of the other frames, pixels*, or vertices). They only communicate via the v2f struct. If you want to pass something from the vertex shader to the fragment shader you have to add additional variables to that struct.

    * Fragment shaders (aka pixel shaders) actually do have some knowledge of neighboring pixels. GPUs always render 2x2 blocks of pixels and that data can kind of be accessed via ddx() ddy() and fwidth() functions. This is done because of how GPUs calculate mip map levels.
     
    shaderop and Henning_Justare like this.
  3. Henning_Justare

    Henning_Justare

    Joined:
    Nov 10, 2014
    Posts:
    21
    Ok I see, thanks for the feedback. Thought the shader itself was an entity with common variables. To
    caught up in the class structure of OOP.

    So any idea of how to get unique data into the material when MaterialPropertyBlocks is not an option (CanvasRendere).

    Still don't want a material instance for each panel ui-element... :/
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,248
    There's no reason you can't encode the data the way you're already doing it, just instead pass that information using the v2f struct.

    struct v2f {
    float4 vertex : POSITION;
    float4 texCoord : TEXCOORD0;
    float testData : TEXCOORD1;
    };

    ...

    o.testData = v.vertex.y;

    ...

    return _Color * i.testData;
     
  5. Henning_Justare

    Henning_Justare

    Joined:
    Nov 10, 2014
    Posts:
    21
    Then I'm missing something...

    I have 8 float in all (4 floats and 4 for a color) I need to get to the fragment shader, and as the vertices know nothing about each other as you informed me, I can't, as I see it.

    Thanks so much for your time helping :)
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,248
    They don't know anything about eachother, no ... but the vertex shader can pass information to the fragment shader, or more accurately the GPU takes data the vertex shaders output and interpolate them across the face of the triangle and then sends that interpolated data to each fragment shader. The v2f struct is so named because it's the "vertex to fragment" data struct. The name is actually arbitrary, the " : TEXCOORD" suffixes, or semantics, are what actually matter, but that'll probably just confuse you.

    I recommend reading this:
    http://www.alanzucconi.com/2015/06/10/a-gentle-introduction-to-shaders-in-unity3d/

    Part 4 has stuff specifically about what you're trying to understand, but I recommend going through the whole thing.
     
  7. Henning_Justare

    Henning_Justare

    Joined:
    Nov 10, 2014
    Posts:
    21
    It turned out that Image OnPopulateMesh was overwriting all my efforts each. :mad: Well who knew :)

    I've re-written Image and got everything to work using TANGENT to store the data :D Still needs some tweaking, but it woks YAY!

    I'll take a look at the link. :) It looks a bit more digestible than the one I'm currently reading at http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter01.html

    Thanks again :)
     
    Last edited: Jun 21, 2016