public void ToMesh(Mesh m, bool computeLightMapUVs)
        {
            m.Clear();
            m.indexFormat = triangles.Count > 65535 ? UnityEngine.Rendering.IndexFormat.UInt32 : UnityEngine.Rendering.IndexFormat.UInt16;
            m.SetVertices(vertices);
            m.SetNormals(normals);
            if (uvs0.Count == vertices.Count)
            {
                m.SetUVs(0, uvs0);
            }
            if (color32s.Count == vertices.Count)
            {
                m.SetColors(color32s);
            }

            m.subMeshCount = 1;
            m.SetTriangles(triangles, 0);

            if (computeLightMapUVs)
            {
                UnwrapParam param;
                UnwrapParam.SetDefaults(out param);
                param.packMargin = 0.02f;
                Unwrapping.GenerateSecondaryUVSet(m, param);
            }

            m.RecalculateBounds();
            // TODO: Use bounds
        }
	public static void UnwrapUV2(Mesh mesh, float hardAngle, float packingMargin){
			UnwrapParam up = new UnwrapParam();
			UnwrapParam.SetDefaults(out up);
			up.hardAngle = hardAngle;
			up.packMargin = packingMargin;
			Unwrapping.GenerateSecondaryUVSet(mesh,up);
	}
		public static void GenerateSecondaryUVSet(Mesh meshsrc)
		{
#if UNITY_EDITOR
			UnwrapParam param;
			UnwrapParam.SetDefaults(out param);
			Unwrapping.GenerateSecondaryUVSet(meshsrc, param);
#else
			Debug.LogWarning("GenerateSecondaryUVSet is unavailable at runtime!");
#endif
		}
示例#4
0
        public static void GenerateUV2(this Mesh mesh, bool forceUpdate)
        {
            // SetUVParams(8f, 15f, 15f, 20f);
            UnwrapParam param;

            UnwrapParam.SetDefaults(out param);

            Unwrapping.GenerateSecondaryUVSet(mesh, param);

            EditorUtility.SetDirty(mesh as Object);
        }
示例#5
0
 private void RegenLightmapUV()
 {
     meshFilter = GetComponent <MeshFilter>();
     if (!meshFilter)
     {
         Debug.LogError("No Mesh filter found on object");
         return;
     }
     mesh = meshFilter.sharedMesh;
     if (!mesh)
     {
         Debug.LogError("Mesh not assigned in meshfilter...");
         return;
     }
     Debug.Log("Secondary UV Set Generate: Start");
     unwrapParam = new UnwrapParam();
     UnwrapParam.SetDefaults(out unwrapParam);
     Unwrapping.GenerateSecondaryUVSet(mesh, unwrapParam);
     Debug.Log("Secondary UV Set Generate: Complete");
 }
    private void Change_Scaleinlightmap(GameObject go, bool OneMesh, Mesh finalMesh, Meshcombinervtwo myScript)
    {
        //Check if he got a renderer
        if (go.GetComponent <MeshRenderer>() != null)
        {
            //Find the property and modify them

            SerializedObject   serializedObject2     = new UnityEditor.SerializedObject(go.GetComponent <Renderer>());
            SerializedProperty m_nScaleInLightmap    = serializedObject2.FindProperty("m_ScaleInLightmap");
            SerializedProperty m_StitchLightmapSeams = serializedObject2.FindProperty("m_StitchLightmapSeams");
            serializedObject2.Update();

            m_nScaleInLightmap.floatValue   = f_ScaleInLightmap.floatValue;
            m_StitchLightmapSeams.boolValue = b_StitchSeams.boolValue;

            serializedObject2.ApplyModifiedProperties();
        }


        if (!OneMesh)
        {                                           // If there is nothing to combine delete the object
            if (myScript.gameObject.GetComponent <MeshFilter>())
            {
                myScript.gameObject.GetComponent <MeshFilter>().sharedMesh = null;
            }
        }
        else
        {
            UnwrapParam param = new UnwrapParam();              // enable lightmap


            UnwrapParam.SetDefaults(out param);
            param.hardAngle  = _HardAngle.floatValue;
            param.packMargin = _PackMargin.floatValue;
            param.angleError = _AngleError.floatValue;
            param.areaError  = _AreaError.floatValue;


            Unwrapping.GenerateSecondaryUVSet(finalMesh, param);
        }
    }
