Ejemplo n.º 1
0
    ///////////////////////////////////////////////////////////////////////////
    #region [SetInMeshFilter]

    /**
     * Convert a BMesh into a Unity Mesh and set it in the provided MeshFilter
     * WARNING: Only works with tri or quad meshes!
     * read attributes uv, uv2 from vertices and materialId from faces.
     *
     * NB: UVs are read from vertices, because in a Unity mesh when two face
     * corners have different UVs, they are different vertices. If you worked
     * with UVs as Loop attributes, you must first split points and migrate UVs
     * to vertex attributes.
     */
    public static void SetInMeshFilter(BMesh mesh, MeshFilter mf)
    {
        // Points
        Vector2[] uvs     = null;
        Vector2[] uvs2    = null;
        Vector3[] normals = null;
        Color[]   colors  = null;
        Vector3[] points  = new Vector3[mesh.vertices.Count];
        if (mesh.HasVertexAttribute("uv"))
        {
            uvs = new Vector2[mesh.vertices.Count];
        }
        if (mesh.HasVertexAttribute("uv2"))
        {
            uvs2 = new Vector2[mesh.vertices.Count];
        }
        if (mesh.HasVertexAttribute("normal"))
        {
            normals = new Vector3[mesh.vertices.Count];
        }
        if (mesh.HasVertexAttribute("color"))
        {
            colors = new Color[mesh.vertices.Count];
        }
        int i = 0;

        foreach (var vert in mesh.vertices)
        {
            vert.id   = i;
            points[i] = vert.point;
            if (uvs != null)
            {
                var uv = vert.attributes["uv"] as FloatAttributeValue;
                uvs[i] = new Vector2(uv.data[0], uv.data[1]);
            }
            if (uvs2 != null)
            {
                var uv2 = vert.attributes["uv2"] as FloatAttributeValue;
                uvs2[i] = new Vector2(uv2.data[0], uv2.data[1]);
            }
            if (normals != null)
            {
                var normal = vert.attributes["normal"] as FloatAttributeValue;
                normals[i] = normal.AsVector3();
            }
            if (colors != null)
            {
                var color = vert.attributes["color"] as FloatAttributeValue;
                colors[i] = color.AsColor();
            }
            ++i;
        }

        // Triangles
        int  maxMaterialId   = 0;
        bool hasMaterialAttr = mesh.HasFaceAttribute("materialId");

        if (hasMaterialAttr)
        {
            foreach (var f in mesh.faces)
            {
                maxMaterialId = Mathf.Max(maxMaterialId, f.attributes["materialId"].asInt().data[0]);
            }
        }

        int[] tricounts = new int[maxMaterialId + 1];
        foreach (var f in mesh.faces)
        {
            Debug.Assert(f.vertcount == 3 || f.vertcount == 4, "Only meshes with triangles/quads can be converted to a unity mesh");
            int mat = hasMaterialAttr ? f.attributes["materialId"].asInt().data[0] : 0;
            tricounts[mat] += f.vertcount - 2;
        }
        int[][] triangles = new int[maxMaterialId + 1][];
        for (int mat = 0; mat < triangles.Length; ++mat)
        {
            triangles[mat] = new int[3 * tricounts[mat]];
            tricounts[mat] = 0;
        }
        // from now on tricounts[i] is the index of the next triangle to fill in the i-th triangle list
        foreach (var f in mesh.faces)
        {
            int mat = hasMaterialAttr ? f.attributes["materialId"].asInt().data[0] : 0;
            Debug.Assert(f.vertcount == 3 || f.vertcount == 4);
            {
                var l = f.loop;
                triangles[mat][3 * tricounts[mat] + 0] = l.vert.id; l = l.next;
                triangles[mat][3 * tricounts[mat] + 2] = l.vert.id; l = l.next;
                triangles[mat][3 * tricounts[mat] + 1] = l.vert.id; l = l.next;
                ++tricounts[mat];
            }
            if (f.vertcount == 4)
            {
                var l = f.loop.next.next;
                triangles[mat][3 * tricounts[mat] + 0] = l.vert.id; l = l.next;
                triangles[mat][3 * tricounts[mat] + 2] = l.vert.id; l = l.next;
                triangles[mat][3 * tricounts[mat] + 1] = l.vert.id; l = l.next;
                ++tricounts[mat];
            }
        }

        // Apply mesh
        Mesh unityMesh = new Mesh();

        mf.mesh            = unityMesh;
        unityMesh.vertices = points;
        if (uvs != null)
        {
            unityMesh.uv = uvs;
        }
        if (uvs2 != null)
        {
            unityMesh.uv2 = uvs2;
        }
        if (normals != null)
        {
            unityMesh.normals = normals;
        }
        if (colors != null)
        {
            unityMesh.colors = colors;
        }
        unityMesh.subMeshCount = triangles.Length;

        // Fix an issue when renderer has more materials than there are submeshes
        var renderer = mf.GetComponent <MeshRenderer>();

        if (renderer)
        {
            unityMesh.subMeshCount = Mathf.Max(unityMesh.subMeshCount, renderer.materials.Length);
        }

        for (int mat = 0; mat < triangles.Length; ++mat)
        {
            unityMesh.SetTriangles(triangles[mat], mat);
        }

        if (normals == null)
        {
            unityMesh.RecalculateNormals();
        }
    }