Search Unity

Vertex to fragment array

Discussion in 'Shaders' started by Avol, Jan 19, 2018.

  1. Avol

    Avol

    Joined:
    May 27, 2016
    Posts:
    46
    Is it possible to pass an array of texture UV coordinates generated in vertex shader to fragment shader?
    Read somewhere that this way driver optimizes the texture sampling. Tested in webgl before, seemed to boost the performance slightly. Is it possible in Unity?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,967
    Sure.

    Code (csharp):
    1. struct v2f {
    2.   float4 pos : SV_POSITION;
    3.   float2 uvs[4] : TEXCOORD0;
    4. };
    5.  
    6. v2f vert (appdata_full v) {
    7.   v2f o;
    8.   o.pos = UnityObjectToClipPos(v.vertex);
    9.   o.uv[0] = v.texcoord.xy;
    10.   o.uv[1] = v.texcoord.xy * 0.5;
    11.   o.uv[2] = v.texcoord.xy * 2.0;
    12.   o.uv[3] = v.texcoord.xy * 4.0;
    13.   return v2f;
    14. }
    Note, in reality that's spanning the uvs over TEXCOORD0 through TEXCOORD3. It's also a poor use of the vertex to fragment shader memory bandwidth. Each of those TEXCOORD# is always a float4 worth of data for Direct3D*, so it's more efficient to do this:
    Code (csharp):
    1. struct v2f {
    2.   float4 pos : SV_POSITION;
    3.   float4 uvs0 : TEXCOORD0;
    4.   float4 uvs1 : TEXCOORD1;
    5. };
    6.  
    7. v2f vert (appdata_full v) {
    8.   v2f o;
    9.   o.pos = UnityObjectToClipPos(v.vertex);
    10.   o.uvs0 = float4(
    11.     v.texcoord.xy,
    12.     v.texcoord.xy * 0.5
    13.     );
    14.   o.uvs1 = float4(
    15.     v.texcoord.xy * 2.0,
    16.     v.texcoord.xy * 4.0
    17.     );
    18.   return v2f;
    19. }
    But it's also kind of moot a this point as the performance benefits of doing this are unlikely to still exist with WebGL 2.0 or OpenGL ES 3.0, and certainly do not with desktop or console. GPUs are really fast at calculating things, but the memory bandwidth hasn't increased as fast. So this should be faster for most modern GPUs, mobile or otherwise:
    Code (csharp):
    1. struct v2f {
    2.   float4 pos : SV_POSITION;
    3.   float4 uv : TEXCOORD0;
    4. };
    5.  
    6. v2f vert (appdata_full v) {
    7.   v2f o;
    8.   o.pos = UnityObjectToClipPos(v.vertex);
    9.   o.uv = float4(v.texcoord.xy, v.texcoord.xy * 0.5);
    10.   return v2f;
    11. }
    12.  
    13. fixed4 frag (v2f i) : SV_Target {
    14.   float2 uv0 = i.uv.xy;
    15.   float2 uv1 = i.uv.zw;
    16.   float2 uv2 = i.uv.xy * 2.0;
    17.   float2 uv3 = i.uv.xy * 4.0;
    18. }
    It depends on how complicated your UV calculations are, but for a simple case like above or even the TRANSFORM_TEX macro, doing almost all of it in the fragment shader is unlikely going to be slower.


    * OpenGL is more efficient at this and will actually send them as float2s, but it should still be faster to do it in the fragment shader most of the time.
     
  3. Avol

    Avol

    Joined:
    May 27, 2016
    Posts:
    46
    Cool, that explains a lot, thanks :)
     
unityunity