示例#7
0
    public static void GenerateUV2(this pb_Object pb, bool forceUpdate)
    {
        if (pb_Preferences_Internal.GetBool(pb_Constant.pbDisableAutoUV2Generation) && !forceUpdate)
        {
            return;
        }

        // SetUVParams(8f, 15f, 15f, 20f);
        UnwrapParam param;

        UnwrapParam.SetDefaults(out param);

        param.angleError = Mathf.Clamp(pb.angleError, 1f, 75f) * .01f;
        param.areaError  = Mathf.Clamp(pb.areaError, 1f, 75f) * .01f;
        param.hardAngle  = Mathf.Clamp(pb.hardAngle, 0f, 180f);
        param.packMargin = Mathf.Clamp(pb.packMargin, 1f, 64) * .001f;

        Unwrapping.GenerateSecondaryUVSet(pb.GetComponent <MeshFilter>().sharedMesh, param);

        EditorUtility.SetDirty(pb);
    }
        public void ApplyTo(Mesh target, bool recalculateTangents, bool recalculateLightMapUVs)
        {
            target.Clear(false);
            target.vertices = vertices;
            if (normals != null)
            {
                target.normals = normals;
            }
            if (tangents != null)
            {
                target.tangents = tangents;
            }
            if (uvs != null)
            {
                target.SetUVs(0, new List <Vector2>(uvs));
            }
            if (colors != null)
            {
                target.colors32 = colors;
            }

            target.SetTriangles(tris, 0);

            if (recalculateTangents)
            {
                target.RecalculateTangents();
            }

            UnwrapParam param;

            UnwrapParam.SetDefaults(out param);
            param.packMargin = 0.02f;

            if (recalculateLightMapUVs)
            {
                Unwrapping.GenerateSecondaryUVSet(target, param);
            }
        }
示例#9
0
 void UvsGUI()
 {
     //EditorGUILayout.PropertyField(m_SwapUVChannels, Styles.SwapUVChannels);
     EditorGUILayout.PropertyField(m_GenerateSecondaryUV, Styles.GenerateSecondaryUV);
     if (m_GenerateSecondaryUV.boolValue)
     {
         m_SecondaryUVAdvancedOptions = EditorGUILayout.Foldout(m_SecondaryUVAdvancedOptions, Styles.GenerateSecondaryUVAdvanced, true, EditorStyles.foldout);
         if (m_SecondaryUVAdvancedOptions)
         {
             using (new EditorGUI.IndentLevelScope())
             {
                 // TODO: all slider min/max values should be revisited
                 EditorGUI.BeginChangeCheck();
                 EditorGUILayout.Slider(m_SecondaryUVHardAngle, 0, 180, Styles.secondaryUVHardAngle);
                 EditorGUILayout.Slider(m_SecondaryUVPackMargin, 1, 64, Styles.secondaryUVPackMargin);
                 EditorGUILayout.Slider(m_SecondaryUVAngleDistortion, 1, 75, Styles.secondaryUVAngleDistortion);
                 EditorGUILayout.Slider(m_SecondaryUVAreaDistortion, 1, 75, Styles.secondaryUVAreaDistortion);
                 if (EditorGUI.EndChangeCheck())
                 {
                     m_SecondaryUVHardAngle.floatValue       = Mathf.Round(m_SecondaryUVHardAngle.floatValue);
                     m_SecondaryUVPackMargin.floatValue      = Mathf.Round(m_SecondaryUVPackMargin.floatValue);
                     m_SecondaryUVAngleDistortion.floatValue = Mathf.Round(m_SecondaryUVAngleDistortion.floatValue);
                     m_SecondaryUVAreaDistortion.floatValue  = Mathf.Round(m_SecondaryUVAreaDistortion.floatValue);
                 }
                 if (GUILayout.Button("Reset LightmapSettings"))
                 {
                     UnwrapParam uvs;
                     UnwrapParam.SetDefaults(out uvs);
                     m_SecondaryUVHardAngle.floatValue  = Mathf.Round(uvs.hardAngle);
                     m_SecondaryUVPackMargin.floatValue = Mathf.Round(uvs.packMargin * 1000);
                     //Debug.Log(uvs.packMargin*1000);
                     m_SecondaryUVAngleDistortion.floatValue = Mathf.Round(uvs.angleError * 100);
                     m_SecondaryUVAreaDistortion.floatValue  = Mathf.Round(uvs.areaError * 100);
                 }
             }
         }
     }
 }
