private IEnumerator GetWWWFiles(string objFilePath, bool useMtl, Material standardMaterial, Material transparentMaterial, ObjData objData)
    {
        var www = new WWW(objFilePath);

        while (!www.isDone)
        {
            objData.SetProgress(www.progress * (useMtl? .5f : 1.0f));
            yield return(null);
        }
        if (www.error != null)
        {
            Debug.Log(www.error);
            objData.SetDone();
            yield break;
        }

        string objFile  = www.text;
        string filePath = "";
        Dictionary <string, Material> materials = null;

        if (useMtl)
        {
            string mtlFileName = GetMTLFileName(ref objFilePath, ref objFile, ref filePath);
            if (mtlFileName != "")
            {
                // Read in mtl file
                www = new WWW(filePath + mtlFileName);
                yield return(www);

                if (www.error != null)
                {
                    Debug.Log(www.error);
                    objData.SetDone();
                    yield break;
                }
                if (www.text != "")
                {
                    // Get textures and parse MTL file
                    var linesRef = new LinesRef();
                    var textures = new Dictionary <string, Texture2D>();
                    yield return(StartCoroutine(GetTexturesAsync(www.text, linesRef, filePath, textures, objData)));

                    materials = ParseMTL(linesRef.lines, standardMaterial, transparentMaterial, filePath, textures);
                    if (materials == null)
                    {
                        useMtl = false;
                    }
                }
            }
            else
            {
                useMtl = false;
            }
        }

        CreateObjects(ref objFile, useMtl, materials, standardMaterial, objData);
    }
    private IEnumerator GetTexturesAsync(string mtlFile, LinesRef linesRef, string filePath, Dictionary <string, Texture2D> textures, ObjData objData)
    {
        Texture2D diffuseTexture = null;

        string[] lines            = SplitLines(ref mtlFile);
        int      numberOfTextures = 0;

        // See how many textures there are (to use for progress)
        for (int i = 0; i < lines.Length; i++)
        {
            var line = lines[i];
            CleanLine(ref line);
            lines[i] = line;

            if (line.Length < 7 || line[0] == '#')
            {
                continue;
            }

            if (line.StartsWith("map_Kd") && filePath != "")
            {
                numberOfTextures++;
            }
        }

        float progress = .5f;

        for (int i = 0; i < lines.Length; i++)
        {
            if (lines[i].Length < 7 || lines[i][0] == '#')
            {
                continue;
            }

            // Get diffuse texture
            if (lines[i].StartsWith("map_Kd") && filePath != "")
            {
                var lineInfo = lines[i].Split(' ');
                if (lineInfo.Length > 1)
                {
                    var textureFilePath = filePath + lineInfo[1];
                    var www             = new WWW(textureFilePath);
                    while (!www.isDone)
                    {
                        objData.SetProgress(progress + (www.progress / numberOfTextures) * .5f);
                        yield return(null);
                    }
                    if (www.error != null)
                    {
                        Debug.Log(www.error);
                        objData.SetDone();
                        yield break;
                    }
                    progress      += (1.0f / numberOfTextures) * .5f;
                    diffuseTexture = new Texture2D(4, 4);
                    www.LoadImageIntoTexture(diffuseTexture);
                    textures[lineInfo[1]] = diffuseTexture;
                }
                continue;
            }
        }
        linesRef.lines = lines;
    }
    private GameObject[] CreateObjects(ref string objFile, bool useMtl, Dictionary <string, Material> materials, Material standardMaterial, ObjData objData)
    {
        // Set up obj file
        string[] fileLines = SplitLines(ref objFile);

        int totalVertices = 0;
        int totalUVs      = 0;
        int totalNormals  = 0;

        var foundF               = false;
        var foundGroupStart      = false;
        int firstFCount          = 0;
        int groupCount           = 0;
        var originalGroupIndices = new List <int>();
        int faceCount            = 0;

        maxPoints = Mathf.Clamp(maxPoints, 0, 65534);

        // Find number of groups in file; also find total number of vertices, normals, and uvs
        for (int i = 0; i < fileLines.Length; i++)
        {
            if (fileLines[i].Length < 2)
            {
                continue;
            }

            var lineStart = fileLines[i].Substring(0, 2).ToLower();
            if (lineStart == "f ")
            {
                if (!foundF)
                {
                    firstFCount = faceCount;
                }
                faceCount++;
                if (foundGroupStart && !foundF)
                {
                    groupCount++;
                    originalGroupIndices.Add(firstFCount);
                    foundGroupStart = false;
                }
                foundF = true;
            }
            else if (lineStart == "o " || lineStart == "g " || lineStart == "us")
            {
                foundGroupStart = true;
                foundF          = false;
            }
            else if (lineStart == "v ")
            {
                totalVertices++;
            }
            else if (lineStart == "vt")
            {
                totalUVs++;
            }
            else if (useSuppliedNormals && lineStart == "vn")
            {
                totalNormals++;
            }
        }

        if (totalVertices == 0)
        {
            Debug.LogError("No vertices found in file");
            return(null);
        }
        if (faceCount == 0)
        {
            Debug.LogError("No face data found in file");
            return(null);
        }

        originalGroupIndices.Add(-1);

        int verticesCount = 0;
        int uvsCount      = 0;
        int normalsCount  = 0;

        var objVertices        = new Vector3[totalVertices];
        var objUVs             = new Vector2[totalUVs];
        var objNormals         = new Vector3[totalNormals];
        var triData            = new List <string>();
        var quadWarning        = false;
        var polyWarning        = false;
        var objectNames        = new string[groupCount];
        var materialNames      = new string[groupCount];
        int index              = 0;
        var lineInfo           = new string[0];
        var groupIndices       = new int[groupCount + 1];
        int numberOfGroupsUsed = 0;

        faceCount  = 0;
        groupCount = 0;
        int mtlCount         = 0;
        int objectNamesCount = 0;

        try {
            while (index < fileLines.Length)
            {
                var line = fileLines[index++].TrimEnd();

                // Skip over comments and short lines
                if (line.Length < 3 || line[0] == '#')
                {
                    continue;
                }

                // Remove excess whitespace
                CleanLine(ref line);
                // Skip over short lines (again, in the off chance the above line made this line too short)
                if (line.Length < 3)
                {
                    continue;
                }

                // If line ends with "\" then combine with the next line, assuming there is one (should be, but just in case)
                while (line[line.Length - 1] == '\\' && index < fileLines.Length)
                {
                    line = line.Substring(0, line.Length - 1) + " " + fileLines[index++].TrimEnd();
                }

                var stringStart = line.Substring(0, 2).ToLower();
                // Get material name from usemtl line, plus object name if it doesn't have one from g or o lines
                if (stringStart == "us")
                {
                    if (useMtl && line.StartsWith("usemtl") && mtlCount++ == 0)
                    {
                        lineInfo = line.Split(' ');
                        if (lineInfo.Length > 1)
                        {
                            materialNames[groupCount] = lineInfo[1];
                            if (objectNamesCount++ == 0)
                            {
                                objectNames[groupCount] = lineInfo[1];
                            }
                        }
                    }
                }
                // Get object name
                else if ((stringStart == "g " || stringStart == "o ") && objectNamesCount++ == 0)
                {
                    objectNames[groupCount] = line.Substring(2, line.Length - 2);
                }
                // Read vertices
                else if (stringStart == "v ")
                {
                    lineInfo = line.Split(' ');
                    if (lineInfo.Length != 4)
                    {
                        throw new System.Exception("Incorrect number of points while trying to read vertices:\n" + line + "\n");
                    }
                    else
                    {
                        // Invert x value so it works properly in Unity (left-handed)
                        objVertices[verticesCount++] = new Vector3(-float.Parse(lineInfo[1]), float.Parse(lineInfo[2]), float.Parse(lineInfo[3]));
                    }
                }
                // Read UVs
                else if (stringStart == "vt")
                {
                    lineInfo = line.Split(' ');
                    if (lineInfo.Length > 4 || lineInfo.Length < 3)
                    {
                        throw new System.Exception("Incorrect number of points while trying to read UV data:\n" + line + "\n");
                    }
                    else
                    {
                        objUVs[uvsCount++] = new Vector2(float.Parse(lineInfo[1]), float.Parse(lineInfo[2]));
                    }
                }
                // Read normals
                else if (useSuppliedNormals && stringStart == "vn")
                {
                    lineInfo = line.Split(' ');
                    if (lineInfo.Length != 4)
                    {
                        throw new System.Exception("Incorrect number of points while trying to read normals:\n" + line + "\n");
                    }
                    else
                    {
                        // Invert x value so it works properly in Unity
                        objNormals[normalsCount++] = new Vector3(-float.Parse(lineInfo[1]), float.Parse(lineInfo[2]), float.Parse(lineInfo[3]));
                    }
                }
                // Read triangle face info
                else if (stringStart == "f ")
                {
                    lineInfo = line.Split(' ');
                    if (lineInfo.Length >= 4 && lineInfo.Length <= 5)
                    {
                        // If data is relative offset, dissect it and replace it with calculated absolute data
                        if (lineInfo[1].Substring(0, 1) == "-")
                        {
                            for (int i = 1; i < lineInfo.Length; i++)
                            {
                                var lineInfoParts = lineInfo[i].Split('/');
                                lineInfoParts[0] = (verticesCount - -int.Parse(lineInfoParts[0]) + 1).ToString();
                                if (lineInfoParts.Length > 1)
                                {
                                    if (lineInfoParts[1] != "")
                                    {
                                        lineInfoParts[1] = (uvsCount - -int.Parse(lineInfoParts[1]) + 1).ToString();
                                    }
                                    if (lineInfoParts.Length == 3)
                                    {
                                        lineInfoParts[2] = (normalsCount - -int.Parse(lineInfoParts[2]) + 1).ToString();
                                    }
                                }
                                lineInfo[i] = System.String.Join("/", lineInfoParts);
                            }
                        }
                        // Triangle
                        for (int i = 1; i < 4; i++)
                        {
                            triData.Add(lineInfo[i]);
                        }
                        // Quad -- split by adding another triangle
                        if (lineInfo.Length == 5)
                        {
                            quadWarning = true;
                            triData.Add(lineInfo[1]);
                            triData.Add(lineInfo[3]);
                            triData.Add(lineInfo[4]);
                        }
                    }
                    // Line describes polygon containing more than 4 or fewer than 3 points, which are not supported
                    else
                    {
                        polyWarning = true;
                    }
                    // Store index for face group start locations
                    if (++faceCount == originalGroupIndices[groupCount + 1])
                    {
                        groupIndices[++groupCount] = triData.Count;
                        mtlCount         = 0;
                        objectNamesCount = 0;
                    }
                }
            }
        }
        catch (System.Exception err) {
            Debug.Log(err.Message);
            return(null);
        }

        if (combineMultipleGroups && !useSubmeshesWhenCombining)
        {
            numberOfGroupsUsed = 1;
            groupIndices[1]    = triData.Count;
        }
        else
        {
            groupIndices[groupCount + 1] = triData.Count;
            numberOfGroupsUsed           = groupIndices.Length - 1;
        }

        // Parse vert/uv/normal index data from triangle face lines
        var triVerts    = new int[triData.Count];
        var triUVs      = new int[triData.Count];
        var triNorms    = new int[triData.Count];
        var lengthCount = 3;

        for (int i = 0; i < triData.Count; i++)
        {
            string triString = triData[i];
            lineInfo = triString.Split('/');

            triVerts[i] = int.Parse(lineInfo[0]) - 1;
            if (lineInfo.Length > 1)
            {
                if (lineInfo[1] != "")
                {
                    triUVs[i] = int.Parse(lineInfo[1]) - 1;
                }
                if (lineInfo.Length == lengthCount && useSuppliedNormals)
                {
                    triNorms[i] = int.Parse(lineInfo[2]) - 1;
                }
            }
        }

        var objVertList = new List <Vector3>(objVertices);

        if (totalUVs > 0)
        {
            SplitOnUVs(triData, triVerts, triUVs, objVertList, objUVs, objVertices, ref verticesCount);
        }

        // Warnings
        if (quadWarning && !suppressWarnings)
        {
            Debug.LogWarning("At least one object uses quads...automatic triangle conversion is being used, which may not produce best results");
        }
        if (polyWarning && !suppressWarnings)
        {
            Debug.LogWarning("Polygons which are not quads or triangles have been skipped");
        }
        if (totalUVs == 0 && !suppressWarnings)
        {
            Debug.LogWarning("At least one object does not seem to be UV mapped...any textures used will appear as a solid color");
        }
        if (totalNormals == 0 && !suppressWarnings)
        {
            Debug.LogWarning("No normal data found for at least one object...automatically computing normals instead");
        }

        // Errors
        if (totalVertices == 0 && triData.Count == 0)
        {
            Debug.LogError("No objects seem to be present...possibly the .obj file is damaged or could not be read");
            return(null);
        }
        else if (totalVertices == 0)
        {
            Debug.LogError("The .obj file does not contain any vertices");
            return(null);
        }
        else if (triData.Count == 0)
        {
            Debug.LogError("The .obj file does not contain any polygons");
            return(null);
        }

        // Set up GameObject array...only 1 object if combining groups
        var gameObjects = new GameObject[combineMultipleGroups? 1 : numberOfGroupsUsed];

        for (int i = 0; i < gameObjects.Length; i++)
        {
            gameObjects[i] = new GameObject(objectNames[i], typeof(MeshFilter), typeof(MeshRenderer));
        }

        // --------------------------------
        // Create meshes from the .obj data
        GameObject go   = null;
        Mesh       mesh = null;

        Vector3[] newVertices  = null;
        Vector2[] newUVs       = null;
        Vector3[] newNormals   = null;
        int[]     newTriangles = null;
        var       useSubmesh   = (combineMultipleGroups && useSubmeshesWhenCombining && numberOfGroupsUsed > 1)? true : false;

        Material[] newMaterials = null;
        if (useSubmesh)
        {
            newMaterials = new Material[numberOfGroupsUsed];
        }
        Material lastMaterial = null;

        for (int i = 0; i < numberOfGroupsUsed; i++)
        {
            if (!useSubmesh || (useSubmesh && i == 0))
            {
                go   = gameObjects[i];
                mesh = new Mesh();

                // Find the number of unique vertices used by this group, also used to map original vertices into 0..thisVertices.Count range
                var vertHash      = new Dictionary <int, int>();
                var thisVertices  = new List <Vector3>();
                int counter       = 0;
                int vertHashValue = 0;
                int triStart      = groupIndices[i];
                int triEnd        = groupIndices[i + 1];
                if (useSubmesh)
                {
                    triStart = groupIndices[0];
                    triEnd   = groupIndices[numberOfGroupsUsed];
                }

                for (int j = triStart; j < triEnd; j++)
                {
                    if (!vertHash.TryGetValue(triVerts[j], out vertHashValue))
                    {
                        vertHash[triVerts[j]] = counter++;
                        thisVertices.Add(objVertList[triVerts[j]]);
                    }
                }

                if (thisVertices.Count > maxPoints)
                {
                    Debug.LogError("The number of vertices in this object exceeds the maximum allowable limit of " + maxPoints);
                    return(null);
                }

                newVertices  = new Vector3[thisVertices.Count];
                newUVs       = new Vector2[thisVertices.Count];
                newNormals   = new Vector3[thisVertices.Count];
                newTriangles = new int[triEnd - triStart];

                // Copy .obj mesh data for vertices and triangles to arrays of the correct size
                if (scaleFactor == Vector3.one && objRotation == Vector3.zero && objPosition == Vector3.zero)
                {
                    for (int j = 0; j < thisVertices.Count; j++)
                    {
                        newVertices[j] = thisVertices[j];
                    }
                }
                else
                {
                    transform.eulerAngles = objRotation;
                    transform.position    = objPosition;
                    transform.localScale  = scaleFactor;
                    var thisMatrix = transform.localToWorldMatrix;
                    for (int j = 0; j < thisVertices.Count; j++)
                    {
                        newVertices[j] = thisMatrix.MultiplyPoint3x4(thisVertices[j]);
                    }
                    transform.position   = Vector3.zero;
                    transform.rotation   = Quaternion.identity;
                    transform.localScale = Vector3.one;
                }

                // Arrange UVs and normals so they match up with vertices
                if (uvsCount > 0 && normalsCount > 0 && useSuppliedNormals)
                {
                    for (int j = triStart; j < triEnd; j++)
                    {
                        newUVs[vertHash[triVerts[j]]] = objUVs[triUVs[j]];
                        // Needs to be normalized or lighting is whacked (especially with specular), and some apps don't output normalized normals
                        newNormals[vertHash[triVerts[j]]] = objNormals[triNorms[j]].normalized;
                    }
                }
                else
                {
                    // Arrange UVs so they match up with vertices
                    if (uvsCount > 0)
                    {
                        for (int j = triStart; j < triEnd; j++)
                        {
                            newUVs[vertHash[triVerts[j]]] = objUVs[triUVs[j]];
                        }
                    }
                    // Arrange normals so they match up with vertices
                    if (normalsCount > 0 && useSuppliedNormals)
                    {
                        for (int j = triStart; j < triEnd; j++)
                        {
                            newNormals[vertHash[triVerts[j]]] = objNormals[triNorms[j]];
                        }
                    }
                }

                // Since we flipped the normals, swap triangle points 2 & 3
                counter = 0;
                for (int j = triStart; j < triEnd; j += 3)
                {
                    newTriangles[counter]     = vertHash[triVerts[j]];
                    newTriangles[counter + 1] = vertHash[triVerts[j + 2]];
                    newTriangles[counter + 2] = vertHash[triVerts[j + 1]];
                    counter += 3;
                }

                mesh.vertices = newVertices;
                mesh.uv       = newUVs;

                if (useSuppliedNormals)
                {
                    mesh.normals = newNormals;
                }
                if (useSubmesh)
                {
                    mesh.subMeshCount = numberOfGroupsUsed;
                }
            }

            if (useSubmesh)
            {
                int thisLength    = groupIndices[i + 1] - groupIndices[i];
                var thisTriangles = new int[thisLength];
                System.Array.Copy(newTriangles, groupIndices[i], thisTriangles, 0, thisLength);
                mesh.SetTriangles(thisTriangles, i);
                if (materialNames[i] != null)
                {
                    if (useMtl && materials.ContainsKey(materialNames[i]))
                    {
                        newMaterials[i] = materials[materialNames[i]];
                        lastMaterial    = materials[materialNames[i]];
                    }
                }
                else if (lastMaterial != null)
                {
                    newMaterials[i] = lastMaterial;
                }
            }
            else
            {
                mesh.triangles = newTriangles;
            }

            // Stuff that's done for each object, or at the end if using submeshes
            if (!useSubmesh || (useSubmesh && i == numberOfGroupsUsed - 1))
            {
                if (normalsCount == 0 || !useSuppliedNormals)
                {
                    mesh.RecalculateNormals();
                    if (computeTangents)
                    {
                        newNormals = mesh.normals;
                    }
                }
                if (computeTangents)
                {
                    var newTangents = new Vector4[newVertices.Length];
                    CalculateTangents(newVertices, newNormals, newUVs, newTriangles, newTangents);
                    mesh.tangents = newTangents;
                }

                mesh.RecalculateBounds();
                go.GetComponent <MeshFilter>().mesh = mesh;
                if (!useSubmesh)
                {
                    if (useMtl && materialNames[i] != null && materials.ContainsKey(materialNames[i]))
                    {
                        go.GetComponent <Renderer>().material = materials[materialNames[i]];
                    }
                    else
                    {
                        go.GetComponent <Renderer>().material = standardMaterial;
                    }
                }
                else
                {
                    for (int j = 0; j < newMaterials.Length; j++)
                    {
                        if (newMaterials[j] == null)
                        {
                            newMaterials[j] = standardMaterial;
                        }
                    }
                    go.GetComponent <Renderer>().materials = newMaterials;
                }
            }
        }

        if (objData != null)
        {
            objData.SetDone();
            objData.gameObjects = gameObjects;
            return(null);
        }

        return(gameObjects);
    }
