Tiling a noise texture 1:1 over each triangle without creating extra vertices
I have a flat shaded art style which derives mesh normals in a fragment shader using -cross(normalize(ddx(input.posWorld.xyz)), normalize(ddy(input.posWorld.xyz)));
. Vertices are shared by multiple triangles (welded).
Now I'd like to apply a tiling grit texture without increasing the number of vertices. It doesn't matter where the pattern starts or ends on each triangle so long as the ratio is 1:1. It currently looks stretched and distorted:
If I tell Unity to generate UV2s for the mesh with GenerateSecondaryUVSet, it creates (sometimes doubles) the number of vertices in the mesh. If I then use the resulting UV2 in place of UV1 I get exactly how I want it to look:
So, is there a way to get this look without adding vertices? I don't fully understand what GenerateSecondaryUVSet is doing or whether the extra vertices are necessary for a mesh-based solution.
Maybe there's a way to do this in the shader?
Answer by sarahnorthway · May 24, 2017 at 04:03 AM
I can use dynamic triplanar UV mapping, which looks close to correct and needs no extra vertices. UV is calculated from the top, front, and side, then the best one is used (or usually a blend). Code from the fragment shader:
half3 uvY = tex2D(_MainTex, IN.worldPos.xz);
half3 uvX = tex2D(_MainTex, IN.worldPos.zy);
half3 uvZ = tex2D(_MainTex, IN.worldPos.xy);
half3 blendWeights = pow(abs(normalDirection), 100);
blendWeights = blendWeights / (blendWeights.x + blendWeights.y + blendWeights.z);
fixed3 albedo = uvX * blendWeights.x + uvY * blendWeights.y + uvZ * blendWeights.z;
Seems like I should be able to reduce this from 3 planes to 1, especially since I maxed out the blend weights. Some combination of the normal & global position? I'd also like to use local position so objects don't look weird when moving, but can't quite get that right.