Ejemplo n.º 1
0
        /// <summary>
        /// Loads the avatar head files from disk into TexturedMesh object (parses .ply file too).
        /// </summary>
        /// <param name="avatarCode">Avatar code</param>
        /// <param name="withBlendshapes">If True, blendshapes will be loaded and added to mesh.</param>
        /// <param name="detailsLevel">Indicates polygons count in mesh. 0 - highest resolution, 3 - lowest resolution.</param>
        public static AsyncRequest <TexturedMesh> LoadAvatarHeadFromDiskAsync(string avatarCode, bool withBlendshapes, int detailsLevel)
        {
            var request = new AsyncRequest <TexturedMesh> (AvatarSdkMgr.Str(Strings.LoadingAvatar));

            AvatarSdkMgr.SpawnCoroutine(LoadAvatarHeadFromDisk(avatarCode, withBlendshapes, detailsLevel, request));
            return(request);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Read blendshapes from the avatar directory and add them to 3D head mesh.
        /// </summary>
        public static AsyncRequest <Mesh> AddBlendshapesAsync(string avatarId, Mesh mesh, int[] indexMap)
        {
            var request = new AsyncRequest <Mesh> (AvatarSdkMgr.Str(Strings.LoadingAnimations));

            AvatarSdkMgr.SpawnCoroutine(AddBlendshapes(avatarId, mesh, indexMap, request));
            return(request);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Loads the avatar haircut files from disk into TexturedMesh object (parses .ply files too).
        /// </summary>
        /// <returns>Async request which gives complete haircut TexturedMesh object eventually.</returns>
        public static AsyncRequest <TexturedMesh> LoadHaircutFromDiskAsync(string avatarCode, string haircutId)
        {
            var request = new AsyncRequest <TexturedMesh> (AvatarSdkMgr.Str(Strings.LoadingHaircut));

            AvatarSdkMgr.SpawnCoroutine(LoadHaircutFromDiskFunc(avatarCode, haircutId, request));
            return(request);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Loads the mesh with the given details level and converts from .ply format into Unity format.
        /// </summary>
        public static AsyncRequest <MeshData> LoadDetailedMeshDataFromDiskAsync(string avatarId, int detailsLevel)
        {
            var request = new AsyncRequest <MeshData>(AvatarSdkMgr.Str(Strings.LoadingFiles));

            AvatarSdkMgr.SpawnCoroutine(LoadDetailedMeshDataFromDisk(avatarId, detailsLevel, request));
            return(request);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Read text file asynchronously
        /// </summary>
        public static AsyncRequest <string> ReadFileAsync(string path)
        {
            var request = new AsyncRequestThreaded <string>(() => File.ReadAllText(path));

            AvatarSdkMgr.SpawnCoroutine(request.Await());
            return(request);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Parsing .ply-encoded 3D points (e.g. "haircut point cloud").
        /// </summary>
        public static AsyncRequest <Vector3[]> PlyToPointsAsync(byte[] plyBytes)
        {
            var request = new AsyncRequestThreaded <Vector3[]> (() => {
                Vector3[] points;
                PlyReader.ReadPointCloudFromPly(plyBytes, out points);
                return(points);
            }, AvatarSdkMgr.Str(Strings.ParsingPoints));

            AvatarSdkMgr.SpawnCoroutine(request.Await());
            return(request);
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Loads the avatar haircut points file asynchronously.
 /// </summary>
 /// <param name="code">Avatar unique code.</param>
 /// <param name="haircutId">Unique ID of a haircut.</param>
 public static AsyncRequest <byte[]> LoadAvatarHaircutPointcloudFileAsync(string code, string haircutId)
 {
     try {
         var filename = AvatarSdkMgr.Storage().GetAvatarHaircutPointCloudFilename(code, haircutId);
         return(LoadFileAsync(filename));
     } catch (Exception ex) {
         Debug.LogException(ex);
         var request = new AsyncRequest <byte[]> ();
         request.SetError(string.Format("Could not load haircut {0} point cloud, reason: {1}", haircutId, ex.Message));
         return(request);
     }
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Some of the files involved in avatar generation (e.g. textures) may be large. This function helps to
        /// work around this by saving file in a separate thread, thus not blocking the main thread.
        /// </summary>
        /// <param name="bytes">Binary file content.</param>
        /// <param name="path">Full absolute path.</param>
        public static AsyncRequest <string> SaveFileAsync(byte[] bytes, string path)
        {
            var request = new AsyncRequestThreaded <string> (() => {
                Directory.CreateDirectory(Path.GetDirectoryName(path));
                File.WriteAllBytes(path, bytes);
                return(path);
            });

            request.State = AvatarSdkMgr.Str(Strings.SavingFiles);
            AvatarSdkMgr.SpawnCoroutine(request.Await());
            return(request);
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Loads the haircut file asynchronously.
 /// </summary>
 /// <param name="haircutId">Unique ID of a haircut.</param>
 /// <param name="file">File type (e.g. haircut texture).</param>
 public static AsyncRequest <byte[]> LoadHaircutFileAsync(string haircutId, HaircutFile file)
 {
     try {
         var filename = AvatarSdkMgr.Storage().GetHaircutFilename(haircutId, file);
         return(LoadFileAsync(filename));
     } catch (Exception ex) {
         Debug.LogException(ex);
         var request = new AsyncRequest <byte[]> ();
         request.SetError(string.Format("Could not load {0}, reason: {1}", file, ex.Message));
         return(request);
     }
 }
Ejemplo n.º 10
0
 /// <summary>
 /// Helper method that automatically generates full path to file from file type and avatar id, and then calls
 /// SaveFileAsync.
 /// </summary>
 /// <param name="bytes">Binary file content.</param>
 /// <param name="code">Avatar code.</param>
 /// <param name="file">Avatar file type.</param>
 public static AsyncRequest <string> SaveAvatarFileAsync(byte[] bytes, string code, AvatarFile file)
 {
     try {
         var filename = AvatarSdkMgr.Storage().GetAvatarFilename(code, file);
         return(SaveFileAsync(bytes, filename));
     } catch (Exception ex) {
         Debug.LogException(ex);
         var request = new AsyncRequest <string> ("");
         request.SetError(string.Format("Could not save {0}, reason: {1}", file, ex.Message));
         return(request);
     }
 }
Ejemplo n.º 11
0
 /// <summary>
 /// Same as SaveAvatarFileAsync, but for haircut points, because they are unique for each avatar and should be stored in avatar folder.
 /// </summary>
 /// <param name="bytes">Binary file content.</param>
 /// <param name="code">Avatar unique code.</param>
 /// <param name="haircutId">Unique ID of a haircut.</param>
 public static AsyncRequest <string> SaveAvatarHaircutPointCloudZipFileAsync(
     byte[] bytes,
     string code,
     string haircutId
     )
 {
     try {
         var filename = AvatarSdkMgr.Storage().GetAvatarHaircutPointCloudZipFilename(code, haircutId);
         return(SaveFileAsync(bytes, filename));
     } catch (Exception ex) {
         Debug.LogException(ex);
         var request = new AsyncRequest <string> ("Saving file");
         request.SetError(string.Format("Could not save point cloud zip, reason: {0}", ex.Message));
         return(request);
     }
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Parsing .ply data asynchronously into Unity mesh data (vertices, triangles, etc.)
        /// </summary>
        /// <param name="plyBytes">Binary content of .ply file.</param>
        public static AsyncRequest <MeshData> PlyToMeshDataAsync(byte[] plyBytes)
        {
            var request = new AsyncRequestThreaded <MeshData> (() => {
                var meshData = new MeshData();
                PlyReader.ReadMeshDataFromPly(
                    plyBytes,
                    out meshData.vertices,
                    out meshData.triangles,
                    out meshData.uv,
                    out meshData.indexMap
                    );
                return(meshData);
            }, AvatarSdkMgr.Str(Strings.ParsingMeshData));

            AvatarSdkMgr.SpawnCoroutine(request.Await());
            return(request);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Converts current haircut mesh from ply to fbx format and saves recolored texture.
        /// </summary>
        public static void HaircutPlyToFbx(string avatarId, string haircutId, string fbxFile, Color color, Vector4 tint)
        {
            var filenames             = AvatarSdkMgr.Storage();
            var pointCloudPlyFile     = filenames.GetAvatarHaircutPointCloudFilename(avatarId, haircutId);
            var haircutPlyFile        = filenames.GetHaircutFilename(haircutId, HaircutFile.HAIRCUT_MESH_PLY);
            var srcHaircutTextureFile = filenames.GetHaircutFilename(haircutId, HaircutFile.HAIRCUT_TEXTURE);
            var dstHaircutTextureFile = Path.Combine(Path.GetDirectoryName(fbxFile), Path.GetFileNameWithoutExtension(fbxFile) + ".png");

            var returnCode = CreateMeshConverter().СonvertPlyModelToFbx(pointCloudPlyFile, haircutPlyFile, fbxFile, dstHaircutTextureFile);

            if (returnCode != 0)
            {
                Debug.LogErrorFormat("Unable export haircut to fbx. Error code: {0}", returnCode);
                return;
            }

            RecolorAndSaveTexture(srcHaircutTextureFile, dstHaircutTextureFile, color, tint);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Unzips the file asynchronously.
        /// </summary>
        /// <param name="path">Absolute path to zip file.</param>
        /// <param name="location">Unzip location. If null, then files will be unzipped in the location of .zip file.</param>
        public static AsyncRequest <string> UnzipFileAsync(string path, string location = null)
        {
            if (string.IsNullOrEmpty(location))
            {
                location = Path.GetDirectoryName(path);
            }

            AsyncRequest <string> request   = null;
            Func <string>         unzipFunc = () => {
                ZipUtils.Unzip(path, location);
                return(location);
            };

            // unzip asynchronously in a separate thread
            request = new AsyncRequestThreaded <string> (() => unzipFunc(), AvatarSdkMgr.Str(Strings.UnzippingFile));
            AvatarSdkMgr.SpawnCoroutine(request.Await());
            return(request);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Converts avatar mesh from ply to obj format
        /// </summary>
        public static void AvatarPlyToObj(string avatarId, AvatarFile avatarMesh, AvatarFile avatarTexture, string objFile)
        {
            var plyFile        = AvatarSdkMgr.Storage().GetAvatarFilename(avatarId, avatarMesh);
            var srcTextureFile = AvatarSdkMgr.Storage().GetAvatarFilename(avatarId, avatarTexture);
            var dstTextureFile = Path.Combine(Path.GetDirectoryName(objFile), Path.GetFileNameWithoutExtension(objFile) + ".jpg");

            var returnCode = CreateMeshConverter().ConvertPlyModelToObj(plyFile, null, objFile, dstTextureFile);

            if (returnCode != 0)
            {
                Debug.LogErrorFormat("Unable convert avatar to obj. Error code: {0}", returnCode);
                return;
            }

            if (File.Exists(dstTextureFile))
            {
                File.Delete(dstTextureFile);
            }
            File.Copy(srcTextureFile, dstTextureFile);
        }
Ejemplo n.º 16
0
        public static void ExportAvatarAsFbx(string avatarId, string fbxFile)
        {
            var plyFile       = AvatarSdkMgr.Storage().GetAvatarFilename(avatarId, AvatarFile.MESH_PLY);
            var blendshapeDir = AvatarSdkMgr.Storage().GetAvatarSubdirectory(avatarId, AvatarSubdirectory.BLENDSHAPES);

            // copy texture to destination dir
            var srcTextureFile = AvatarSdkMgr.Storage().GetAvatarFilename(avatarId, AvatarFile.TEXTURE);
            var dstTextureFile = Path.Combine(Path.GetDirectoryName(fbxFile), Path.GetFileNameWithoutExtension(fbxFile) + ".jpg");

            if (File.Exists(dstTextureFile))
            {
                File.Delete(dstTextureFile);
            }
            File.Copy(srcTextureFile, dstTextureFile);

            var returnCode = CreateMeshConverter().ExportFbxWithBlendshapes(plyFile, dstTextureFile, blendshapeDir, fbxFile);

            if (returnCode != 0)
            {
                Debug.LogErrorFormat("Unable export avatar to fbx. Error code: {0}", returnCode);
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Delete entire avatar directory.
        /// </summary>
        public static void DeleteAvatarFiles(string avatarCode)
        {
            var path = AvatarSdkMgr.Storage().GetAvatarDirectory(avatarCode);

            Directory.Delete(path, true);
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Delete particular avatar file by type (e.g. zip mesh file after unzip).
        /// </summary>
        public static void DeleteAvatarFile(string avatarCode, AvatarFile file)
        {
            var path = AvatarSdkMgr.Storage().GetAvatarFilename(avatarCode, file);

            File.Delete(path);
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Read blendshapes from the avatar directory and add them to 3D head mesh.
        /// </summary>
        private static IEnumerator AddBlendshapes(string avatarId, Mesh mesh, int[] indexMap, AsyncRequest <Mesh> request)
        {
            var blendshapesDirs = AvatarSdkMgr.Storage().GetAvatarBlendshapesDirs(avatarId);

            var loadBlendshapesRequest = new AsyncRequestThreaded <Dictionary <string, Vector3[]> > ((r) => {
                var timer       = new MeasureTime("Read all blendshapes");
                var blendshapes = new Dictionary <string, Vector3[]> ();
                List <string> blendshapeFiles = new List <string>();
                foreach (string dir in blendshapesDirs)
                {
                    blendshapeFiles.AddRange(Directory.GetFiles(dir));
                }
                var blendshapeReader = new BlendshapeReader(indexMap);

                for (int i = 0; i < blendshapeFiles.Count; ++i)
                {
                    var blendshapePath = blendshapeFiles [i];
                    var filename       = Path.GetFileName(blendshapePath);

                    // crude parsing of filenames
                    if (!filename.EndsWith(".bin"))
                    {
                        continue;
                    }
                    var tokens = filename.Split(new [] { ".bin" }, StringSplitOptions.None);
                    if (tokens.Length != 2)
                    {
                        continue;
                    }

                    var blendshapeName           = tokens [0];
                    blendshapes [blendshapeName] = blendshapeReader.ReadVerticesDeltas(blendshapePath);
                    r.Progress = (float)i / blendshapeFiles.Count;
                }

                timer.Stop();
                return(blendshapes);
            }, AvatarSdkMgr.Str(Strings.ParsingBlendshapes));

            yield return(request.AwaitSubrequest(loadBlendshapesRequest, finalProgress: 0.9f));

            if (request.IsError)
            {
                yield break;
            }

            var   addBlendshapesTimer = DateTime.Now;
            float targetFps           = 30.0f;

            int numBlendshapes = 0, loadedSinceLastPause = 0;
            var blendshapesDict = loadBlendshapesRequest.Result;

            foreach (var blendshape in blendshapesDict)
            {
                mesh.AddBlendShapeFrame(blendshape.Key, 100.0f, blendshape.Value, null, null);
                ++numBlendshapes;
                ++loadedSinceLastPause;

                if ((DateTime.Now - addBlendshapesTimer).TotalMilliseconds > 1000.0f / targetFps && loadedSinceLastPause >= 5)
                {
                    // Debug.LogFormat ("Pause after {0} blendshapes to avoid blocking the main thread", numBlendshapes);
                    yield return(null);

                    addBlendshapesTimer  = DateTime.Now;
                    loadedSinceLastPause = 0;
                }
            }

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