예제 #4
0
파일: ObjReader.cs 프로젝트: ADuc/Dress
    private IEnumerator GetWWWFiles(string objFilePath, bool useMtl, Material standardMaterial, Material transparentMaterial, ObjData objData)
    {
        var www = new WWW(objFilePath);
        while (!www.isDone) {
            objData.SetProgress (www.progress * (useMtl? .5f : 1.0f));
            if (objData.cancel) {
                yield break;
            }
            yield return null;
        }
        if (www.error != null) {
            Debug.LogError ("Error loading " + objFilePath + ": " + www.error);
            objData.SetDone();
            yield break;
        }

        string objFile = www.text;
        string filePath = "";
        Dictionary<string, Material> materials = null;

        if (useMtl) {
            string mtlFileName = GetMTLFileName (ref objFilePath, ref objFile, ref filePath);
            if (mtlFileName != "") {
                // Read in mtl file
                www = new WWW(filePath + mtlFileName);
                while (!www.isDone) {
                    if (objData.cancel) {
                        yield break;
                    }
                    yield return null;
                }
                if (www.error != null) {
                    if (!useMTLFallback) {
                        Debug.LogError ("Error loading " + (filePath + mtlFileName) + ": " + www.error);
                        objData.SetDone();
                        yield break;
                    }
                    else {
                        useMtl = false;
                    }
                }
                if (useMtl && www.text != "") {
                    // Get textures and parse MTL file
                    var linesRef = new LinesRef();
                    var textures = new Dictionary<string, Texture2D>();
                    var loadError = new BoolRef(false);
                    yield return StartCoroutine (GetTexturesAsync (www.text, linesRef, filePath, textures, objData, loadError));
                    if (loadError.b == true) {
                        yield break;
                    }
                    materials = ParseMTL (linesRef.lines, standardMaterial, transparentMaterial, filePath, textures);
                    if (materials == null) {
                        useMtl = false;
                    }
                }
            }
            else {
                useMtl = false;
            }
        }

        CreateObjects (ref objFile, useMtl, materials, standardMaterial, objData, Path.GetFileNameWithoutExtension (objFilePath));
    }
