示例#1
0
        /// <summary>
        /// Parses one object from input .obj file.
        /// </summary>
        /// <param name="reader">Reader with current position in .obj file.</param>
        /// <returns>
        /// Triangle mesh with name of the associated material.
        /// If material name is an empty string, no material was used.
        /// </returns>
        private Tuple <string, FastTriangleMesh> parseObject(StreamReader reader, ref int verticesCount, ref int txtCoordsCount, ref int normalsCount)
        {
            SceneBrep scene        = new SceneBrep();
            string    materialName = "";

            int v0         = scene.Vertices;
            int lastVertex = v0 - 1;

            int faces = 0;

            List <Vector2> txtCoords    = new List <Vector2>(256);
            List <Vector3> normals      = new List <Vector3>(256);
            int            lastTxtCoord = -1;
            int            lastNormal   = -1;

            int[] f = new int[3];

            while (!reader.EndOfStream)
            {
                // Check if there is defined "o" tag, if yes, it is the end of definition of one object
                // and return this object.
                if ((char)reader.Peek() == 'o')
                {
                    break;
                }

                string   line   = reader.ReadLine();
                string[] tokens = line.Split();
                if (tokens.Length == 0)
                {
                    continue;
                }
                switch (tokens[0])
                {
                case "v":
                    if (tokens.Length != 4)
                    {
                        throw new Exception("Incorrect .obj file.");
                    }

                    // Add vertex.
                    float x, y, z;
                    if (!float.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out x) ||
                        !float.TryParse(tokens[2], NumberStyles.Float, CultureInfo.InvariantCulture, out y) ||
                        !float.TryParse(tokens[3], NumberStyles.Float, CultureInfo.InvariantCulture, out z))
                    {
                        throw new Exception("Incorrect .obj file.");
                    }

                    lastVertex = scene.AddVertex(new Vector3(x, y, z));
                    break;

                case "vt":
                    if (tokens.Length != 3)
                    {
                        throw new Exception("Incorrect .obj file.");
                    }

                    // Add vertex.
                    float u, v;
                    if (!float.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out u) ||
                        !float.TryParse(tokens[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v))
                    {
                        throw new Exception("Incorrect .obj file.");
                    }

                    txtCoords.Add(new Vector2(u, v));
                    ++lastTxtCoord;
                    break;

                case "vn":
                    if (tokens.Length != 4)
                    {
                        throw new Exception("Incorrect .obj file.");
                    }

                    // Add vertex.
                    float nx, ny, nz;
                    if (!float.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out nx) ||
                        !float.TryParse(tokens[2], NumberStyles.Float, CultureInfo.InvariantCulture, out ny) ||
                        !float.TryParse(tokens[3], NumberStyles.Float, CultureInfo.InvariantCulture, out nz))
                    {
                        throw new Exception("Incorrect .obj file.");
                    }

                    normals.Add(new Vector3(nx, ny, nz));
                    break;

                case "usemtl":
                    // Set name of the material used for this object.
                    if (tokens.Length != 2)
                    {
                        throw new Exception("Incorrect .obj file.");
                    }
                    materialName = tokens[1];
                    break;

                case "f":
                    // Face must be formed by at least three vertices.
                    if (tokens.Length < 4)
                    {
                        continue;
                    }

                    // Number of vertices.
                    int N = tokens.Length - 1;
                    // Reuse same array for each face and resize it if needed.
                    if (f.Length < N)
                    {
                        f = new int[N];
                    }
                    // Shrink it if less vertices is used.
                    if (N < f.Length)
                    {
                        f = new int[N];
                    }

                    int i;

                    for (i = 0; i < N; i++) // read indices for one vertex
                    {
                        string[] vt = tokens[i + 1].Split('/');
                        int      ti, ni;
                        ti = ni = 0; // 0 => value not present

                        // 0 .. vertex coord index
                        if (!int.TryParse(vt[0], out f[i]) ||
                            f[i] == 0)
                        {
                            break;
                        }

                        if (f[i] > 0)
                        {
                            f[i] = v0 + f[i] - 1 - verticesCount;
                        }
                        else
                        {
                            f[i] = lastVertex + 1 - f[i];
                        }

                        if (vt.Length > 1)
                        {
                            // 1 .. texture coord index (not yet)
                            if (!int.TryParse(vt[1], out ti))
                            {
                                ti = 0;
                            }

                            if (vt.Length > 2)
                            {
                                // 2 .. normal vector index
                                if (!int.TryParse(vt[2], out ni))
                                {
                                    ni = 0;
                                }
                            }
                        }

                        // there was a texture coord..
                        if (ti != 0)
                        {
                            if (ti > 0)
                            {
                                ti = ti - txtCoordsCount - 1;
                            }
                            else
                            {
                                ti = lastTxtCoord + 1 - ti;
                            }
                            if (ti >= 0 && ti < txtCoords.Count)
                            {
                                scene.SetTxtCoord(f[i], txtCoords[ti]);
                            }
                        }

                        // there was a normal..
                        if (ni != 0)
                        {
                            if (ni > 0)
                            {
                                ni = ni - normalsCount - 1;
                            }
                            else
                            {
                                ni = lastNormal + 1 - ni;
                            }
                            if (ni >= 0 && ni < normals.Count)
                            {
                                scene.SetNormal(f[i], normals[ni]);
                            }
                        }
                    }

                    N = i;
                    for (i = 1; i < N - 1; i++)
                    {
                        scene.AddTriangle(f[0], f[i], f[i + 1]);
                        faces++;
                    }

                    break;
                }
            }

            // Update count of vertices, txt coords and normals.
            verticesCount  += scene.Vertices;
            txtCoordsCount += txtCoords.Count;
            normalsCount   += normals.Count;

            scene.BuildCornerTable();
            scene.BuildBoundingBox();

            return(new Tuple <string, FastTriangleMesh>(materialName, new FastTriangleMesh(scene)));
        }