【问题标题】:Why does my unity hang when importing an obj?为什么我的统一在导入 obj 时会挂起?
【发布时间】:2015-05-04 07:13:18
【问题描述】:

这是将 objs 导入我的 unity 的代码。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

public class ObjImporter : MonoBehaviour {

    public GameObject spawnPoint;
    public GameObject emptyPrefabWithMeshRenderer;
    public string meshPath;
    public GameObject spawnedPrefab;

    static float progressPercentageMin;
    static float progressPercentageMax;
    static float progressPercentage;

    public Texture2D barBG;
    public Texture2D barLoad;

    int noOfLines;

    void Start ()
    {
        progressPercentageMin = 0;
        progressPercentageMax = 0;
        progressPercentage = 0;
    }

    void Update ()
    {
        progressPercentage = Mathf.Lerp (progressPercentageMin, progressPercentageMax, Time.time * progressPercentageMax * 0.01f);
        if(Input.GetKeyDown("space")){
            Mesh importedMesh = GetComponent<ObjImporter>().ImportFile(meshPath);
            noOfLines = TotalLines(meshPath);
            spawnedPrefab=Instantiate(emptyPrefabWithMeshRenderer,spawnPoint.transform.position,spawnPoint.transform.rotation) as GameObject;
            spawnedPrefab.GetComponent<MeshFilter>().mesh=importedMesh;
            spawnedPrefab.GetComponent<Renderer>().material.color = new Color(Random.value, Random.value, Random.value, 1.0f);
        }
    }

    public static void UpdateProgressBar()
    {
        progressPercentageMax += 10;
    }

    private struct meshStruct
    {
        public Vector3[] vertices;
        public Vector3[] normals;
        public Vector2[] uv;
        public Vector2[] uv1;
        public Vector2[] uv2;
        public int[] triangles;
        public int[] faceVerts;
        public int[] faceUVs;
        public Vector3[] faceData;
        public string name;
        public string fileName;
    }

    // Use this for initialization
    public Mesh ImportFile (string filePath){
        meshStruct newMesh = createMeshStruct(filePath);
        populateMeshStruct(ref newMesh);

        UpdateProgressBar();

        Vector3[] newVerts = new Vector3[newMesh.faceData.Length];
        Vector2[] newUVs = new Vector2[newMesh.faceData.Length];
        Vector3[] newNormals = new Vector3[newMesh.faceData.Length];
        int i = 0;
        /* The following foreach loops through the facedata and assigns the appropriate vertex, uv, or normal
         * for the appropriate Unity mesh array.
         */

        UpdateProgressBar();

        foreach (Vector3 v in newMesh.faceData)
        {
            newVerts[i] = newMesh.vertices[(int)v.x - 1];
            if (v.y >= 1)
                newUVs[i] = newMesh.uv[(int)v.y - 1];

            if (v.z >= 1)
                newNormals[i] = newMesh.normals[(int)v.z - 1];
            i++;
        }

        Mesh mesh = new Mesh();

        mesh.vertices = newVerts;
        mesh.uv = newUVs;
        mesh.normals = newNormals;
        mesh.triangles = newMesh.triangles;

        mesh.RecalculateBounds();
        mesh.Optimize ();

        UpdateProgressBar();

        return mesh;
    }

    private int TotalLines(string filePath)
    {
        using (StreamReader r = new StreamReader(filePath))
        {
            int i = 0;
            while (r.ReadLine() != null)
            {
                i++;
            }
            return i;
        }
    }

    private static meshStruct createMeshStruct(string filename)
    {
        int triangles = 0;
        int vertices = 0;
        int vt = 0;
        int vn = 0;
        int face = 0;
        meshStruct mesh = new meshStruct();
        mesh.fileName = filename;

        // Read and retrieve all the text in the file.
        StreamReader stream = File.OpenText(filename);
        string entireText = stream.ReadToEnd();
        stream.Close(); // End of stream.

        UpdateProgressBar();

        // Going through the retrieved text.
        using (StringReader reader = new StringReader(entireText))
        {
            string currentText = reader.ReadLine();
            char[] splitIdentifier = { ' ' };
            string[] brokenString;

            UpdateProgressBar();

            while (currentText != null)
            {
                if (!currentText.StartsWith("f ") && !currentText.StartsWith("v ") && !currentText.StartsWith("vt ")
                    && !currentText.StartsWith("vn "))
                {
                    currentText = reader.ReadLine();
                    if (currentText != null)
                    {
                        currentText = currentText.Replace("  ", " ");
                    }
                }
                else
                {
                    currentText = currentText.Trim();                           // Trim the current line
                    brokenString = currentText.Split(splitIdentifier, 50);      // Split the line into an array, separating the original line by blank spaces
                    switch (brokenString[0])
                    {
                    case "v":
                        vertices++;
                        break;
                    case   "vt":
                        vt++;
                        break;
                    case "vn":
                        vn++;
                        break;
                    case "f":
                        face = face + brokenString.Length - 1;
                        triangles = triangles + 3 * (brokenString.Length - 2); /*brokenString.Length is 3 or greater since a face must have at least
                                                                                     3 vertices.  For each additional vertice, there is an additional
                                                                                     triangle in the mesh (hence this formula).*/
                        break;
                    }
                    currentText = reader.ReadLine();
                    if (currentText != null)
                    {
                        currentText = currentText.Replace("  ", " ");
                    }
                }
            }
            UpdateProgressBar();
        }
        mesh.triangles = new int[triangles];
        mesh.vertices = new Vector3[vertices];
        mesh.uv = new Vector2[vt];
        mesh.normals = new Vector3[vn];
        mesh.faceData = new Vector3[face];

        UpdateProgressBar();

        return mesh;
    }