예제 #5
0
파일: ObjReader.cs 프로젝트: ADuc/Dress
    private IEnumerator GetTexturesAsync(string mtlFile, LinesRef linesRef, string filePath, Dictionary<string, Texture2D> textures, ObjData objData, BoolRef loadError)
    {
        Texture2D diffuseTexture = null;
        string[] lines = mtlFile.Split ('\n');

        int numberOfTextures = 0;

        // See how many textures there are (to use for progress)
        for (int i = 0; i < lines.Length; i++) {
            var line = lines[i];
            CleanLine (ref line);
            lines[i] = line;

            if (line.Length < 7 || line[0] == '#') {
                continue;
            }

            if (IsTextureLine (line) && filePath != "") {
                numberOfTextures++;
            }
        }

        float progress = .5f;
        for (int i = 0; i < lines.Length; i++) {
            if (lines[i].Length < 7 || lines[i][0] == '#') {
                continue;
            }

            // Get diffuse/bump texture
            if (IsTextureLine (lines[i]) && filePath != "") {
                var textureFilePath = GetFileName (lines[i], GetToken (lines[i]));
                if (textureFilePath != "") {
                    var completeFilePath = filePath + textureFilePath;
                    var www = new WWW(completeFilePath);
                    while (!www.isDone) {
                        objData.SetProgress (progress + (www.progress / numberOfTextures) * .5f);
                        if (objData.cancel) {
                            loadError.b = true;
                            yield break;
                        }
                        yield return null;
                    }
                    if (www.error != null) {
                        Debug.LogError ("Error loading " + completeFilePath + ": " + www.error);
                        loadError.b = true;
                        objData.SetDone();
                        yield break;
                    }
                    progress += (1.0f / numberOfTextures) * .5f;
                    diffuseTexture = new Texture2D (4, 4);
                    www.LoadImageIntoTexture (diffuseTexture);
                    if (lines[i].StartsWith ("map_bump") || lines[i].StartsWith ("bump")) {
                        ConvertToNormalmap (diffuseTexture);
                    }
                    textures[textureFilePath] = diffuseTexture;
                }
            }
        }
        linesRef.lines = lines;
    }