示例#10
0
    public static void GenerateUV2(this pb_Object pb, bool show_NoDraw)
    {
        if (pb.onlyNodraw)
        {
            Vector2[] u = new Vector2[pb.msh.vertices.Length];
            for (int n = 0; n < u.Length; n++)
            {
                u[n] = Vector2.zero;
            }
            pb.SetUV2(u);
            return;
        }

        Vector2[] uvs = pb.msh.uv;              // nodraw uvs are nuked in this process, so save 'em
        pb.ToMesh(true);                        // re-draw meshes without nodraw faces

        // SetUVParams(8f, 15f, 15f, 20f);
        UnwrapParam param;

        UnwrapParam.SetDefaults(out param);

        param.angleError = Mathf.Clamp(pb.angleError, 1f, 75f) * .01f;
        param.areaError  = Mathf.Clamp(pb.areaError, 1f, 75f) * .01f;
        param.hardAngle  = Mathf.Clamp(pb.hardAngle, 0f, 180f);
        param.packMargin = Mathf.Clamp(pb.packMargin, 1f, 64) * .001f;

        Unwrapping.GenerateSecondaryUVSet(pb.GetComponent <MeshFilter>().sharedMesh, param);

        if (show_NoDraw)
        {
            pb.ToMesh(false);
        }

        pb.msh.uv = uvs;

        EditorUtility.SetDirty(pb);
    }
示例#11
0
    void OnPostprocessModel(GameObject g)
    {
        Init();
        //if (storage == null) return;

        ModelImporter importer = (ModelImporter)assetImporter;

        if (importer.generateSecondaryUV)
        {
            // Auto UVs: Adjust UV padding per mesh
            //if (!storage.modifiedAssetPathList.Contains(assetPath) && g.tag == "BakeryProcessed") return;
            //if (ftLightmaps.IsModelProcessed(assetPath)) return;

            //g.tag = "BakeryProcessed";
            Debug.Log("Bakery: processing auto-unwrapped asset " + assetPath);
            if (storage != null)
            {
                ftLightmaps.MarkModelProcessed(assetPath, true);
            }

            uparams = new UnwrapParam();
            UnwrapParam.SetDefaults(out uparams);
            uparams.angleError = importer.secondaryUVAngleDistortion * 0.01f;
            uparams.areaError  = importer.secondaryUVAreaDistortion * 0.01f;
            uparams.hardAngle  = importer.secondaryUVHardAngle;

#if UNITY_2017_1_OR_NEWER
            deserializedSuccess = false;
            var props = importer.extraUserProperties;
            for (int p = 0; p < props.Length; p++)
            {
                if (props[p].Substring(0, 7) == "#BAKERY")
                {
                    var json = props[p].Substring(7);
                    deserialized        = JsonUtility.FromJson <ftGlobalStorage.AdjustedMesh>(json);
                    deserializedSuccess = true;
                    break;
                }
            }
#endif
            if (storage != null)
            {
                storage.InitModifiedMeshMap(assetPath);
            }

            AdjustUV(g.transform);
        }
        else
        {
            if (storage == null)
            {
                return;
            }

            Debug.Log("Bakery: checking for UV overlaps in " + assetPath);

            //if (g.tag == "BakeryProcessed") g.tag = "";
            ftLightmaps.MarkModelProcessed(assetPath, true);//false);

            // Manual UVs: check if overlapping
            CheckUVOverlap(g, assetPath);
        }

        if (g.tag == "BakeryProcessed")
        {
            g.tag = "";                             // remove legacy mark
        }
    }
