Well, usually a shader uses the same set of UV cooordinates for the mainTexture as well as the normal map. However you can write / modify a shader to use a different uv channel for the normal map. That way you can change the UVs for the main texture but you will keep the UVs for the normal map.
Another way would be to only have one set of UV coordinates but set shader parameters to tell the atlas tiling in u and v axis. Knowing that you can multiply the UVs by the tiling count and only use the fractional part as UV for your normal map.
Like MrSoad said, you can get alignment problems since the texture and the normal map use a different resolution and the UVs have different precision.
It’s usually better to just use the same layout for both, main texture and normal map.
ps: Didn’t you want to use a submesh for the coins face and the coins border in your other question? Of course using two seperate materials will cause 2 draw calls.
edit
Here it is. The example of the second solution.
The mesh consists of 4 quads combined in one mesh. The mesh has only one set of UVs. Since we use normalmapping the mesh needs vertex normals and tangents. Note: all textures and normal maps are simply taken from google image search
The atlas texture is one of the old terrain textures of minecraft. It’s an atlas that contains a uniform grid of tiles. In the material inspector i’ve set the x and y values of the “Atlas Tiling” to 16 because the atlas has 16x16 tiles (256 tiles / textures).
The shader is like i said just the normalmap example shader with a few modifications:
Shader "Custom/NormalMappedAtlas" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
_AtlasTiling ("Atlas Tiling", Vector) = (1,1,0,0)
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
sampler2D _BumpMap;
float4 _AtlasTiling;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
float2 bumpUV = frac(IN.uv_MainTex * _AtlasTiling.xy);
o.Normal = UnpackNormal (tex2D (_BumpMap, bumpUV));
}
ENDCG
}
Fallback "Diffuse"
}
The actual changes are:
- I added a new property called “Atlas Tiling” (the shader variable name is _AtlasTiling)
- Inside the CG code i declared that variable as vector (float4)
- And just added that one line of code to calculate the uv for the normal map
This line:
float2 bumpUV = frac(IN.uv_MainTex * _AtlasTiling.xy);
does all the magic. Here’a an example to understand what actually happens. As we know the incoming uv coordinates are between 0 and 1. Since our atlas is uniformly tiled you will only use a rectangular fraction of that range. The rectangle of the first tile (near uv 0/0) has the uv coordinates (0,0) and (1/16, 1/16) since there are 16 tiles in each direction. So when multiplying the incoming values (which are between 0 and 1/16) with the tile count (that’s 16) we get values between 0 and 1 and that’s what we want for the normalmap.
The second tile however has the uv coords: (1/16,0) and (2/16,1/16). The resulting uv in x / u direction would be between 1 and 2. If the normalmap’s wrapmode is set to repeat this would already work. However to bring the coordinates back into the 0 to 1 range we only use the fractional part by using the “frac” function. That’s all.
As i said earlier this method has some problems / restrictions. The atlas need to be uniformly tiled. Here are some examples of atlas textures where this technique wouldn’t work: different tile sizes1 different tile sizes2. Another problem is that you can’t use 1 or 2 pixel padding between the textures since the tiles need to be edge to edge. That will cause problems when mipmapping is used and you might get color bleeding when you use bilinear or trilinear filtering. One solutions would be to only use every second tile so one tile would be padding. That’s of course quite inefficient since you would waste about half of the texture space.
If color bleeding occures or when mipmapping gives you problems, the first solution would be better. There you can pack your atlas as you wish since you would pass the normalmap UVs seperately. But keep in mind that the second uv channel can’t be used for lightmapping or other things in this case. It’s also possible to put your second UV set into the color channel if it’s not required