コード例 #1
0
        /// <summary>
        /// LoadHaircutFromDiskAsync implementation.
        /// </summary>
        private static IEnumerator LoadHaircutFromDiskFunc(
            string avatarCode, string haircutId, AsyncRequest <TexturedMesh> request
            )
        {
            var loadingTime = Time.realtimeSinceStartup;

            // start three async request in parallel
            var haircutTexture = LoadHaircutFileAsync(haircutId, HaircutFile.HAIRCUT_TEXTURE);
            var haircutMesh    = LoadHaircutFileAsync(haircutId, HaircutFile.HAIRCUT_MESH_PLY);
            var haircutPoints  = LoadAvatarHaircutPointcloudFileAsync(avatarCode, haircutId);

            // wait until mesh and points load
            yield return(request.AwaitSubrequests(0.4f, haircutMesh, haircutPoints));

            if (request.IsError)
            {
                yield break;
            }

            // we can start another two subrequests, now parsing the ply files
            var parseHaircutPly    = PlyToMeshDataAsync(haircutMesh.Result);
            var parseHaircutPoints = PlyToPointsAsync(haircutPoints.Result);

            // await everything else we need for the haircut
            yield return(request.AwaitSubrequests(0.95f, parseHaircutPly, parseHaircutPoints, haircutTexture));

            if (request.IsError)
            {
                yield break;
            }

            // now we have all data we need to generate a textured mesh
            var haircutMeshData = ReplacePointCoords(parseHaircutPly.Result, parseHaircutPoints.Result);

            var texturedMesh = new TexturedMesh();

            texturedMesh.mesh    = CreateMeshFromMeshData(haircutMeshData, "HaircutMesh");
            texturedMesh.texture = new Texture2D(0, 0);
            texturedMesh.texture.LoadImage(haircutTexture.Result);

            request.Result = texturedMesh;
            request.IsDone = true;

            Debug.LogFormat("Took {0} seconds to load a haircut", Time.realtimeSinceStartup - loadingTime);
        }
コード例 #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;
        }
コード例 #3
0
        /// <summary>
        /// Loads a mesh with the given level of details.
        /// It takes faces and UV-coordinates from the template model, points coordinates from the avatar's model and merges them into a single model.
        /// </summary>
        private static IEnumerator LoadDetailedMeshDataFromDisk(string avatarId, int detailsLevel, AsyncRequest <MeshData> request)
        {
            if (detailsLevel < 0)
            {
                Debug.LogWarningFormat("Invalid details level parameter: {0}. Will be used value 0 (highest resolution).", detailsLevel);
                detailsLevel = 0;
            }

            if (detailsLevel > 4)
            {
                Debug.LogWarningFormat("Invalid details level parameter: {0}. Will be used value 3 (lowest resolution).", detailsLevel);
                detailsLevel = 4;
            }

            if (detailsLevel == 0)
            {
                yield return(LoadMeshDataFromDisk(avatarId, request));
            }
            else
            {
                var meshBytesRequest = LoadAvatarFileAsync(avatarId, AvatarFile.MESH_PLY);
                yield return(request.AwaitSubrequest(meshBytesRequest, finalProgress: 0.3f));

                if (request.IsError)
                {
                    yield break;
                }

                string headTemplateFileName = string.Format("template_heads/head_lod_{0}", detailsLevel);
                var    headTemplateRequest  = Resources.LoadAsync(headTemplateFileName);
                yield return(headTemplateRequest);

                TextAsset templateHeadAsset = headTemplateRequest.asset as TextAsset;
                if (templateHeadAsset == null)
                {
                    Debug.LogError("Unable to load template head!");
                    yield break;
                }

                var meshRequest   = PlyToMeshDataAsync(templateHeadAsset.bytes);
                var pointsRequest = PlyToPointsAsync(meshBytesRequest.Result);
                yield return(request.AwaitSubrequests(0.95f, meshRequest, pointsRequest));

                request.Result = ReplacePointCoords(meshRequest.Result, pointsRequest.Result);
                request.IsDone = true;
            }
        }