示例#12
0
    public Material mat;                                                                                                        // Put here a material. This gameObject combine all the gameobject with this material. Assign material only for children of obj


    // Use this for initialization
    public void CombineMeshes()                                                         // -> Combine all the maesh with a specif material.
    {
        Quaternion oldRot  = obj.transform.rotation;                                    // Save the original position and rotation of obj
        Vector3    oldPos  = obj.transform.position;
        bool       OneMesh = false;                                                     // This variable is used to know if there is at least one mesh to combine

        obj.transform.rotation = Quaternion.identity;                                   // Init position to zero
        obj.transform.position = Vector3.zero;                                          // Init position to Vector3(0,0,0)

        MeshFilter[] filters = obj.GetComponentsInChildren <MeshFilter>();              // Find all the children with MeshFilter component

        Debug.Log(name + " is combining " + filters.Length + " meshes");


        Mesh finalMesh = new Mesh();                                                    // Create the new mesh

        CombineInstance[] combiners = new CombineInstance[filters.Length];              // Struct used to describe meshes to be combined using Mesh.CombineMeshes.


        for (int i = 0; i < filters.Length; i++)                                                                // Check all the children
        {
            if (filters[i].transform == obj.transform)                                                          // Do not select the parent himself
            {
                continue;
            }
            if (filters[i].gameObject.GetComponent <Renderer>() == null)                        // Check if there is Renderer component
            {
                continue;
            }
            bool checkTag = false;
            for (int j = 0; j < arrtags.Length; j++)                                                            // Check tag to know if you need to ignore this gameobject
            {
                if (filters[i].gameObject.tag == arrtags[j])
                {
                    checkTag = true;
                }
            }


            if (mat == filters[i].gameObject.GetComponent <Renderer>().sharedMaterial&& !checkTag &&            // Add this gameObject to the combiner
                filters[i].gameObject.GetComponent <Renderer>().enabled)
            {
                combiners[i].subMeshIndex = 0;
                combiners[i].mesh         = filters[i].sharedMesh;
                combiners[i].transform    = filters[i].transform.localToWorldMatrix;
                filters[i].gameObject.GetComponent <Renderer>().enabled = false;
                OneMesh = true;
            }
        }



        finalMesh.CombineMeshes(combiners);                                     // Combine the new mesh
        GetComponent <MeshFilter>().sharedMesh = finalMesh;                     // Create the new Mesh Filter
        GetComponent <Renderer>().material     = mat;                           // ADd the good material



        transform.rotation = oldRot;                                                            // Move the object at his original position
        transform.position = oldPos;

        obj.transform.rotation = oldRot;
        obj.transform.position = oldPos;

        if (!OneMesh)                                                                                           // If there is nothing to combine delete the object
        {
            gameObject.SetActive(false);
            GetComponent <MeshFilter>().sharedMesh = null;
            if (DeleteUnusedMaterial)
            {
                Object.DestroyImmediate(gameObject);
            }
        }
        else
        {
            UnwrapParam param = new UnwrapParam();                                      // enable lightmap
            UnwrapParam.SetDefaults(out param);
            Unwrapping.GenerateSecondaryUVSet(finalMesh, param);
        }
    }
