Unity Mesh及材质球合并
首先我们需要一个插件 Mesh Baker
下载链接传送门
a.我们创建2个物体分别给予不同的材质球
b.我们先来看一个Betches 及SetPass Calls
未处理前是6个,这里我把阴影关闭了。默认下可能会更高点
c.我们找到GameObject 工具栏下面的CreateOther 下新建一个TextureBakerAndMeshBaker
d.这个时候我们就开始合并吧
首先是待合并的MeshRender 当然也可以是SkinMeshRender 然后就是打包的图片图集一些相关的设置然后直接Bake 材质球吧
然后Bake Mesh 一下
最后我们关闭原来的MeshRender来看一下。可以插件关闭也可以手动关闭
有关动画的问题
个人测试下来,目前我带有动画的物体合并均需要在Bake成 SkinMeshRender 才可以播放,目前没有深究,我个人的处理办法是把原物体的Render关闭,然后挂在Animation 或者Animator 组件,然后Bake的时候选择SkinMeshRender动画正常播放,并且合并Mesh及材质球后互相不影响。
有关相同Shader 只是颜色不同的处理,或者就是仅仅颜色不同的材质球如何处理。
这里我们想到最简单的方式是用色块贴图来代替Shader中的RGB数值,这样在合并材质球的时候,它会打包成一个色块的颜色图集,然后对应的UV对上就好了(建议带纹理的贴图,颜色保持一致,如果颜色不一样,那么Shader也要对应的更改成用色块取色的Shader)这样就可以在同一个材质球下不同的颜色可以达到使用同一个材质的效果。
效果如下:
最后附一下自己尝试的Mesh 合并的代码及贴图合并的代码(仅供自己以后重构)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshCombine : MonoBehaviour
{
private void Start()
{
CombineMesh();
// SetColor();
// CombineMeshColor();
}
void CombineMesh()
{
MeshFilter[] mfChildren = GetComponentsInChildren<MeshFilter>();
CombineInstance[] combine = new CombineInstance[mfChildren.Length];
MeshRenderer[] mrChildren = GetComponentsInChildren<MeshRenderer>();
Material[] materials = new Material[mrChildren.Length];
MeshRenderer mrSelf = gameObject.AddComponent<MeshRenderer>();
MeshFilter mfSelf = gameObject.AddComponent<MeshFilter>();
Texture2D[] textures = new Texture2D[mrChildren.Length];
for (int i = 0; i < mrChildren.Length; i++)
{
if (mrChildren[i].transform == transform)
{
continue;
}
materials[i] = mrChildren[i].sharedMaterial;
Texture2D tx = materials[i].GetTexture("_MainTex") as Texture2D;
if (tx == null)
{
continue;
}
Texture2D tx2D = new Texture2D(tx.width, tx.height, TextureFormat.ARGB32, false);
tx2D.SetPixels(tx.GetPixels(0, 0, tx.width, tx.height));
tx2D.Apply();
textures[i] = tx2D;
}
Material materialNew = new Material(materials[0]);
materialNew.CopyPropertiesFromMaterial(materials[0]);
mrSelf.sharedMaterial = materialNew;
Texture2D texture = new Texture2D(1024, 1024);
materialNew.SetTexture("_MainTex", texture);
Rect[] rects = texture.PackTextures(textures, 10, 1024);
for (int i = 0; i < mfChildren.Length; i++)
{
if (mfChildren[i].transform == transform)
{
continue;
}
Rect rect = rects[i];
Mesh meshCombine = mfChildren[i].mesh;
Vector2[] uvs = new Vector2[meshCombine.uv.Length];
for (int j = 0; j < uvs.Length; j++)
{
uvs[j].x = rect.x + meshCombine.uv[j].x * rect.width;
uvs[j].y = rect.y + meshCombine.uv[j].y * rect.height;
}
meshCombine.uv = uvs;
combine[i].mesh = meshCombine;
combine[i].transform = mfChildren[i].transform.localToWorldMatrix;
mfChildren[i].gameObject.SetActive(false);
}
Mesh newMesh = new Mesh();
newMesh.CombineMeshes(combine, true, true);
mfSelf.mesh = newMesh;
}
void CombineMeshColor()
{
MeshFilter[] mfChildren = GetComponentsInChildren<MeshFilter>();
CombineInstance[] combine = new CombineInstance[mfChildren.Length];
MeshRenderer[] mrChildren = GetComponentsInChildren<MeshRenderer>();
Material[] materials = new Material[mrChildren.Length];
MeshRenderer mrSelf = gameObject.AddComponent<MeshRenderer>();
MeshFilter mfSelf = gameObject.AddComponent<MeshFilter>();
// Texture2D[] textures = new Texture2D[mrChildren.Length];
for (int i = 0; i < mrChildren.Length; i++)
{
if (mrChildren[i].transform == transform)
{
continue;
}
materials[i] = mrChildren[i].sharedMaterial;
// Texture2D tx = materials[i].GetTexture("_MainTex") as Texture2D;
// if (tx == null)
// {
// continue;
// }
//
// Texture2D tx2D = new Texture2D(tx.width, tx.height, TextureFormat.ARGB32, false);
// tx2D.SetPixels(tx.GetPixels(0, 0, tx.width, tx.height));
// tx2D.Apply();
// textures[i] = tx2D;
}
Material materialNew = new Material(materials[0]);
materialNew.CopyPropertiesFromMaterial(materials[0]);
mrSelf.sharedMaterial = materialNew;
// Texture2D texture = new Texture2D(1024, 1024);
// materialNew.SetTexture("_MainTex", texture);
// Rect[] rects = texture.PackTextures(textures, 10, 1024);
for (int i = 0; i < mfChildren.Length; i++)
{
if (mfChildren[i].transform == transform)
{
continue;
}
Mesh meshCombine = mfChildren[i].mesh;
Vector2[] uvs = new Vector2[meshCombine.uv.Length];
meshCombine.uv = uvs;
combine[i].mesh = meshCombine;
combine[i].transform = mfChildren[i].transform.localToWorldMatrix;
mfChildren[i].gameObject.SetActive(false);
}
Mesh newMesh = new Mesh();
newMesh.CombineMeshes(combine, true, true); //合并网格
mfSelf.mesh = newMesh;
}
}
这段代码仅仅是参考理解原理使用。效果达不到上述插件的效果(仅理解)