public IEnumerable <TaskInfo> ImportIE()
        {
            yield return(new TaskInfo("Preparing import", 0));

            smr = GetComponent <SkinnedMeshRenderer>();
            if (smr == null)
            {
                yield return(new TaskInfo("Missing Skinned Mesh Render component", -1));

                yield break;
            }
            PointCache pc = pointCache;

            pc.SetMaterialsUnused();

            if (ProjectionSamples.Get == null)
            {
                yield return(new TaskInfo("Missing Projection Samples asset. Reinstal Vertex Animation Tools package", -1));

                yield break;
            }

            #region BUILD_TASK_STACK
            TasksStack ts = new TasksStack(string.Format("Importing {0}", pc.name));
            for (int i = 0; i < pointCache.PreImport.UsedMeshesCount; i++)
            {
                ts.Add(string.Format("Building mesh #{0}", i), 1, 0.01f);
            }
            ts.Add("Building binding helper", 1, 0.05f);
            ts.Add("Binding constraints", pc.PreConstraints.Count, 0.01f);

            for (int m = 0; m < pc.PreImport.UsedMeshesCount; m++)
            {
                ts.Add(string.Format("Mesh #{0} binding", m), 1, 0.75f);
            }

            for (int c = 0; c < pc.PreImport.UsedClipsCount; c++)
            {
                ts.Add(string.Format("Building clip #{0}", c), 1, 2f);
                ts.Add(string.Format("Applying clip #{0} frames", c), 1, 0.2f);
            }

            ts.Add("Set meshes compression", pc.PreImport.UsedMeshesCount, 0.1f);
            ts.Add("Optimize meshes", pc.PreImport.UsedMeshesCount, 0.1f);
            ts.Add("Storing changes and cleanup", 1, 0.1f);
            ts.Normalize();

            //ts.PrintDebugInfo();
            #endregion

            #region VALIDATE_MAIN_MESH
            if (!pc.Meshes[0].CheckAndUpdateInfo())
            {
                yield return(new TaskInfo(string.Format("Main mesh not valid: {0}", pc.Meshes[0].Info), -1f));
            }
            #endregion

            #region VALIDATE_CLIPS
            for (int c = 0; c < pc.PreImport.UsedClipsCount; c++)
            {
                if (!pc.Clips[c].PreImport.CheckAndUpdateInfo(pc.Meshes[0].VertsCount))
                {
                    yield return(new TaskInfo(string.Format("Clip {0} not valid: {1}", c, pc.Clips[c].PreImport.FileInfo), -1f));

                    yield break;
                }
            }
            #endregion

            #region LOAD_MESHES
            for (int i = 0; i < pointCache.PreImport.UsedMeshesCount; i++)
            {
                pointCache.Meshes[i].CheckAndUpdateInfo();

                if (pointCache.Meshes[i].VertsCount < 0)
                {
                    yield return(new TaskInfo(string.Format("LODs {0} not valid {1}", i, pointCache.Meshes[i].Info), -1f));

                    yield break;
                }

                if (pointCache.Meshes[i].mesh == null)
                {
                    Mesh newMesh = new Mesh();
                    newMesh.name = string.Format("LOD{0}", i);
                    pointCache.Meshes[i].mesh = newMesh;
                }

                PointCache.PolygonMesh lod = pointCache.Meshes[i];
                lod.od = new ObjData(lod.Path);
                SetIndexFormat(pointCache.Meshes[i].od, pc);
                lod.od.FlipNormals              = pc.PreImport.FlipNormals;
                lod.od.SmoothingGroupsMode      = pc.PreImport.SmoothingGroupImportMode;
                lod.od.NormalsRecalculationMode = pc.PreImport.NormalRecalculationMode;
                lod.od.ImportUV          = true;
                lod.od.CalculateNormals  = true;
                lod.od.CalculateTangents = true;
                SetIndexFormat(lod.od, pc);
                lod.od.Build();
                lod.od.Apply(pc.PreImport.SwapYZAxis, pc.PreImport.ScaleFactor);
                lod.od.CopyTo(lod.mesh);
                if (pc.PreImport.GenerateMaterials)
                {
                    lod.Materials = pc.GetPolygonalMeshMaterials(lod.od.SubMeshes.GetNames());
                }

                lod.od.SetBindPoseFrameVertices();

                yield return(ts[string.Format("Building mesh #{0}", i)].GetInfo(1));
            }
            #endregion

            PointCache.PolygonMesh lod0 = pointCache.Meshes[0];
            Bounds bindPoseBounds       = lod0.od.UM_Bounds;

            #region BUILD_BINDING_HELPER
            yield return(ts["Building binding helper"].GetInfo(0));

            BindingHelper bh = new BindingHelper(pc.Meshes[0].mesh, transform);
            bh.SetVertices(pointCache.Meshes[0].od.UM_vertices, pointCache.Meshes[0].od.UM_normals, pointCache.Meshes[0].od.UM_v3tangents);
            #endregion

            #region BUILD_CONSTRAINTS
            pc.PostConstraints = new PointCache.PostImportConstraint[pc.PreConstraints.Count];
            for (int co = 0; co < pc.PreConstraints.Count; co++)
            {
                yield return(ts["Binding constraints"].GetInfo(co));

                PointCache.PreImportConstraint pre = pc.PreConstraints[co];
                bh.Bind(pre.ObjSpace, ref pre.BI);
                pc.PostConstraints[co]          = new PointCache.PostImportConstraint();
                pc.PostConstraints[co].Name     = pc.PreConstraints[co].Name;
                pc.PostConstraints[co].ObjSpace = pc.PreConstraints[co].ObjSpace;
                pc.PostConstraints[co].Clips    = new ConstraintClip[pc.PreImport.UsedClipsCount];
            }
            #endregion

            #region BIND_GEOMETRY
            for (int m = 1; m < pointCache.PreImport.UsedMeshesCount; m++)
            {
                PointCache.PolygonMesh lod = pointCache.Meshes[m];
                string taskName            = string.Format("Mesh #{0} binding", m);
                foreach (TaskInfo ti in lod.od.BindIE(bh))
                {
                    yield return(ts[taskName].GetInfo(ti.Persentage));
                }
            }
            #endregion

            bool   boundsIsCreated    = false;
            Bounds bounds             = new Bounds();
            int    blendshapesCounter = 0;

            for (int c = 0; c < pc.PreImport.UsedClipsCount; c++)
            {
                PointCache.Clip clip          = pc.Clips[c];
                string          taskStackName = string.Format("Building clip #{0}", c);
                PointCacheData  pcdata        = new PointCacheData(clip, pc, lod0.od.Vertices.Count);
                foreach (TaskInfo ti in pcdata.Build())
                {
                    if (ti.Persentage < 0)
                    {
                        bh.Delete();
                        yield return(new TaskInfo(ti.Name, -1f));

                        yield break;
                    }
                    TaskInfo totalInfo = ts[taskStackName].GetInfo(ti.Persentage);
                    totalInfo.Name = taskStackName + " / " + ti.Name;
                    yield return(totalInfo);
                }
                taskStackName = string.Format("Applying clip #{0} frames", c);

                clip.PreImport.FrameIdxOffset = blendshapesCounter;


                for (int co = 0; co < pc.PreConstraints.Count; co++)
                {
                    pc.PostConstraints[co].Clips[c] = new ConstraintClip(clip.PreImport.ImportRangeLength);
                }

                for (int f = 0; f < pcdata.Frames.Count; f++)
                {
                    yield return(ts[taskStackName].GetInfo(f / (float)pcdata.Frames.Count));

                    lod0.od.VerticesToSet = pcdata.GetFrameVertices(f);
                    lod0.od.Apply(false, 1);
                    if (!boundsIsCreated)
                    {
                        bounds          = lod0.od.UM_Bounds;
                        boundsIsCreated = true;
                    }
                    else
                    {
                        bounds.Encapsulate(lod0.od.UM_Bounds);
                    }
                    Vector3[] posDelta  = lod0.od.GetPosDeltas();
                    Vector3[] normDelta = lod0.od.GetNormsDeltas();
                    Vector3[] tanDelta  = lod0.od.GetTansDeltas();

                    bh.SetVertices(lod0.od.UM_vertices, lod0.od.UM_normals, lod0.od.UM_v3tangents);

                    string shapeName = string.Format("c{0}f{1}", c, f);
                    lod0.mesh.AddBlendShapeFrame(shapeName, 100, posDelta, normDelta, tanDelta);

                    for (int co = 0; co < pc.PreConstraints.Count; co++)
                    {
                        PFU frameObjSpace = pc.PreConstraints[co].GetFrame(bh);
                        pc.PostConstraints[co].Clips[c].Frames[f] = frameObjSpace - pc.PreConstraints[co].ObjSpace;
                    }

                    for (int l = 1; l < pointCache.PreImport.UsedMeshesCount; l++)
                    {
                        pc.Meshes[l].od.ApplyBinded(bh);
                        pc.Meshes[l].mesh.AddBlendShapeFrame(shapeName, 100, pc.Meshes[l].od.GetPosDeltas(), pc.Meshes[l].od.GetNormsDeltas(), pc.Meshes[l].od.GetTansDeltas());
                    }

                    blendshapesCounter++;
                }
            }

            yield return(ts["Storing changes and cleanup"].GetInfo(0));

            bh.Delete();
            if (!boundsIsCreated)
            {
                bounds = bindPoseBounds;
            }
            smr.localBounds = bounds;

            for (int c = 0; c < pc.Clips.Length; c++)
            {
                pc.Clips[c].PostImport = pc.Clips[c].PreImport;
            }


            pc.PostImport = pc.PreImport;
            pc.ImportSettingsIsDirtyFlag = false;
            pc.ClearUnusedMaterials();
            Init();
            yield return(ts.Done);
        }
        public void UpdatePlayback()
        {
            if (pointCache != null)
            {
                ActiveMesh = Mathf.Clamp(ActiveMesh, 0, pointCache.PostImport.UsedMeshesCount);
                PointCache.PolygonMesh polygonMesh = pointCache.Meshes[ActiveMesh];

                if (polygonMesh.mesh == null)
                {
                    return;
                }
                smr.sharedMesh = polygonMesh.mesh;
                if (pointCache.PostImport.GenerateMaterials)
                {
                    smr.sharedMaterials = polygonMesh.Materials;
                }
                int totalFramesCount = smr.sharedMesh.blendShapeCount;
                for (int i = 0; i < totalFramesCount; i++)
                {
                    smr.SetBlendShapeWeight(i, 0);
                }

                for (int cn = 0; cn < Constraints.Length; cn++)
                {
                    Constraints[cn].utm = pointCache.PostConstraints[cn].ObjSpace;
                }

                for (int c = 0; c < pointCache.PostImport.UsedClipsCount; c++)
                {
                    Clip            clip            = Clips[c];
                    PointCache.Clip pcclip          = pointCache.Clips[c];
                    int             clipFramesCount = pcclip.PostImport.FramesCount;
                    int             framesOffset    = pcclip.PostImport.FrameIdxOffset;

                    if (clipFramesCount <= 0)
                    {
                        continue;
                    }

                    int   idxA    = -1;
                    int   idxB    = -1;
                    float weightB = 0;
                    float weightA = 0;

                    clip.NormalizedTime = Mathf.Clamp01(clip.NormalizedTime);

                    if (pcclip.PostImport.IsLoop)
                    {
                        float time = clip.NormalizedTime * clipFramesCount;
                        float lv   = time - Mathf.Floor(time);
                        idxA    = (int)(time % clipFramesCount);
                        idxB    = (int)((time + 1) % clipFramesCount);
                        weightB = lv * clip.Weight;
                        weightA = (1f - lv) * clip.Weight;
                        smr.SetBlendShapeWeight(framesOffset + idxB, weightB * 100);
                        smr.SetBlendShapeWeight(framesOffset + idxA, weightA * 100);
                    }
                    else
                    {
                        float time      = clip.NormalizedTime * (clipFramesCount - 1);
                        float lv        = time - Mathf.Floor(time);
                        int   lastFrame = clipFramesCount - 1;
                        idxA    = Mathf.Clamp(Mathf.FloorToInt(time), 0, lastFrame);
                        idxB    = Mathf.Clamp(idxA + 1, 0, lastFrame);
                        weightA = (1f - lv) * clip.Weight;
                        weightB = lv * clip.Weight;
                        smr.SetBlendShapeWeight(framesOffset + idxB, weightB * 100);
                        smr.SetBlendShapeWeight(framesOffset + idxA, weightA * 100);
                    }

                    for (int cn = 0; cn < Constraints.Length; cn++)
                    {
                        PointCache.PostImportConstraint iconstraint = pointCache.PostConstraints[cn];
                        Constraint constraint = Constraints[cn];
                        constraint.utm = constraint.utm + (iconstraint.Clips[c].Frames[idxA] * weightA) + (iconstraint.Clips[c].Frames[idxB] * weightB);
                    }

                    if (Application.isPlaying)
                    {
                        float dt = (UseTimescale ? Time.deltaTime : Time.unscaledDeltaTime) / clip.DurationInSeconds * timeDirection;
                        if (clip.AutoPlaybackType == AutoPlaybackTypeEnum.Repeat)
                        {
                            clip.NormalizedTime += dt;
                            if (clip.NormalizedTime > 1f)
                            {
                                clip.NormalizedTime = clip.NormalizedTime - Mathf.Floor(clip.NormalizedTime);
                            }
                        }
                        else if (clip.AutoPlaybackType == AutoPlaybackTypeEnum.Once)
                        {
                            clip.NormalizedTime += dt;
                            if (clip.NormalizedTime > 1f)
                            {
                                clip.NormalizedTime   = 1f;
                                clip.AutoPlaybackType = AutoPlaybackTypeEnum.None;
                            }
                        }
                        else if (clip.AutoPlaybackType == AutoPlaybackTypeEnum.PingPong)
                        {
                            clip.NormalizedTime += dt;
                            if (clip.NormalizedTime > 1f)
                            {
                                clip.NormalizedTime = 1f - (clip.NormalizedTime - Mathf.Floor(clip.NormalizedTime));
                                timeDirection       = -1;
                            }
                            else if (clip.NormalizedTime < 0)
                            {
                                clip.NormalizedTime = -clip.NormalizedTime;
                                timeDirection       = 1;
                            }
                        }
                    }
                }
            }
            Matrix4x4 ltw = transform.localToWorldMatrix;

            for (int cn = 0; cn < Constraints.Length; cn++)
            {
                Constraints[cn].Apply(ltw);
            }
            PreparedMeshCollider = -1;
        }