示例#13
0
    public override void OnImportAsset(AssetImportContext ctx)
    {
        Debug.Log("Attempting to import AMF:" + ctx.assetPath);
        progressString += ctx.assetPath;
        EditorUtility.DisplayProgressBar(progressString, "Parsing...", 0);
        AMF amf = ParseAMF(ctx.assetPath);

        string workingDir = ctx.assetPath.Substring(0, ctx.assetPath.LastIndexOf("/") + 1);

        /*
         * Setup materials first
         */
        Dictionary <string, Material>      mats        = new Dictionary <string, Material>();
        Dictionary <string, AMFShaderInfo> matsHelpers = new Dictionary <string, AMFShaderInfo>();

        System.IO.Directory.CreateDirectory(workingDir + "Materials/");
        //System.IO.Directory.CreateDirectory(workingDir+"MaterialHelpers/");
        AMFShaderInfo asi;
        float         totalMats    = amf.shaderInfos.Count;
        float         matsComplete = 0;

        foreach (AdjutantSharp.ShaderInfo si in amf.shaderInfos)
        {
            EditorUtility.DisplayProgressBar("Setting up Materials...", si.sName, (matsComplete / totalMats));
            asi      = (AMFShaderInfo)AMFShaderInfo.CreateInstance(typeof(AMFShaderInfo));
            asi.name = si.sName;
            asi.SaveData(si);
            if (!mats.ContainsKey(si.sName))
            {
                string   path     = workingDir + "Materials/" + si.sName + ".mat";
                Material material = (Material)AssetDatabase.LoadAssetAtPath(workingDir + "Materials/" + si.sName + ".mat", typeof(Material));

                if (material == null)
                {
                    asi.workingDir = workingDir;
                    material       = asi.CreateMaterial();

                    /* if(si.GetType()==typeof(RegularShader)){
                     *  material=SetupRegularMaterial((RegularShader)si,workingDir);
                     * }else{
                     *  material=SetupTerrainMaterial((TerrainShader)si,workingDir);
                     * } */

                    AssetDatabase.CreateAsset(material, workingDir + "Materials/" + si.sName + ".mat");
                }



                mats.Add(si.sName, material);
                matsHelpers.Add(si.sName, asi);
                ctx.AddObjectToAsset("MaterialHelper-" + asi.sName, asi);
                ctx.DependsOnSourceAsset(workingDir + "Materials/" + si.sName + ".mat");

                /* if(material!=null)
                 *  ctx.AddObjectToAsset(material.name,material); */
            }
            matsComplete++;
        }
        //EditorUtility.DisplayProgressBar(progressString,"[4/5] Creating Meshes...",(4f/5f));

        /*
         * Create Meshes
         */

        GameObject root = new GameObject(amf.modelName);

        ctx.AddObjectToAsset(amf.modelName, root);
        ctx.SetMainObject(root);
        Dictionary <long, Mesh> meshList = ConvertMeshes(amf, mats, matsHelpers, root);

        //root.transform.rotation=Quaternion.Euler(-90f,0f,0f);

        /* LoadRegions(amf,root);
         * List<Mesh> meshList=CreateMeshes(amf,root.transform,mats);
         */
        UnwrapParam.SetDefaults(out uvSettings);
        EditorUtility.DisplayProgressBar(progressString, "[5/5] Finishing up...", (5f / 5f));
        float lightCount = 0;
        float totalLight = meshList.Count;

        foreach (Mesh m in meshList.Values)
        {
            /* if(GenerateLightmapUVs){
             *  EditorUtility.DisplayProgressBar("Generating Lightmaps","["+lightCount+"/"+totalLight+"] Generating UVs...",(lightCount/totalLight));
             *  Unwrapping.GenerateSecondaryUVSet(m,uvSettings);
             *  lightCount++;
             * } */
            ctx.AddObjectToAsset(m.name, m);
        }

        Debug.Log("AMF import complete");
        EditorUtility.ClearProgressBar();
    }
示例#14
0
 private void OnEnable()
 {
     UnwrapParam.SetDefaults(out unwrapParam);
 }
