Ejemplo n.º 1
0
        /// <summary>
        /// Load an OBJ file from a stream. No materials will be loaded, and will instead be supplemented by a blank white material.
        /// </summary>
        /// <param name="input">Input OBJ stream</param>
        /// <returns>Returns a GameObject represeting the OBJ file, with each imported object as a child.</returns>
        public GameObject Load(Stream input)
        {
            var inputReader = new StreamReader(input);
            var reader      = new StringReader(inputReader.ReadToEnd());

            Dictionary <string, OBJObjectBuilder> builderDict = new Dictionary <string, OBJObjectBuilder>();
            OBJObjectBuilder currentBuilder  = null;
            string           currentMaterial = "default";

            //lists for face data
            //prevents excess GC
            List <int> vertexIndices = new List <int>();
            List <int> normalIndices = new List <int>();
            List <int> uvIndices     = new List <int>();

            //helper func
            Action <string> setCurrentObjectFunc = (string objectName) =>
            {
                if (!builderDict.TryGetValue(objectName, out currentBuilder))
                {
                    currentBuilder          = new OBJObjectBuilder(objectName, this);
                    builderDict[objectName] = currentBuilder;
                }
            };

            //create default object
            setCurrentObjectFunc.Invoke("default");

            //do the reading
            for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
            {
                if (StringExtension.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                string   processedLine = line.Clean();
                string[] splitLine     = processedLine.Split(' ');

                //comment or blank
                if (processedLine[0] == '#' || splitLine.Length < 2)
                {
                    continue;
                }

                //load material library
                if (splitLine[0] == "mtllib" && Materials == null)
                {
                    string mtlLibPath = processedLine.Substring(7);
                    LoadMaterialLibrary(mtlLibPath);
                }

                //vtx
                if (splitLine[0] == "v")
                {
                    Vertices.Add(OBJLoaderHelper.VectorFromStrArray(splitLine));
                    continue;
                }

                //normal
                if (splitLine[0] == "vn")
                {
                    Normals.Add(OBJLoaderHelper.VectorFromStrArray(splitLine));
                    continue;
                }

                //uv
                if (splitLine[0] == "vt")
                {
                    UVs.Add(OBJLoaderHelper.VectorFromStrArray(splitLine));
                    continue;
                }

                //new material
                if (splitLine[0] == "usemtl")
                {
                    string materialName = processedLine.Substring(7);
                    currentMaterial = materialName;

                    if (SplitMode == SplitMode.Material)
                    {
                        setCurrentObjectFunc.Invoke(materialName);
                    }
                    continue;
                }

                //new object
                if ((splitLine[0] == "o" || splitLine[0] == "g") && SplitMode == SplitMode.Object)
                {
                    string objectName = processedLine.Substring(2);
                    setCurrentObjectFunc.Invoke(objectName);
                    continue;
                }

                //face data (the fun part)
                if (splitLine[0] == "f")
                {
                    //loop through indices
                    for (int i = 1; i < splitLine.Length; i++)
                    {
                        string faceLoop = splitLine[i];

                        int vertexIndex = int.MinValue;
                        int normalIndex = int.MinValue;
                        int uvIndex     = int.MinValue;

                        //parse face loop
                        if (faceLoop.Contains("//"))
                        {
                            //vertex and normal
                            string[] slashSplits = faceLoop.Split('/');
                            vertexIndex = OBJLoaderHelper.FastIntParse(slashSplits[0]);
                            normalIndex = OBJLoaderHelper.FastIntParse(slashSplits[2]);
                        }
                        else if (faceLoop.Contains("/"))
                        {
                            //get slash splits
                            string[] slashSplits = faceLoop.Split('/');
                            if (slashSplits.Length > 2)
                            {
                                //vertex, uv, and normal
                                vertexIndex = OBJLoaderHelper.FastIntParse(slashSplits[0]);
                                uvIndex     = OBJLoaderHelper.FastIntParse(slashSplits[1]);
                                normalIndex = OBJLoaderHelper.FastIntParse(slashSplits[2]);
                            }
                            else
                            {
                                //vertex, and uv
                                vertexIndex = OBJLoaderHelper.FastIntParse(slashSplits[0]);
                                uvIndex     = OBJLoaderHelper.FastIntParse(slashSplits[1]);
                            }
                        }
                        else
                        {
                            //just vertex index
                            vertexIndex = OBJLoaderHelper.FastIntParse(faceLoop);
                        }

                        //"postprocess" indices
                        if (vertexIndex > int.MinValue)
                        {
                            if (vertexIndex < 0)
                            {
                                vertexIndex = Vertices.Count - vertexIndex;
                            }
                            vertexIndex--;
                        }
                        if (normalIndex > int.MinValue)
                        {
                            if (normalIndex < 0)
                            {
                                normalIndex = Normals.Count - normalIndex;
                            }
                            normalIndex--;
                        }
                        if (uvIndex > int.MinValue)
                        {
                            if (uvIndex < 0)
                            {
                                uvIndex = UVs.Count - uvIndex;
                            }
                            uvIndex--;
                        }

                        //set array values
                        vertexIndices.Add(vertexIndex);
                        normalIndices.Add(normalIndex);
                        uvIndices.Add(uvIndex);
                    }

                    //push to builder
                    currentBuilder.PushFace(currentMaterial, vertexIndices, normalIndices, uvIndices);

                    //clear lists
                    vertexIndices.Clear();
                    normalIndices.Clear();
                    uvIndices.Clear();
                }
            }

            //finally, put it all together
            GameObject obj = new GameObject(_objInfo != null ? Path.GetFileNameWithoutExtension(_objInfo.Name) : "WavefrontObject");

            obj.transform.localScale = new Vector3(-1f, 1f, 1f);

            foreach (var builder in builderDict)
            {
                //empty object
                if (builder.Value.PushedFaceCount == 0)
                {
                    continue;
                }

                var builtObj = builder.Value.Build();
                builtObj.transform.SetParent(obj.transform, false);
            }

            return(obj);
        }
Ejemplo n.º 2
0
        public GameObject Build()
        {
            var go = new GameObject(_name);

            //add meshrenderer
            var mr      = go.AddComponent <MeshRenderer>();
            int submesh = 0;


            //locate the material for each submesh
            Material[] materialArray = new Material[_materialIndices.Count];
            foreach (var kvp in _materialIndices)
            {
                Material material = null;
                if (_loader.Materials == null)
                {
                    material      = OBJLoaderHelper.CreateNullMaterial();
                    material.name = kvp.Key;
                }
                else
                {
                    if (!_loader.Materials.TryGetValue(kvp.Key, out material))
                    {
                        material      = OBJLoaderHelper.CreateNullMaterial();
                        material.name = kvp.Key;
                        _loader.Materials[kvp.Key] = material;
                    }
                }
                materialArray[submesh] = material;
                submesh++;
            }
            mr.sharedMaterials = materialArray;

            //add meshfilter
            var mf = go.AddComponent <MeshFilter>();

            submesh = 0;

            var msh = new Mesh()
            {
                name         = _name,
                indexFormat  = (_vertices.Count > 65535) ? UnityEngine.Rendering.IndexFormat.UInt32 : UnityEngine.Rendering.IndexFormat.UInt16,
                subMeshCount = _materialIndices.Count
            };

            //set vertex data
            msh.SetVertices(_vertices);
            msh.SetNormals(_normals);
            msh.SetUVs(0, _uvs);

            //set faces
            foreach (var kvp in _materialIndices)
            {
                msh.SetTriangles(kvp.Value, submesh);
                submesh++;
            }

            //recalculations
            if (recalculateNormals)
            {
                msh.RecalculateNormals();
            }
            //msh.RecalculateTangents();
            //msh.RecalculateBounds();

            mf.sharedMesh = msh;

            return(go);
        }