예제 #6
0
파일: ObjReader.cs 프로젝트: ADuc/Dress
    private GameObject[] CreateObjects(ref string objFile, bool useMtl, Dictionary<string, Material> materials, Material standardMaterial, ObjData objData, string fileName)
    {
        // Set up obj file
        string[] fileLines = objFile.Split ('\n');

        int totalVertices = 0;
        int totalUVs = 0;
        int totalNormals = 0;

        var foundF = false;
        var foundGroupStart = false;
        int firstFCount = 0;
        int groupCount = 0;
        var originalGroupIndices = new List<int>();
        int faceCount = 0;
        maxPoints = Mathf.Clamp (maxPoints, 0, 65534);

        // Find number of groups in file; also find total number of vertices, normals, and uvs
        for (int i = 0; i < fileLines.Length; i++) {
            if (fileLines[i].Length < 2) continue;

            char char1 = System.Char.ToLower(fileLines[i][0]);
            char char2 = System.Char.ToLower(fileLines[i][1]);
            if (char1 == 'f' && char2 == ' ') {
                if (!foundF) {
                    firstFCount = faceCount;
                }
                faceCount++;
                if (foundGroupStart && !foundF) {
                    groupCount++;
                    originalGroupIndices.Add (firstFCount);
                    foundGroupStart = false;
                }
                foundF = true;
            }
            else if ((char1 == 'o' && char2 == ' ') || (char1 == 'g' && char2 == ' ') || (char1 == 'u' && char2 == 's')) {	// "us" == "usemtl"
                foundGroupStart = true;
                foundF = false;
            }
            else if (char1 == 'v' && char2 == ' ') {
                totalVertices++;
            }
            else if (char1 == 'v' && char2 == 't') {
                totalUVs++;
            }
            else if (useSuppliedNormals && char1 == 'v' && char2 == 'n') {
                totalNormals++;
            }
        }

        if (groupCount == 0) {
            originalGroupIndices.Add (firstFCount);
            groupCount = 1;
        }

        if (totalVertices == 0) {
            Debug.LogError ("No vertices found in file");
            return null;
        }
        if (faceCount == 0) {
            Debug.LogError ("No face data found in file");
            return null;
        }

        originalGroupIndices.Add (-1);

        int verticesCount = 0;
        int uvsCount = 0;
        int normalsCount = 0;

        var objVertices = new Vector3[totalVertices];
        var objUVs = new Vector2[totalUVs];
        var objNormals = new Vector3[totalNormals];
        var triData = new List<string>();
        var quadWarning = false;
        var polyWarning = false;
        var objectNames = new string[groupCount];
        var materialNames = new string[groupCount];
        int index = 0;
        var lineInfo = new string[0];
        var groupIndices = new int[groupCount+1];
        int numberOfGroupsUsed = 0;
        faceCount = 0;
        groupCount = 0;
        int mtlCount = 0;
        int objectNamesCount = 0;

        try {
            while (index < fileLines.Length) {
                var line = fileLines[index++];

                // Skip over comments and short lines
                if (line.Length < 3 || line[0] == '#') continue;

                // Remove excess whitespace
                CleanLine (ref line);
                // Skip over short lines (again, in the off chance the above line made this line too short)
                if (line.Length < 3) continue;

                // If line ends with "\" then combine with the next line, assuming there is one (should be, but just in case)
                while (line[line.Length-1] == '\\' && index < fileLines.Length) {
                    line = line.Substring (0, line.Length-1) + " " + fileLines[index++].TrimEnd();
                    CleanLine (ref line);
                }

                char char1 = System.Char.ToLower(line[0]);
                char char2 = System.Char.ToLower(line[1]);
                // Get material name from usemtl line, plus object name if it doesn't have one from g or o lines
                if (char1 == 'u' && char2 == 's') {
                    if (useMtl && line.StartsWith ("usemtl") && mtlCount++ == 0) {
                        lineInfo = line.Split (' ');
                        if (lineInfo.Length > 1) {
                            materialNames[groupCount] = lineInfo[1];
                            if (objectNamesCount++ == 0) {
                                if (useFileNameAsObjectName && fileName != "") {
                                    objectNames[groupCount] = fileName;
                                }
                                else {
                                    objectNames[groupCount] = lineInfo[1];
                                }
                            }
                        }
                    }
                }
                // Get object name
                else if (((char1 == 'o' && char2 == ' ') || (char1 == 'g' && char2 == ' ')) && objectNamesCount++ == 0) {
                    if (useFileNameAsObjectName && fileName != "") {
                        objectNames[groupCount] = fileName;
                    }
                    else {
                        objectNames[groupCount] = line.Substring (2, line.Length-2);
                    }
                }
                // Read vertices
                else if (char1 == 'v' && char2 == ' ') {
                    lineInfo = line.Split (' ');
                    if (lineInfo.Length != 4) {
                        throw new System.Exception ("Incorrect number of points while trying to read vertices:\n" + line + "\n");
                    }
                    else {
                        // Invert x value so it works properly in Unity (left-handed)
                        objVertices[verticesCount++] = new Vector3(-float.Parse (lineInfo[1], CultureInfo.InvariantCulture), float.Parse (lineInfo[2], CultureInfo.InvariantCulture), float.Parse (lineInfo[3], CultureInfo.InvariantCulture));
                    }
                }
                // Read UVs
                else if (char1 == 'v' && char2 == 't') {
                    lineInfo = line.Split (' ');
                    if (lineInfo.Length > 4 || lineInfo.Length < 3) {
                        throw new System.Exception ("Incorrect number of points while trying to read UV data:\n" + line + "\n");
                    }
                    else {
                        objUVs[uvsCount++] = new Vector2(float.Parse (lineInfo[1], CultureInfo.InvariantCulture), float.Parse (lineInfo[2], CultureInfo.InvariantCulture));
                    }
                }
                // Read normals
                else if (useSuppliedNormals && char1 == 'v' && char2 == 'n') {
                    lineInfo = line.Split (' ');
                    if (lineInfo.Length != 4) {
                        throw new System.Exception ("Incorrect number of points while trying to read normals:\n" + line + "\n");
                    }
                    else {
                        // Invert x value so it works properly in Unity
                        objNormals[normalsCount++] = new Vector3(-float.Parse (lineInfo[1], CultureInfo.InvariantCulture), float.Parse (lineInfo[2], CultureInfo.InvariantCulture), float.Parse (lineInfo[3], CultureInfo.InvariantCulture));
                    }
                }
                // Read triangle face info
                else if (char1 == 'f' && char2 == ' ') {
                    lineInfo = line.Split (' ');
                    if (lineInfo.Length >= 4 && lineInfo.Length <= 5) {
                        // If data is relative offset, dissect it and replace it with calculated absolute data
                        if (lineInfo[1].Substring (0, 1) == "-") {
                            for (int i = 1; i < lineInfo.Length; i++) {
                                var lineInfoParts = lineInfo[i].Split ('/');
                                lineInfoParts[0] = (verticesCount - -int.Parse (lineInfoParts[0])+1).ToString();
                                if (lineInfoParts.Length > 1) {
                                    if (lineInfoParts[1] != "") {
                                        lineInfoParts[1] = (uvsCount - -int.Parse (lineInfoParts[1])+1).ToString();
                                    }
                                    if (lineInfoParts.Length == 3) {
                                        lineInfoParts[2] = (normalsCount - -int.Parse (lineInfoParts[2])+1).ToString();
                                    }
                                }
                                lineInfo[i] = System.String.Join ("/", lineInfoParts);
                            }
                        }
                        // Triangle
                        for (int i = 1; i < 4; i++) {
                            triData.Add (lineInfo[i]);
                        }
                        // Quad -- split by adding another triangle
                        if (lineInfo.Length == 5) {
                            quadWarning = true;
                            triData.Add (lineInfo[1]);
                            triData.Add (lineInfo[3]);
                            triData.Add (lineInfo[4]);
                        }
                    }
                    // Line describes polygon containing more than 4 or fewer than 3 points, which are not supported
                    else {
                        polyWarning = true;
                    }
                    // Store index for face group start locations
                    if (++faceCount == originalGroupIndices[groupCount+1]) {
                        groupIndices[++groupCount] = triData.Count;
                        mtlCount = 0;
                        objectNamesCount = 0;
                    }
                }
            }
        }
        catch (System.Exception err) {
            GameObject.Find("Canvas").transform.FindChild("PanelPopupLoad").gameObject.SetActive(false);
            Debug.LogError (err.Message);
            return null;
        }

        if (combineMultipleGroups && !useSubmeshesWhenCombining) {
            numberOfGroupsUsed = 1;
            groupIndices[1] = triData.Count;
        }
        else {
            groupIndices[groupCount+1] = triData.Count;
            numberOfGroupsUsed = groupIndices.Length-1;
        }

        // Parse vert/uv/normal index data from triangle face lines
        var triVerts = new int[triData.Count];
        var triUVs = new int[triData.Count];
        var triNorms = new int[triData.Count];
        var lengthCount = 3;
        for (int i = 0; i < triData.Count; i++) {
            string triString = triData[i];
            lineInfo = triString.Split ('/');

            triVerts[i] = int.Parse (lineInfo[0])-1;
            if (lineInfo.Length > 1) {
                if (lineInfo[1] != "") {
                    triUVs[i] = int.Parse (lineInfo[1])-1;
                }
                if (lineInfo.Length == lengthCount && useSuppliedNormals) {
                    triNorms[i] = int.Parse (lineInfo[2])-1;
                }
            }
        }

        var objVertList = new List<Vector3>(objVertices);
        if (totalUVs > 0) {
            SplitOnUVs (triData, triVerts, triUVs, objVertList, objUVs, objVertices, ref verticesCount);
        }

        // Warnings
        if (quadWarning && !suppressWarnings) {
            Debug.LogWarning ("At least one object uses quads...automatic triangle conversion is being used, which may not produce best results");
        }
        if (polyWarning && !suppressWarnings) {
            Debug.LogWarning ("Polygons which are not quads or triangles have been skipped");
        }
        if (totalUVs == 0 && !suppressWarnings) {
            Debug.LogWarning ("At least one object does not seem to be UV mapped...any textures used will appear as a solid color");
        }
        if (totalNormals == 0 && !suppressWarnings) {
            Debug.LogWarning ("No normal data found for at least one object...automatically computing normals instead");
        }

        // Errors
        if (totalVertices == 0 && triData.Count == 0) {
            Debug.LogError ("No objects seem to be present...possibly the .obj file is damaged or could not be read");
            return null;
        }
        else if (totalVertices == 0) {
            Debug.LogError ("The .obj file does not contain any vertices");
            return null;
        }
        else if (triData.Count == 0) {
            Debug.LogError ("The .obj file does not contain any polygons");
            return null;
        }

        // Set up GameObject array...only 1 object if combining groups
        var gameObjects = new GameObject[combineMultipleGroups? 1 : numberOfGroupsUsed];
        for (int i = 0; i < gameObjects.Length; i++) {
            gameObjects[i] = new GameObject(objectNames[i], typeof(MeshFilter), typeof(MeshRenderer));
        }

        // --------------------------------
        // Create meshes from the .obj data
        GameObject go = null;
        Mesh mesh = null;
        Vector3[] newVertices = null;
        Vector2[] newUVs = null;
        Vector3[] newNormals = null;
        int[] newTriangles = null;
        var useSubmesh = (combineMultipleGroups && useSubmeshesWhenCombining && numberOfGroupsUsed > 1)? true : false;
        Material[] newMaterials = null;
        if (useSubmesh) {
            newMaterials = new Material[numberOfGroupsUsed];
        }
        int lastUsedMaterialIndex = 0;
        bool hasUsedMaterial = false;

        for (int i = 0; i < numberOfGroupsUsed; i++) {
            if (!useSubmesh || (useSubmesh && i == 0)) {
                go = gameObjects[i];
                mesh = new Mesh();

                // Find the number of unique vertices used by this group, also used to map original vertices into 0..thisVertices.Count range
                var vertHash = new Dictionary<int, int>();
                var thisVertices = new List<Vector3>();
                int counter = 0;
                int vertHashValue = 0;
                int triStart = groupIndices[i];
                int triEnd = groupIndices[i + 1];
                if (useSubmesh) {
                    triStart = groupIndices[0];
                    triEnd = groupIndices[numberOfGroupsUsed];
                }

                for (int j = triStart; j < triEnd; j++) {
                    if (!vertHash.TryGetValue (triVerts[j], out vertHashValue)) {
                        vertHash[triVerts[j]] = counter++;
                        thisVertices.Add (objVertList[triVerts[j]]);
                    }
                }

                if (thisVertices.Count > maxPoints) {
                    Debug.LogError ("The number of vertices in the object " + objectNames[i] + " exceeds the maximum allowable limit of " + maxPoints);
                    return null;
                }

                newVertices = new Vector3[thisVertices.Count];
                newUVs = new Vector2[thisVertices.Count];
                newNormals = new Vector3[thisVertices.Count];
                newTriangles = new int[triEnd - triStart];

                // Copy .obj mesh data for vertices and triangles to arrays of the correct size
                if (scaleFactor == Vector3.one && objRotation == Vector3.zero && objPosition == Vector3.zero) {
                    for (int j = 0; j < thisVertices.Count; j++) {
                        newVertices[j] = thisVertices[j];
                    }
                }
                else {
                    transform.eulerAngles = objRotation;
                    transform.position = objPosition;
                    transform.localScale = scaleFactor;
                    var thisMatrix = transform.localToWorldMatrix;
                    for (int j = 0; j < thisVertices.Count; j++) {
                        newVertices[j] = thisMatrix.MultiplyPoint3x4 (thisVertices[j]);
                    }
                    transform.position = Vector3.zero;
                    transform.rotation = Quaternion.identity;
                    transform.localScale = Vector3.one;
                }

                // Arrange UVs and normals so they match up with vertices
                if (uvsCount > 0 && normalsCount > 0 && useSuppliedNormals) {
                    for (int j = triStart; j < triEnd; j++) {
                        newUVs[vertHash[triVerts[j]]] = objUVs[triUVs[j]];
                        // Needs to be normalized or lighting is whacked (especially with specular), and some apps don't output normalized normals
                        newNormals[vertHash[triVerts[j]]] = objNormals[triNorms[j]].normalized;
                    }
                }
                else {
                    // Arrange UVs so they match up with vertices
                    if (uvsCount > 0) {
                        for (int j = triStart; j < triEnd; j++) {
                            newUVs[vertHash[triVerts[j]]] = objUVs[triUVs[j]];
                        }
                    }
                    // Arrange normals so they match up with vertices
                    if (normalsCount > 0 && useSuppliedNormals) {
                        for (int j = triStart; j < triEnd; j++) {
                            newNormals[vertHash[triVerts[j]]] = objNormals[triNorms[j]];
                        }
                    }
                }

                // Since we flipped the normals, swap triangle points 2 & 3
                counter = 0;
                for (int j = triStart; j < triEnd; j += 3) {
                    newTriangles[counter  ] = vertHash[triVerts[j  ]];
                    newTriangles[counter+1] = vertHash[triVerts[j+2]];
                    newTriangles[counter+2] = vertHash[triVerts[j+1]];
                    counter += 3;
                }

                mesh.vertices = newVertices;
                mesh.uv = newUVs;

                if (autoCenterOnOrigin) {
                    var offset = mesh.bounds.center;
                    int end = newVertices.Length;
                    for (int j = 0; j < end; j++) {
                        newVertices[j] -= offset;
                    }
                    mesh.vertices = newVertices;
                }

                if (useSuppliedNormals) {
                    mesh.normals = newNormals;
                }
                if (useSubmesh) {
                    mesh.subMeshCount = numberOfGroupsUsed;
                }
            }

            if (useSubmesh) {
                int thisLength = groupIndices[i + 1] - groupIndices[i];
                var thisTriangles = new int[thisLength];
                System.Array.Copy (newTriangles, groupIndices[i], thisTriangles, 0, thisLength);
                mesh.SetTriangles (thisTriangles, i);
                if (materialNames[i] != null) {
                    if (useMtl && materials.ContainsKey (materialNames[i])) {
                        newMaterials[i] = materials[materialNames[i]];
                        if (materials[materialNames[i]]) {

                        }
                        hasUsedMaterial = true;
                        lastUsedMaterialIndex = i;
                    }
                }
                else {
                    if (hasUsedMaterial) {
                        newMaterials[i] = materials[materialNames[lastUsedMaterialIndex]];
                    }
                    else {
                        newMaterials[i] = standardMaterial;
                    }
                }
            }
            else {
                mesh.triangles = newTriangles;
            }

            // Stuff that's done for each object, or at the end if using submeshes
            if (!useSubmesh || (useSubmesh && i == numberOfGroupsUsed-1) ) {
                if (normalsCount == 0 || !useSuppliedNormals) {
                    mesh.RecalculateNormals();
                    if (computeTangents) {
                        newNormals = mesh.normals;
                    }
                }
                if (computeTangents) {
                    var newTangents = new Vector4[newVertices.Length];
                    CalculateTangents (newVertices, newNormals, newUVs, newTriangles, newTangents);
                    mesh.tangents = newTangents;
                }

                mesh.RecalculateBounds();
                go.GetComponent<MeshFilter>().mesh = mesh;
                if (!useSubmesh) {
                    if (materialNames[i] != null) {
                        if (useMtl && materials.ContainsKey (materialNames[i])) {
                            go.GetComponent<Renderer>().material = materials[materialNames[i]];
                            hasUsedMaterial = true;
                            lastUsedMaterialIndex = i;
                        }
                    }
                    else {
                        if (hasUsedMaterial) {
                            go.GetComponent<Renderer>().material = materials[materialNames[lastUsedMaterialIndex]];
                        }
                        else {
                            go.GetComponent<Renderer>().material = standardMaterial;
                        }
                    }
                }
                else {
                    go.GetComponent<Renderer>().materials = newMaterials;
                }
            }
        }

        if (objData != null) {
            objData.SetDone();
            objData.gameObjects = gameObjects;
            return null;
        }

        return gameObjects;
    }