示例#15
0
    public void CombineMeshes(Material mat)                                                                                             // -> Combine all the maesh with a specif material.
    {
        Meshcombinervtwo myScript = (Meshcombinervtwo)target;

        GameObject newGameObject = new GameObject();

        newGameObject.AddComponent <MeshFilter>();
        newGameObject.AddComponent <MeshRenderer>();

        newGameObject.GetComponent <Renderer>().sharedMaterial = null;

        newGameObject.name = "Combine_" + mat.name;
        Undo.RegisterCreatedObjectUndo(newGameObject, "CombineMat" + mat.name);

        myScript.list_CreatedObjects.Add(newGameObject);

        bool OneMesh = false;                                                                                   // This variable is used to know if there is at least one mesh to combine

        newGameObject.transform.rotation = Quaternion.identity;                                                 // Init position to zero

        newGameObject.transform.SetParent(myScript.transform);
        newGameObject.transform.localPosition = new Vector3(0, 0, 0);                                                                   // Init position to Vector3(0,0,0)
        newGameObject.isStatic = true;

        MeshFilter[] filters = myScript.gameObject.GetComponentsInChildren <MeshFilter>(); // Find all the children with MeshFilter component

        Mesh finalMesh = new Mesh();                                                       // Create the new mesh

        CombineInstance[] combiners = new CombineInstance[filters.Length];                 // Struct used to describe meshes to be combined using Mesh.CombineMeshes.


        for (int i = 0; i < filters.Length; i++)                                                                // Check all the children
        {
            if (filters[i].transform == myScript.gameObject.transform)                                          // Do not select the parent himself
            {
                continue;
            }
            if (filters[i].gameObject.GetComponent <Renderer>() == null)                        // Check if there is Renderer component
            {
                continue;
            }
            bool checkTag = false;
            for (int j = 0; j < myScript.list_Tags.Count; j++)                                                          // Check tag to know if you need to ignore this gameobject
            {
                if (filters[i].gameObject.tag == myScript.list_Tags[j])
                {
                    checkTag = true;
                }
            }

            if (mat == filters[i].gameObject.GetComponent <Renderer>().sharedMaterial&& !checkTag &&            // Add this gameObject to the combiner
                filters[i].gameObject.GetComponent <Renderer>().enabled)
            {
                combiners[i].subMeshIndex = 0;
                combiners[i].mesh         = filters[i].sharedMesh;

                combiners[i].transform = filters[i].transform.localToWorldMatrix;

                myScript.list_CombineObjects.Add(filters[i].gameObject);

                SerializedObject serializedObject3 = new UnityEditor.SerializedObject(filters[i].gameObject.GetComponents <Renderer>());
                serializedObject3.Update();
                SerializedProperty tmpSer2 = serializedObject3.FindProperty("m_Enabled");
                tmpSer2.boolValue = false;
                serializedObject3.ApplyModifiedProperties();

                OneMesh = true;
            }
        }

        finalMesh.CombineMeshes(combiners);                                                     // Combine the new mesh
        newGameObject.GetComponent <MeshFilter>().sharedMesh = finalMesh;                       // Create the new Mesh Filter
        newGameObject.GetComponent <Renderer>().material     = mat;                             // ADd the good material

        if (!OneMesh)                                                                           // If there is nothing to combine delete the object
        {
            if (myScript.gameObject.GetComponent <MeshFilter>())
            {
                myScript.gameObject.GetComponent <MeshFilter>().sharedMesh = null;
            }
        }
        else
        {
            UnwrapParam param = new UnwrapParam();                                      // enable lightmap
            UnwrapParam.SetDefaults(out param);
            Unwrapping.GenerateSecondaryUVSet(finalMesh, param);
        }
    }
