/// <summary>
        /// GetHaircutMeshAsync implementation
        /// </summary>
        private IEnumerator GetHaircutMeshFunc(string avatarCode, string haircutId, AsyncRequest <TexturedMesh> request)
        {
            DateTime startTime = DateTime.Now;
            // In order to display the haircut in a scene correctly we need three things: mesh, texture, and coordinates of
            // vertices adjusted specifically for our avatar (this is called "haircut point cloud"). We need this because
            // algorithms automatically adjust haircuts for each model to provide better fitness.
            // Haircut texture and mesh (number of points and mesh topology) are equal for all avatars, but "point cloud"
            // should be downloaded separately for each model.
            // If mesh and texture are not cached yet, lets download and save them.
            string haircutMeshFilename       = AvatarSdkMgr.Storage().GetHaircutFilename(haircutId, HaircutFile.HAIRCUT_MESH_PLY);
            string haircutTextureFilename    = AvatarSdkMgr.Storage().GetHaircutFilename(haircutId, HaircutFile.HAIRCUT_TEXTURE);
            string haircutPointCloudFilename = AvatarSdkMgr.Storage().GetAvatarHaircutPointCloudFilename(avatarCode, haircutId);

            bool existMeshFiles  = File.Exists(haircutMeshFilename) && File.Exists(haircutTextureFilename);
            bool existPointcloud = File.Exists(haircutPointCloudFilename);

            if (!existMeshFiles || !existPointcloud)
            {
                var haircutDataRequest = GetHaircutDataAsync(avatarCode, haircutId);
                yield return(request.AwaitSubrequest(haircutDataRequest, 0.05f));

                if (request.IsError)
                {
                    yield break;
                }

                List <AsyncRequest> downloadRequests = new List <AsyncRequest>();
                if (!existMeshFiles)
                {
                    downloadRequests.Add(DownloadAndSaveHaircutMeshAsync(haircutDataRequest.Result));
                }
                if (!existPointcloud)
                {
                    downloadRequests.Add(DownloadAndSaveHaircutPointsAsync(avatarCode, haircutDataRequest.Result));
                }

                yield return(request.AwaitSubrequests(0.9f, downloadRequests.ToArray()));

                if (request.IsError)
                {
                    yield break;
                }
            }

            var loadHaircutRequest = CoreTools.LoadHaircutFromDiskAsync(avatarCode, haircutId);

            yield return(request.AwaitSubrequest(loadHaircutRequest, 1.0f));

            if (request.IsError)
            {
                yield break;
            }

            request.IsDone = true;
            request.Result = loadHaircutRequest.Result;
        }
        /// <summary>
        /// DownloadAndSaveHaircutMeshAsync implementation
        /// </summary>
        private IEnumerator DownloadAndSaveHaircutMeshFunc(AvatarHaircutData haircutData, AsyncRequest request)
        {
            Debug.LogFormat("Downloading haircut mesh, texture and points simultaneously...");
            var haircutMeshRequest    = connection.DownloadHaircutMeshZipAsync(haircutData);
            var haircutTextureRequest = connection.DownloadHaircutTextureBytesAsync(haircutData);

            yield return(request.AwaitSubrequests(0.8f, haircutMeshRequest, haircutTextureRequest));

            if (request.IsError)
            {
                yield break;
            }

            Debug.LogFormat("Saving haircut mesh and texture to disk...");
            var saveHaircutMeshRequest    = CoreTools.SaveHaircutFileAsync(haircutMeshRequest.Result, haircutData.identity, HaircutFile.HAIRCUT_MESH_ZIP);
            var saveHaircutTextureRequest = CoreTools.SaveHaircutFileAsync(haircutTextureRequest.Result, haircutData.identity, HaircutFile.HAIRCUT_TEXTURE);

            yield return(request.AwaitSubrequests(0.9f, saveHaircutMeshRequest, saveHaircutTextureRequest));

            if (request.IsError)
            {
                yield break;
            }

            Debug.LogFormat("Unzip haircut mesh...");
            var unzipMeshRequest = CoreTools.UnzipFileAsync(saveHaircutMeshRequest.Result);

            yield return(request.AwaitSubrequest(unzipMeshRequest, 1.0f));

            if (request.IsError)
            {
                yield break;
            }

            request.IsDone = true;
        }
        /// <summary>
        /// InitializeAvatarAsync implementation
        /// </summary>
        private IEnumerator InitializeAvatarFunc(byte[] photoBytes, string name, string description, PipelineType pipeline,
                                                 AvatarResources resources, AsyncRequest <string> request)
        {
            // uploading photo and registering new avatar on the server
            var createAvatar = connection.CreateAvatarWithPhotoAsync(name, description, photoBytes, false, pipeline, resources);

            // Wait until async request is completed (without blocking the main thread).
            // Instead of using AwaitSubrequest we could just use `yield return createAvatar;`
            // AwaitSubrequest is a helper function that allows to track progress on composite
            // requests automatically. It also provides info for the caller about current subrequest
            // (and it's progress) and propagetes error from subrequest to the parent request.
            // finalProgress is a value between 0 and 1, a desired progress of parent request when given
            // subrequest is completed.
            yield return(request.AwaitSubrequest(createAvatar, finalProgress: 0.99f));

            // must check whether request was successful before proceeding
            if (request.IsError)
            {
                yield break;
            }

            string avatarCode = createAvatar.Result.code;

            // save photo for later use
            var savePhoto = CoreTools.SaveAvatarFileAsync(photoBytes, avatarCode, AvatarFile.PHOTO);
            // save pipeline type
            var savePipeline = CoreTools.SaveAvatarFileAsync(Encoding.ASCII.GetBytes(pipeline.GetPipelineTypeName()), avatarCode, AvatarFile.PIPELINE_INFO);

            yield return(request.AwaitSubrequests(1.0f, savePhoto, savePipeline));

            // again, must check for the error, there's no point in proceeding otherwise
            if (request.IsError)
            {
                yield break;
            }

            request.Result = avatarCode;
            request.IsDone = true;
        }