예제 #7
0
    private IEnumerator GetWWWFiles(string objFilePath, bool useMtl, Material standardMaterial, Material transparentMaterial, ObjData objData)
    {
        var www = new WWW(objFilePath);
        while (!www.isDone) {
            objData.SetProgress (www.progress * (useMtl? .5f : 1.0f));
            yield return null;
        }
        if (www.error != null) {
            Debug.Log (www.error);
            objData.SetDone();
            yield break;
        }

        string objFile = www.text;
        string filePath = "";
        Dictionary<string, Material> materials = null;

        if (useMtl) {
            string mtlFileName = GetMTLFileName (ref objFilePath, ref objFile, ref filePath);
            if (mtlFileName != "") {
                // Read in mtl file
                www = new WWW(filePath + mtlFileName);
                yield return www;
                if (www.error != null) {
                    Debug.Log (www.error);
                    objData.SetDone();
                    yield break;
                }
                if (www.text != "") {
                    // Get textures and parse MTL file
                    var linesRef = new LinesRef();
                    var textures = new Dictionary<string, Texture2D>();
                    yield return StartCoroutine (GetTexturesAsync (www.text, linesRef, filePath, textures, objData));
                    materials = ParseMTL (linesRef.lines, standardMaterial, transparentMaterial, filePath, textures);
                    if (materials == null) {
                        useMtl = false;
                    }
                }
            }
            else {
                useMtl = false;
            }
        }

        CreateObjects (ref objFile, useMtl, materials, standardMaterial, objData);
    }