示例#16
0
    static string QuadsToMesh(
        MeshFilter mf,        // output mesh filter
        quadByUV quads,       // input structure -> quads
        string undoTitle      // title for undo operation
        )
    {                         // output a quad list to a mesh structure
        if (mf == null ||     // no output MeshFilter
            quads == null ||  // OR no quad list
            quads.Count <= 0) // OR no quad entries
        {
            return("");
        }
        // get original asset path and convert to a path we can load from/save to
        string path   = AssetDatabase.GetAssetPath(mf.sharedMesh);
        string suffix = path.Substring(path.LastIndexOf("."));
        string name   = path.Replace(suffix, ".asset");
        // get a previous instance of the mesh. if none, create new asset at path.
        Mesh m = AssetDatabase.LoadAssetAtPath <Mesh>(name);

        if (m == null)
        {                                                   // no old asset could be loaded. create new asset with new GUID.
            AssetDatabase.CreateAsset(new Mesh(), name);    // create file in DB
            AssetDatabase.SaveAssets();                     // save changes
            AssetDatabase.Refresh();                        // update DB
            m = AssetDatabase.LoadAssetAtPath <Mesh>(name); // reload from new path
        }
        // now dump every quad into the mesh. decimate vertices by only saving unique sets
        HashSet <Vertex>      allVertices = new HashSet <Vertex>();      // unique vertex entries of (P,N,UV)
        List <List <Vertex> > allQuads    = new List <List <Vertex> >(); // list of quad faces for indexing

        foreach (Vector2 UV in quads.Keys)                               // by UV color
        {
            foreach (Vector3 N in quads[UV].Keys)                        // by normal direction
            {
                foreach (float r in quads[UV][N].Keys)                   // by row
                {
                    foreach (HashSet <Vector3> A in quads[UV][N][r])     // for every "quad vertex set A"
                    {                                                    // dump every quads contents into the lists
                        // get clockwise winding, create vertex entries
                        List <Vector3> v = SortVerticesClockwise(A, N);  // raw A,B,C,D vectors
                        List <Vertex>  e = new List <Vertex>();          // face vertex entries
                        foreach (Vector3 p in v)                         // create vertex entry
                        {
                            e.Add(new Vertex(p, N, UV));
                        }
                        allVertices.UnionWith(e);                                                                               // add them to the global list
                        // now create the references and add them to the face list
                        List <Vertex> singleQuad = new List <Vertex>();
                        singleQuad.AddRange                                                                                     // add vertex-links for A+B triangle
                            (new Vertex[] { e[0], e[1], e[2], e[0], e[2], e[3] });
                        allQuads.Add(singleQuad);                                                                               // add to global quad face list
                    }
                }
            }
        }
        // convert the vertex lists to arrays. (V,N,UV)-lists have to be of same size (WTF, Unity?)
        List <Vertex>  entries  = new List <Vertex>(allVertices);
        List <Vector3> vertices = new List <Vector3>();
        List <Vector3> normals  = new List <Vector3>();
        List <Vector2> uvs      = new List <Vector2>();
        List <Color32> colors   = new List <Color32>();

        foreach (Vertex e in entries)
        {
            e.Dump(vertices, normals, uvs, colors);
        }
        // relink the faces to a proper index into the dumped lists
        List <int> faces = new List <int>();

        foreach (List <Vertex> vertexIndices in allQuads)
        {
            foreach (Vertex e in vertexIndices)
            {
                faces.Add(entries.IndexOf(e));
            }
        }
        // set final contents of output mesh
        m.Clear();                                                      // clear old contents first
        m.vertices = vertices.ToArray();                                // vertices
        m.normals  = normals.ToArray();                                 // normals
        m.uv       = uvs.ToArray();                                     // UV1
        m.colors32 = colors.ToArray();                                  // vertex colors
        m.SetTriangles(faces.ToArray(), 0);                             // triangles indices
        // optimize structures
        m.Optimize();
        m.RecalculateBounds();
        // generate lightmap set as UV2
        UnwrapParam up;                                         // unwrapping parameters

        UnwrapParam.SetDefaults(out up);                        // set to default
        up.hardAngle  *= 4;                                     // increase hard angles for less seams
        up.packMargin *= 4;                                     // increase margin (otherwise: black streaks)
        Unwrapping.GenerateSecondaryUVSet(m, up);               // generate UV2

        // save changes, update AssetDatabase again
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

        // update the MeshFilter to use the generated mesh
        Undo.RecordObject(mf, undoTitle);
        mf.sharedMesh = m;
        // check if we have to update a MeshCollider as well
        MeshCollider mc = mf.GetComponent <MeshCollider>();

        if (mc != null)
        {         // if a MeshCollider is present, also update it's shared mesh
            Undo.RecordObject(mc, undoTitle);
            mc.sharedMesh = m;
        }
        // return the title of the converted new mesh asset
        return(name);
    }