    private static void populateMeshStruct(ref meshStruct mesh)
    {
        StreamReader stream = File.OpenText(mesh.fileName);
        string entireText = stream.ReadToEnd();
        stream.Close();

        UpdateProgressBar();

        using (StringReader reader = new StringReader(entireText))
        {
            string currentText = reader.ReadLine();

            char[] splitIdentifier = { ' ' };
            char[] splitIdentifier2 = { '/' };
            string[] brokenString;
            string[] brokenBrokenString;
            int f = 0;
            int f2 = 0;
            int v = 0;
            int vn = 0;
            int vt = 0;
            int vt1 = 0;
            int vt2 = 0;

            UpdateProgressBar();

            while (currentText != null)
            {
                if (!currentText.StartsWith("f ") && !currentText.StartsWith("v ") && !currentText.StartsWith("vt ") &&
                    !currentText.StartsWith("vn ") && !currentText.StartsWith("g ") && !currentText.StartsWith("usemtl ") &&
                    !currentText.StartsWith("mtllib ") && !currentText.StartsWith("vt1 ") && !currentText.StartsWith("vt2 ") &&
                    !currentText.StartsWith("vc ") && !currentText.StartsWith("usemap "))
                {
                    currentText = reader.ReadLine();
                    if (currentText != null)
                    {
                        currentText = currentText.Replace("  ", " ");
                    }
                }
                else
                {
                    currentText = currentText.Trim();
                    brokenString = currentText.Split(splitIdentifier, 50);
                    switch (brokenString[0])
                    {
                    case "g":
                        break;
                    case "usemtl":
                        break;
                    case "usemap":
                        break;
                    case "mtllib":
                        break;
                        // 
                    case "v":
                        mesh.vertices[v] = new Vector3(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]),
                                                       System.Convert.ToSingle(brokenString[3]));
                        v++;
                        break;
                    case "vt":
                        mesh.uv[vt] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]));
                        vt++;
                        break;
                    case "vt1":
                        mesh.uv[vt1] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]));
                        vt1++;
                        break;
                    case "vt2":
                        mesh.uv[vt2] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]));
                        vt2++;
                        break;
                    case "vn":
                        mesh.normals[vn] = new Vector3(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]),
                                                       System.Convert.ToSingle(brokenString[3]));
                        vn++;
                        break;
                    case "vc":
                        break;
                    case "f":

                        int j = 1;
                        List<int> intArray = new List<int>();
                        while (j < brokenString.Length && ("" + brokenString[j]).Length > 0)
                        {
                            Vector3 temp = new Vector3();
                            brokenBrokenString = brokenString[j].Split(splitIdentifier2, 3);    //Separate the face into individual components (vert, uv, normal)
                            temp.x = System.Convert.ToInt32(brokenBrokenString[0]);
                            if (brokenBrokenString.Length > 1)                                  //Some .obj files skip UV and normal
                            {
                                if (brokenBrokenString[1] != "")                                    //Some .obj files skip the uv and not the normal
                                {
                                    temp.y = System.Convert.ToInt32(brokenBrokenString[1]);
                                }
                                temp.z = System.Convert.ToInt32(brokenBrokenString[2]);
                            }
                            j++;

                            mesh.faceData[f2] = temp;
                            intArray.Add(f2);
                            f2++;
                        }
                        j = 1;
                        while (j + 2 < brokenString.Length)     //Create triangles out of the face data.  There will generally be more than 1 triangle per face.
                        {
                            mesh.triangles[f] = intArray[0];
                            f++;
                            mesh.triangles[f] = intArray[j];
                            f++;
                            mesh.triangles[f] = intArray[j+1];
                            f++;

                            j++;
                        }
                        break;
                    }
                    currentText = reader.ReadLine();
                    if (currentText != null)
                    {
                        currentText = currentText.Replace("  ", " ");       //Some .obj files insert double spaces, this removes them.
                    }
                }
            }
        }
        UpdateProgressBar();
    }

    void OnGUI()
    {
        //GUI.Label (new Rect (20, 20, 100, 100), progressPercentage.ToString());
        GUI.DrawTexture(new Rect(100, 100, 100, 20), barBG); 
        GUI.DrawTexture(new Rect(100, 100, progressPercentage, 20), barLoad);
    }
}

加载模型时,进度条应该会平稳运行。 但是,由于加载了模型,Unity 挂起,您实际上看不到进度条的进度。 任何人都知道如何延迟进度条的绘制,以便看到它。

【问题讨论】:

    标签: c# unity3d unityscript


    【解决方案1】:

    Unity 挂起的原因是因为 Unity(大部分)在单线程上运行,这意味着 Update 中的 ImportFile 函数将在调用下一行代码之前完全完成,这将阻止 OnGUI 函数被调用,直到整个更新功能完成。

    解决这个问题的唯一方法是使用多线程,这在 Unity 中可能很困难,因为您无法在主线程之外访问任何 Unity 数据,因此您只能在单独的线程中访问您自己的数据。

    https://web.archive.org/web/20140702033426/http://unitygems.com/threads/

    看起来原来的网站已经关闭,但这确实很好地为我解释了 Unity 中的线程,并附带了一些示例代码和用例

    【讨论】:

      猜你喜欢
      • 2021-07-02
      • 1970-01-01
      • 2018-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多