예제 #8
0
    private IEnumerator GetTexturesAsync(string mtlFile, LinesRef linesRef, string filePath, Dictionary<string, Texture2D> textures, ObjData objData)
    {
        Texture2D diffuseTexture = null;
        string[] lines = SplitLines (ref mtlFile);
        int numberOfTextures = 0;

        // See how many textures there are (to use for progress)
        for (int i = 0; i < lines.Length; i++) {
            var line = lines[i];
            CleanLine (ref line);
            lines[i] = line;

            if (line.Length < 7 || line[0] == '#') {
                continue;
            }

            if (line.StartsWith ("map_Kd") && filePath != "") {
                numberOfTextures++;
            }
        }

        float progress = .5f;
        for (int i = 0; i < lines.Length; i++) {
            if (lines[i].Length < 7 || lines[i][0] == '#') {
                continue;
            }

            // Get diffuse texture
            if (lines[i].StartsWith ("map_Kd") && filePath != "") {
                var lineInfo = lines[i].Split (' ');
                if (lineInfo.Length > 1) {
                    var textureFilePath = filePath + lineInfo[1];
                    var www = new WWW(textureFilePath);
                    while (!www.isDone) {
                        objData.SetProgress (progress + (www.progress / numberOfTextures) * .5f);
                        yield return null;
                    }
                    if (www.error != null) {
                        Debug.Log (www.error);
                        objData.SetDone();
                        yield break;
                    }
                    progress += (1.0f / numberOfTextures) * .5f;
                    diffuseTexture = new Texture2D (4, 4);
                    www.LoadImageIntoTexture (diffuseTexture);
                    textures[lineInfo[1]] = diffuseTexture;
                }
                continue;
            }
        }
        linesRef.lines = lines;
    }