Search Unity

How to write to the different TEXCOORD channels?

Discussion in 'Shaders' started by Mr_Admirals, Jan 16, 2019.

  1. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Hello!

    I feel like I have a unique situation that may be a bit challenging to explain. Here goes:

    I start off with a single planar mesh and use a C# script I wrote to subdivide the mesh into separate meshes. Important to note is that the UV coordinates are preserved, so all the "sub-meshes" still look like the starting mesh. This works great and wasn't tricky to do at all, and I rather like this property of the script.

    BUT, I need a separate set of UV coordinates that will use an entire texture for the purpose of vertex displacement. I know I should be taking advantage of the different TEXCOORD channels, but I don't quite know how to write to them with a C# script. My initial intuition was to write to the different UV channels, but that doesn't seem to work.

    Here's my relevant portion of the shader and scripts before I really started messing with them:

    Shader:
    Code (CSharp):
    1. struct appdata {
    2.     float4 vertex : POSITION;
    3.     float3 normal : NORMAL;
    4.     float4 tangent : TANGENT;
    5.     float2 uv : TEXCOORD0;
    6.     float2 uv1 : TEXCOORD1;
    7.     float2 uv2 : TEXCOORD2;
    8. };
    9.  
    10. struct v2f {
    11.     float4 pos : SV_POSITION;
    12.     float2 uv : TEXCOORD0;
    13.     float3 normal : TEXCOORD1;
    14.     float2 dispUV : TEXCOORD2;
    15. };
    16.  
    17. v2f VertexProgram(appdata v) {
    18.     v2f i;
    19.     UNITY_INITIALIZE_OUTPUT(v2f, i);
    20.  
    21.     i.uv = TRANSFORM_TEX(v.uv, _DispTex);
    22.  
    23.     float d = tex2Dlod(_DispTex, float4(1 - i.uv.x, i.uv.y, 0, 0)).r * _Displacement;
    24.     //v.normal = normalize(v.normal);
    25.     v.vertex.y -= v.normal.y * d;
    26.     v.vertex.y += v.normal.y * _Displacement;
    27.  
    28.     i.pos = UnityObjectToClipPos(v.vertex);
    29.     return i;
    30. }
    Script:

    Code (CSharp):
    1. // Set up displacement UVs
    2.             Vector2[] dispUVs = new Vector2[subMesh.vertexCount];
    3.             for(int count = 0, i = 0; i < subMeshSide; i++)
    4.             {
    5.                 for(int j = 0; j < subMeshSide; j++, count++)
    6.                 {
    7.                     dispUVs[count] = new Vector2(j / (subMeshSide - 1), i / (subMeshSide - 1));
    8.                 }
    9.             }
    10.             subMesh.uv2 = dispUVs;
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    In the shader, the mesh's UVs from appdata are zero based, ie: TEXCOORD0, TEXCOORD1, etc., like you already have in your shader. From script the .uv is one based, ie: uv (1), uv2, uv3, etc. That means subMesh.uv2 == TEXCOORD1. I would recommend using the SetUVs() function instead as they're zero based just like the shaders which will reduce confusion. Additionally the SetUVs() function lets you set a Vector4/float4 value per UV instead of being limited to a Vector2 value. That means you can store both the base texture and displacement UVs in one uv set.

    Code (csharp):
    1. List<Vector4> baseUVs = new List<Vector4>();
    2. subMesh.GetUVs(0, baseUVs);
    3. // loop start
    4. baseUVs[count].z = j / (subMeshSide - 1);
    5. baseUVs[count].w = i / (subMeshSide - 1);
    6. // loop end
    7. subMesh.SetUVs(0, baseUVs);
    Now, in the shader, you're currently never actually using those extra UVs, only the first one. But presumably you want to pass on the original UVs for use in the fragment shader still and only need the displacement UVs in the vertex shader.

    Code (csharp):
    1. struct appdata {
    2.     float4 vertex : POSITION;
    3.     float3 normal : NORMAL;
    4.     float4 tangent : TANGENT;
    5.     // note float4 not float2
    6.     float4 uv : TEXCOORD0;
    7. };
    8.  
    9. struct v2f {
    10.     float4 pos : SV_POSITION;
    11.     // only float2 for UVs passed to fragment
    12.     float2 uv : TEXCOORD0;
    13.     // no dispUV since presumably it's not needed in the fragment shader
    14. };
    15.  
    16. v2f VertexProgram(appdata v) {
    17.     v2f i;
    18.     UNITY_INITIALIZE_OUTPUT(v2f, i);
    19.  
    20.     // use z and w components of v.uv for the displacement texture.
    21.     // no need to apply TRANSFORM_TEX since presumably you don't ever want
    22.     // to use the scale offset settings for it
    23.     float d = tex2Dlod(_DispTex, float4(1 - v.uv.z, v.uv.w, 0, 0)).r * _Displacement;
    24.     v.vertex.y -= v.normal.y * d;
    25.     v.vertex.y += v.normal.y * _Displacement;
    26.  
    27.     // for base color UVs only use the x and y of v.uv, and apply _MainTex offsets (if you want them)
    28.     i.uv = TRANSFORM_TEX(v.uv.xy, _MainTex);
    29.     i.pos = UnityObjectToClipPos(v.vertex);
    30.     return i;
    31. }
     
    Mr_Admirals likes this.
  3. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Awesome! Thank you so much! I'll check it out later today and report back on if I was able to get it to work.
     
  4. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Okay, so I implemented your suggestions and got it running, but nothing overall seems to have changed... Hmm...

    Here's a clip of what's going on.

    There's three main things.

    1. The scale is wrong
    2. The displacement is incorrect
    3. The tessellation does not follow the displacement.

    Looks like I have some more debugging to do. Which is annoying because everything I have works on an ordinary mesh.
     
  5. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    I was about to say I had to scrap the notion of preserving the original UV coordinates because it wouldn't have worked, but upon typing it out I figured it out!

    Anyway, I got it all working now. The earlier issue was that I was forgetting to adjust the relevant tessellation and fragment items as I was making adjustments. Silly me.
     
    bgolus likes this.
  6. canyon_gyh

    canyon_gyh

    Joined:
    Aug 15, 2018
    Posts:
    48
    Thanks,i think:
    textcoord = uv = mesh
    upload_2021-3-16_9-42-5.png