项目里面需要做一个蒙皮网格的合并。由于是在编辑器下的合并,贴图合并参考了雨松老哥的博客。https://www.xuanyusong.com/archives/4729 。
static Texture2D Combine(Texture2D []texs, ValueTuple<int,int>[]offests,int size)
{
Texture2D @out = new Texture2D(size, size, TextureFormat.RGBA32, true);
for (int i = 0; i < texs.Length; i++)
{
var tex = texs[i];
var offest = offests[i];
var width = tex.width;
var height = tex.height;
RenderTexture tmp = RenderTexture.GetTemporary(width,height,0,RenderTextureFormat.Default,RenderTextureReadWrite.Linear);
Graphics.Blit(tex, tmp);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = tmp;
Texture2D @new = new Texture2D(width, height);
@new.ReadPixels(new Rect(0, 0, width, height), 0, 0);
@new.Apply();
@out.SetPixels(offest.Item1, offest.Item2, width, height, @new.GetPixels());
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(tmp);
}
return @out;
}
合并后,根据offset计算UV偏移并重新赋值即可。但是在合 法线贴图的过程中,法线合并后的贴图的R通道值为空,而其他通道非空。我将texture的type设置为default后,再次合并后结果正确。所以解决方案一:在编辑器代码中,修改Teuture的import type,并重新读入贴图进行合并。但是由于这里会产生一些计算,因此速度会慢很多。
首先,在shader里面我认为拿到的法线贴图是正确的。
inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
{
fixed3 normal;
normal.xy = packednormal.wy * 2 - 1;
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
通过观察unpacknormal的代码,倒推出在normalmap type下,texture的a通道储存了法线的r通道的值。
而原贴图的b通道,则可以通过其他两个通道计算得出。
之所以如此,可以参考https://blog.csdn.net/leonwei/article/details/79893445,关于法线贴图压缩的知识。减小了压缩过程的损失。
那么我们可以直接修改Graphics.Blit,新编写一个材质,用于复制过程中对贴图的处理。
//在片段着色器中,拿到原始的法线贴图数据并写回
float3 normal = unpacknormal(tex2d(_normalMap,i.uv));
float3 color = normal * 0.5 + 0.5;
return float4(color,1);
最终结果看来,似乎有细微的差别,我这种凡人要看半天。如果懂的大神麻烦讲一下(-.-)。我猜是因为从压缩格式读入数据并重写压缩后,由于压缩是有损压缩数据会丢失一部分,虽然效果上并不明显。所以后面如果美术大大有问题,还是会选择直接修改texuture type吧(-_-)。
最后提一句,由于法线贴图不储存颜色,而是储存数据信息,因此注意选择线性空间而不是SRGB。。