/// <summary>
        /// Asynchronously imports the given .obj file from the specified url
        /// </summary>
        /// <param name="url">The url to the .obj file</param>
        /// <returns>The GameObject that was created for the imported .obj</returns>
        public async Task <GameObject> ImportAsync(string url)
        {
            i5Debug.Log("Starting import", this);
            Uri uri = new Uri(url);
            // fetch the model
            WebResponse <string> resp = await FetchModelAsync(uri);

            // if there was an error, we cannot create anything
            if (!resp.Successful)
            {
                i5Debug.LogError("Error fetching obj. No object imported.\n" + resp.ErrorMessage, this);
                return(null);
            }

            // create the parent object
            // it is a standard GameObject; its only purpose is to bundle the child objects
            GameObject parentObject = ObjectPool <GameObject> .RequestResource(() => { return(new GameObject()); });

            parentObject.name = System.IO.Path.GetFileNameWithoutExtension(uri.LocalPath);

            // parse the .obj file
            List <ObjParseResult> parseResults = await ParseModelAsync(resp.Content);

            // for each sub-object in the .obj file, an own parse result was created
            foreach (ObjParseResult parseResult in parseResults)
            {
                // check that the referenced mtl library is already loaded; if not: load it
                if (!MtlLibrary.LibraryLoaded(parseResult.LibraryPath))
                {
                    string mtlUri      = UriUtils.RewriteFileUriPath(uri, parseResult.LibraryPath);
                    string libraryName = System.IO.Path.GetFileNameWithoutExtension(uri.LocalPath);
                    bool   successful  = await MtlLibrary.LoadLibraryAsyc(new Uri(mtlUri), libraryName);

                    if (!successful)
                    {
                        i5Debug.LogError("Could not load .mtl file " + parseResult.LibraryPath, this);
                    }
                }

                // get the material constructor of the sub-object
                MaterialConstructor mat = MtlLibrary.GetMaterialConstructor(
                    System.IO.Path.GetFileNameWithoutExtension(uri.LocalPath),
                    parseResult.MaterialName);

                if (mat != null)
                {
                    // first get dependencies; this will e.g. fetch referenced textures
                    await mat.FetchDependencies();

                    parseResult.ObjectConstructor.MaterialConstructor = mat;
                }

                // construct the object and make it a child of the parentObject
                parseResult.ObjectConstructor.ConstructObject(parentObject.transform);
            }

            return(parentObject);
        }
Esempio n. 2
0
        /// <summary>
        /// Parses the contents of a .mtl file
        /// </summary>
        /// <param name="uri">The full URI where the .mtl file is stored</param>
        /// <param name="libraryContent">The line array of the file's content</param>
        /// <returns>A list a material constructor for each material in the library</returns>
        private List <MaterialConstructor> ParseMaterialLibrary(Uri uri, string[] libraryContent)
        {
            List <MaterialConstructor> materials = new List <MaterialConstructor>();
            MaterialConstructor        current   = null;
            int numberOfErrors = 0;

            for (int i = 0; i < libraryContent.Length; i++)
            {
                string trimmedLine = libraryContent[i].Trim();

                // newmtl and # (comment) can be executed also if there is no current material set
                // skip empty lines
                if (string.IsNullOrEmpty(trimmedLine))
                {
                    continue;
                }
                else if (trimmedLine.StartsWith("newmtl"))
                {
                    if (current != null)
                    {
                        materials.Add(current);
                    }
                    current      = new MaterialConstructor();
                    current.Name = trimmedLine.Substring(6).TrimStart();
                }
                else if (trimmedLine.StartsWith("#"))
                {
                    if (ExtendedLogging)
                    {
                        i5Debug.Log("Comment found: " + trimmedLine.Substring(1).TrimStart(), this);
                    }
                }
                // all other commands require an already initialized material
                // this means that the line newmtl must have been read at least once until now
                else
                {
                    if (current != null)
                    {
                        // Kd sets the diffuse color
                        if (trimmedLine.StartsWith("Kd"))
                        {
                            string[] strValues = trimmedLine.Substring(2).TrimStart().Split(' ');
                            if (strValues.Length != 3)
                            {
                                numberOfErrors++;
                                if (ExtendedLogging)
                                {
                                    i5Debug.LogError("Expected three color values but found " + strValues.Length, this);
                                }
                                continue;
                            }
                            if (ParserUtils.TryParseStringArrayToVector3(strValues, out Vector3 colorVector))
                            {
                                // could successfully parse color vector
                                Color albedo = colorVector.ToColor();
                                current.Color = albedo;
                            }
                            else
                            {
                                numberOfErrors++;
                                if (ExtendedLogging)
                                {
                                    i5Debug.LogError("Could not parse color data", this);
                                }
                            }
                        }
                        // Ks sets the specular intensity
                        else if (trimmedLine.StartsWith("Ks"))
                        {
                            string[] strValues = trimmedLine.Substring(2).TrimStart().Split(' ');
                            if (strValues.Length != 3 && strValues.Length != 1)
                            {
                                numberOfErrors++;
                                if (ExtendedLogging)
                                {
                                    i5Debug.LogError("Expected one or three smoothness values but found " + strValues.Length, this);
                                }
                                continue;
                            }
                            // we assume that all values are equal
                            if (float.TryParse(strValues[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float smoothness))
                            {
                                // could successfully parse smoothness
                                current.SetFloat("_Glossiness", smoothness);
                            }
                            else
                            {
                                numberOfErrors++;
                                if (ExtendedLogging)
                                {
                                    i5Debug.LogError("Could not parse color data", this);
                                }
                            }
                        }
                        // map_Kd sets the albedo texture
                        else if (trimmedLine.StartsWith("map_Kd"))
                        {
                            string texturePath = trimmedLine.Substring(6).TrimStart();
                            // rewrite the URI to the texture's path and then add a texture constructor to the material
                            string fullUri = UriUtils.RewriteFileUriPath(uri, texturePath);
                            current.SetTexture("_MainTex", new TextureConstructor(fullUri));
                        }
                    }
                    else
                    {
                        i5Debug.LogWarning("Material instruction line found but material has not yet been initialized. The .mtl-file is probably malformed.", this);
                    }
                }
            }

            if (current != null)
            {
                materials.Add(current);
            }

            // check if materials were created
            if (materials.Count == 0)
            {
                i5Debug.LogWarning(".mtl-file was read but no materials were parsed.", this);
            }

            return(materials);
        }