Ejemplo n.º 1
0
        /// <summary>
        /// See LoadMeshDataFromDiskAsync.
        /// </summary>
        private static IEnumerator LoadMeshDataFromDisk(string avatarId, AsyncRequest <MeshData> request)
        {
            var meshBytesRequest = LoadAvatarFileAsync(avatarId, AvatarFile.MESH_PLY);

            yield return(request.AwaitSubrequest(meshBytesRequest, finalProgress: 0.5f));

            if (request.IsError)
            {
                yield break;
            }

            var parsePlyTimer   = new MeasureTime("Parse ply");
            var parsePlyRequest = PlyToMeshDataAsync(meshBytesRequest.Result);

            yield return(request.AwaitSubrequest(parsePlyRequest, finalProgress: 1));

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

            request.Result = parsePlyRequest.Result;
            request.IsDone = true;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// LoadAvatarHeadFromDiskAsync implementation.
        /// </summary>
        private static IEnumerator LoadAvatarHeadFromDisk(
            string avatarId,
            bool withBlendshapes,
            int detailsLevel,
            AsyncRequest <TexturedMesh> request
            )
        {
            // loading two files simultaneously
            var meshDataRequest     = LoadDetailedMeshDataFromDiskAsync(avatarId, detailsLevel);
            var textureBytesRequest = LoadAvatarFileAsync(avatarId, AvatarFile.TEXTURE);

            yield return(request.AwaitSubrequests(0.6f, meshDataRequest, textureBytesRequest));

            if (request.IsError)
            {
                yield break;
            }

            MeshData meshData = meshDataRequest.Result;

            var parseTextureTimer = new MeasureTime("Parse texture data");
            // at this point we have all data we need to generate a textured mesh
            var texturedMesh = new TexturedMesh {
                mesh    = CreateMeshFromMeshData(meshData, "HeadMesh"),
                texture = new Texture2D(0, 0)
            };

            // This actually blocks the main thread for a few frames, which is bad for VR.
            // To optimize: load jpg/png texture in C++ code in a separate thread and only SetPixels here in Unity. Should be faster.
            texturedMesh.texture.LoadImage(textureBytesRequest.Result);
            parseTextureTimer.Stop();

            if (withBlendshapes)
            {
                // adding blendshapes...
                using (new MeasureTime("Add blendshapes")) {
                    var addBlendshapesRequest = AddBlendshapesAsync(avatarId, texturedMesh.mesh, meshData.indexMap);
                    yield return(request.AwaitSubrequest(addBlendshapesRequest, 1.0f));

                    if (addBlendshapesRequest.IsError)
                    {
                        Debug.LogError("Could not add blendshapes!");
                    }
                }
            }

            request.Result = texturedMesh;
            request.IsDone = true;
        }
Ejemplo n.º 3
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;
        }