在unity中结合FBX Exporter合并mesh并导出Fbx

目标是把多个mesh合并成一个或者几个,降低drawcall,但是又不想标记成static的,也不想进3dmax合并的一个尝试。
首先在Window -> Package Manager里安装FBX Exporter,我的unity版本是2020,2019应该也可以
在这里插入图片描述
安装成功后发现右键GameObject,可以导出fbx了。
在这里插入图片描述

接下来就是合并多个mesh

假设我有这么100个cube,我想让他合并成1个mesh
在这里插入图片描述
首先直接用Fbx Export导出试试
在这里插入图片描述
导出后还是很多个cube,和我想要的不一样
在这里插入图片描述

我目前的想法是读取每个mesh的顶点 nv 法线信息,然后triangles在新的mesh的时候,每次加上之前点数量,感觉上连面就没有问题了。
然后不同的材质需要分不同的mesh。

首先要获取所有选中物体的mesh,之后我暂时根据material的名字记录在一个Dictionary<string, List> meshByMaterial里(以后应该把string改成 直接的material)

合并之后的mesh放在新创建的物体下

       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);
        }

在每次创建新mesh时,先清空之前的数据

    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;

    }

获取每个mesh的顶点在世界坐标下的位置


        for (int i = 0; i < newVertices.Length; i++)
        {
    
    
            vertices.Add(meshObj.transform.TransformPoint(newVertices[i]));
        }

存储一个GameObject缩放方向的V3,Obj要是有负数的缩放,法线和traingle顺序都需要改。

 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
                 );

存储法线

        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 是负数 要反转面

   
        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;

            }

        }

然后每个mesh的Indices中的每个数要加上之前存储mesh的顶点数。完事之后再把当前mesh的顶点数存下来

 for (int i = 0; i < newIndices.Length; i++)
        {
    
    
            int index = newIndices[i] + addMaxIndics;
            indices.Add(index);

        }
          addMaxIndics = vertices.Count;

然后发现,顶点数过多的时候,面会有很奇怪的破损,查了下有人说unitymesh有最大顶点限制65535,所以如果超过这个数字,就新建一个mesh存储。

    if (newVertices.Length + vertices.Count >= maxVerticesCount)
        {
    
    
            CreateNewMesh(material);
            ClearMeshAttribute();
        }

最终CreateNewMesh给mesh赋值,生成

点击Window/combineMeshEditor
在这里插入图片描述
场景里出现了在这里插入图片描述
FBX Exporter 导出后,可看出是一个mesh
在这里插入图片描述

TODO 用unity 的CombineMeshes来完成以上功能

项目地址 https://gitee.com/go_x/unity-project.git

猜你喜欢

转载自blog.csdn.net/weixin_38926960/article/details/124276313