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:
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.
List<Vector4> baseUVs = new List<Vector4>();
subMesh.GetUVs(0, baseUVs);
// loop start
baseUVs[count].z = j / (subMeshSide - 1);
baseUVs[count].w = i / (subMeshSide - 1);
// loop end
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.
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
// note float4 not float2
float4 uv : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
// only float2 for UVs passed to fragment
float2 uv : TEXCOORD0;
// no dispUV since presumably it's not needed in the fragment shader
};
v2f VertexProgram(appdata v) {
v2f i;
UNITY_INITIALIZE_OUTPUT(v2f, i);
// use z and w components of v.uv for the displacement texture.
// no need to apply TRANSFORM_TEX since presumably you don't ever want
// to use the scale offset settings for it
float d = tex2Dlod(_DispTex, float4(1 - v.uv.z, v.uv.w, 0, 0)).r * _Displacement;
v.vertex.y -= v.normal.y * d;
v.vertex.y += v.normal.y * _Displacement;
// for base color UVs only use the x and y of v.uv, and apply _MainTex offsets (if you want them)
i.uv = TRANSFORM_TEX(v.uv.xy, _MainTex);
i.pos = UnityObjectToClipPos(v.vertex);
return i;
}
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.