Example #4
0
        /// <summary>
        /// DownloadAndSaveAvatarModelAsync implementation.
        /// </summary>
        private static IEnumerator DownloadAndSaveAvatarModel(
            Connection connection,
            AvatarData avatar,
            bool withHaircutPointClouds,
            bool withBlendshapes,
            AsyncRequest <AvatarData> request
            )
        {
            // By initializing multiple requests at the same time (without yield between them) we're
            // starting them in parallel. In this particular case we're downloading multiple files at the same time,
            // which is usually a bit faster than sequential download.
            var meshZip        = connection.DownloadMeshZipAsync(avatar);
            var textureRequest = connection.DownloadTextureBytesAsync(avatar);

            var download = new List <AsyncRequest> {
                meshZip, textureRequest
            };
            AsyncWebRequest <byte[]> allHaircutPointCloudsZip = null, blendshapesZip = null;

                        #if BLENDSHAPES_IN_PLY_OR_FBX
            // just a sample of how to get blendshapes in a different format

            AsyncWebRequest <byte[]> blendshapesZipFbx = null, blendshapesZipPly = null;
                        #endif

            if (withHaircutPointClouds)
            {
                allHaircutPointCloudsZip = connection.DownloadAllHaircutPointCloudsZipAsync(avatar);
                download.Add(allHaircutPointCloudsZip);
            }

            if (withBlendshapes)
            {
                blendshapesZip = connection.DownloadBlendshapesZipAsync(avatar);
                download.Add(blendshapesZip);

                                #if BLENDSHAPES_IN_PLY_OR_FBX
                // just a sample of how to get blendshapes in a different format

                blendshapesZipFbx = connection.DownloadBlendshapesZipAsync(avatar, BlendshapesFormat.FBX);
                download.Add(blendshapesZipFbx);

                blendshapesZipPly = connection.DownloadBlendshapesZipAsync(avatar, BlendshapesFormat.PLY);
                download.Add(blendshapesZipPly);
                                #endif
            }

            // continue execution when all requests finish
            yield return(request.AwaitSubrequests(0.9f, download.ToArray()));

            // return if any of the requests failed
            if (request.IsError)
            {
                yield break;
            }

            // save all the results to disk, also in parallel
            var saveMeshZip = CoreTools.SaveAvatarFileAsync(meshZip.Result, avatar.code, AvatarFile.MESH_ZIP);
            var saveTexture = CoreTools.SaveAvatarFileAsync(textureRequest.Result, avatar.code, AvatarFile.TEXTURE);

            var save = new List <AsyncRequest> ()
            {
                saveMeshZip, saveTexture
            };
            AsyncRequest <string> saveHaircutPointsZip = null, saveBlendshapesZip = null;
            if (allHaircutPointCloudsZip != null)
            {
                saveHaircutPointsZip = CoreTools.SaveAvatarFileAsync(allHaircutPointCloudsZip.Result, avatar.code, AvatarFile.ALL_HAIRCUT_POINTS_ZIP);
                save.Add(saveHaircutPointsZip);
            }

            if (blendshapesZip != null)
            {
                saveBlendshapesZip = CoreTools.SaveAvatarFileAsync(blendshapesZip.Result, avatar.code, AvatarFile.BLENDSHAPES_ZIP);
                save.Add(saveBlendshapesZip);
            }

                        #if BLENDSHAPES_IN_PLY_OR_FBX
            // just a sample of how to get blendshapes in a different format

            if (blendshapesZipFbx != null)
            {
                var saveBlendshapesZipFbx = CoreTools.SaveAvatarFileAsync(blendshapesZipFbx.Result, avatar.code, AvatarFile.BLENDSHAPES_FBX_ZIP);
                save.Add(saveBlendshapesZipFbx);
            }

            if (blendshapesZipPly != null)
            {
                var saveBlendshapesZipPly = CoreTools.SaveAvatarFileAsync(blendshapesZipPly.Result, avatar.code, AvatarFile.BLENDSHAPES_PLY_ZIP);
                save.Add(saveBlendshapesZipPly);
            }
                        #endif

            yield return(request.AwaitSubrequests(0.95f, save.ToArray()));

            if (request.IsError)
            {
                yield break;
            }

            var unzipMesh = CoreTools.UnzipFileAsync(saveMeshZip.Result);

            var unzip = new List <AsyncRequest> ()
            {
                unzipMesh
            };
            AsyncRequest <string> unzipHaircutPoints = null, unzipBlendshapes = null;
            if (saveHaircutPointsZip != null)
            {
                unzipHaircutPoints = CoreTools.UnzipFileAsync(saveHaircutPointsZip.Result);
                unzip.Add(unzipHaircutPoints);
            }
            if (saveBlendshapesZip != null)
            {
                unzipBlendshapes = UnzipBlendshapes(saveBlendshapesZip.Result, avatar.code);
                unzip.Add(unzipBlendshapes);
            }

            yield return(request.AwaitSubrequests(0.99f, unzip.ToArray()));

            if (request.IsError)
            {
                yield break;
            }

            // delete all .zip files we don't need anymore
            try {
                foreach (var fileToDelete in new AvatarFile[] { AvatarFile.MESH_ZIP, AvatarFile.ALL_HAIRCUT_POINTS_ZIP, AvatarFile.BLENDSHAPES_ZIP })
                {
                    CoreTools.DeleteAvatarFile(avatar.code, fileToDelete);
                }
            } catch (Exception ex) {
                // error here is not critical, we can just ignore it
                Debug.LogException(ex);
            }

            request.Result = avatar;
            request.IsDone = true;
        }