unity提供了CombineInstance类用于网格的合并:
使用这个类可以非常简单的合并网格:
public class CombineMesh : MonoBehaviour
{
public SkinnedMeshRenderer[] smr;
private void Start()
{
List<CombineInstance> instances = new List<CombineInstance>();
for (int i = 0; i < smr.Length; i++)
{
CombineInstance instance = new CombineInstance
{
mesh = smr[i].sharedMesh,
transform = smr[i].localToWorldMatrix
};
instances.Add(instance);
}
Mesh mesh = new Mesh();
mesh.CombineMeshes(instances.ToArray(), false, true);
GetComponent<MeshFilter>().mesh = mesh;
}
}
上述代码合并后的网格仍需要三张贴图才能正常显示:
所以我们需要尝试将贴图合并,然后重新计算UV坐标:
private void Start()
{
List<Texture2D> texs = new List<Texture2D>();
List<CombineInstance> instances = new List<CombineInstance>();
for (int i = 0; i < smr.Length; i++)
{
CombineInstance instance = new CombineInstance
{
mesh = smr[i].sharedMesh,
transform = smr[i].localToWorldMatrix
};
instances.Add(instance);
texs.Add(smr[i].sharedMaterial.GetTexture("_BackTex") as Texture2D);
}
Mesh mesh = new Mesh();
mesh.CombineMeshes(instances.ToArray());
//合并纹理
Texture2D texture2D = new Texture2D(0, 0);
//通过矩形数据重新计算uv
Rect[] rects = texture2D.PackTextures(texs.ToArray(), 0);
List<Vector2> uvs = new List<Vector2>();
for (int i = 0; i < smr.Length; i++)
{
Vector2[] olduv = smr[i].sharedMesh.uv;
for (int j = 0; j < olduv.Length; j++)
{
float uvx = rects[i].x + rects[i].width * olduv[j].x;
float uvy = rects[i].y + rects[i].height * olduv[j].x;
uvs.Add(new Vector2(uvx, uvy));
}
}
mesh.uv = uvs.ToArray();
GetComponent<MeshFilter>().mesh = mesh;
Texture2D face = smr[0].sharedMaterial.GetTexture("_MainTex") as Texture2D;
Material material = new Material(Shader.Find("Custom/Face"));
material.SetTexture("_BackTex", texture2D);
material.SetTexture("_MainTex", face);
material.SetFloat("_PosX", texture2D.width / face.width);
material.SetFloat("_PosY", texture2D.height / face.height);
GetComponent<MeshRenderer>().material = material;
}
这样我们就将网格和贴图全部合并了,最后生成了一个完整的小人: