The goal is to merge multiple meshes into one or several, reduce drawcall, but don't want to mark it as static, and don't want to make an attempt to merge with 3dmax.
First, install FBX Exporter in Window -> Package Manager. My unity version is 2020, and 2019 should also work.
After successful installation, I found that right-clicking the GameObject can export fbx.
The next step is to merge multiple meshes
Suppose I have such 100 cubes, and I want to merge them into 1 mesh.
First, try exporting directly with Fbx Export.
After exporting, there are still many cubes, which are different from what I want.
My current idea is to read the vertex nv normal information of each mesh, and then when the triangles are in the new mesh, add the number of previous points each time, and it feels that there is no problem connecting the faces.
Then different materials need to be divided into different meshes.
First, get the mesh of all selected objects, and then I temporarily record it in a Dictionary<string, List> meshByMaterial according to the name of the material (the string should be changed to a direct material in the future)
The merged mesh is placed under the newly created object
GameObject newObjsRoot = new GameObject(name + "__combine");
newObjsRoot.transform.position = Vector3.zero;
foreach (KeyValuePair<string, List<MeshFilter>> keyPair in meshByMaterial)
{
//材质一样的mesh 放到一个父物体下
currentMaterialParent = new GameObject(keyPair.Key).transform;
currentMaterialParent.transform.SetParent(newObjsRoot.transform);
CombineMeshes(keyPair.Value);
}
Every time a new mesh is created, the previous data is cleared
private static void ClearMeshAttribute()
{
vertices = new List<Vector3>();
uvs = new List<Vector2>();
normals = new List<Vector3>();
indices = new List<int>();
// addMaxIndics = 0;
tangents = new List<Vector4>();
addMaxIndics = 0;
}
Get the position of the vertices of each mesh in world coordinates
for (int i = 0; i < newVertices.Length; i++)
{
vertices.Add(meshObj.transform.TransformPoint(newVertices[i]));
}
Store a V3 of the scaling direction of the GameObject. If the Obj has a negative scaling, the normal and traingle order need to be changed.
Vector3 fixV3 = new Vector3(
meshObj.transform.localScale.x < 0 ? -1 : 1,
meshObj.transform.localScale.y < 0 ? -1 : 1,
meshObj.transform.localScale.z < 0 ? -1 : 1
);
store normals
for (int i = 0; i < newNormals.Length; i++)
{
newNormals[i] = new Vector3(
newNormals[i].x * fixV3.x,
newNormals[i].y * fixV3.y,
newNormals[i].z * fixV3.z
);
}
// local scale is negative to reverse the face
if (fixV3.x * fixV3.y * fixV3.z < 0)
{
for (int i = 0; i < newIndices.Length; i += 3)
{
int change = newIndices[i + 1];
newIndices[i + 1] = newIndices[i + 2];
newIndices[i + 2] = change;
}
}
Then each number in the Indices of each mesh is added to the number of vertices stored in the mesh before. After finishing the work, save the number of vertices of the current mesh
for (int i = 0; i < newIndices.Length; i++)
{
int index = newIndices[i] + addMaxIndics;
indices.Add(index);
}
addMaxIndics = vertices.Count;
Then I found that when there are too many vertices, the surface will be very strangely damaged. After checking, someone said that unitymesh has a maximum vertex limit of 65535, so if it exceeds this number, create a new mesh storage.
if (newVertices.Length + vertices.Count >= maxVerticesCount)
{
CreateNewMesh(material);
ClearMeshAttribute();
}
Finally, CreateNewMesh assigns a value to the mesh and generates
Click Window/combineMeshEditor and FBX Exporter
appears in the scene
. After exporting, it can be seen that it is a mesh
TODO Use Unity's CombineMeshes to complete the above functions
Project address https://gitee.com/go_x/unity-project.git