public void UnlinkAll()
            {
#if UNITY_2017_1_OR_NEWER
                for (int i = 0; i < _nClipData; i++)
                {
                    _c_curClipData = _clipData[i];
                    _c_curClipData.Unlink();
                    _c_curClipData._isCalculated     = false;
                    _c_curClipData._isCalculatedPrev = false;
                }
#endif
            }
            public void Update(apAnimPlayManager animPlayManager)
            {
#if UNITY_2017_1_OR_NEWER
                _c_curTime = _parentTrackSet._playableDirector.time;

                _lastPlayedTimelineClip = null;
#endif
                _lastPlayedLocalTime = 0.0f;

                //1. 전체 Reday To Update
                for (int i = 0; i < _nClipData; i++)
                {
                    _clipData[i].ReadyToUpdate();
                }

#if UNITY_2017_1_OR_NEWER
                //2. 범위 체크해서 업데이트 여부 결정과 Set Data
                _c_curClipData = null;
                _c_clipA       = null;
                _c_clipB       = null;

                _c_localTimeA = 0.0;
                _c_localTimeB = 0.0;
                _c_weightA    = 0.0f;
                _c_weightB    = 0.0f;

                _c_nPlayClips = 0;

                for (int i = 0; i < _nClipData; i++)
                {
                    _c_curClipData = _clipData[i];

                    if (_c_curTime < _c_curClipData._timelineClip.start ||
                        _c_curTime > _c_curClipData._timelineClip.end)
                    {
                        continue;
                    }

                    if (_c_clipA == null)
                    {
                        _c_clipA      = _c_curClipData;
                        _c_nPlayClips = 1;

                        _c_localTimeA = _c_clipA._timelineClip.ToLocalTimeUnbound(_c_curTime);
                    }
                    else if (_c_clipB == null)
                    {
                        //단, A와 AnimClip이 겹치면 안된다.
                        if (_c_clipA._animClip != _c_curClipData._animClip)
                        {
                            _c_clipB      = _c_curClipData;
                            _c_nPlayClips = 2;

                            _c_localTimeB = _c_clipB._timelineClip.ToLocalTimeUnbound(_c_curTime);
                            break;                            //B까지 연결했으면 끝
                        }
                    }
                }

                if (_c_nPlayClips == 1)
                {
                    //PlayClip이 1개일 때
                    if (_c_localTimeA < _c_clipA._timelineClip.easeInDuration)
                    {
                        _c_weightA = GetWeightIn(_c_localTimeA, _c_clipA._timelineClip.easeInDuration);
                    }
                    else if (_c_localTimeA < _c_clipA._timelineClip.duration - _c_clipA._timelineClip.easeOutDuration)
                    {
                        _c_weightA = 1.0f;
                    }
                    else
                    {
                        _c_weightA = GetWeightOut(_c_localTimeA, _c_clipA._timelineClip.easeOutDuration, _c_clipA._timelineClip.duration);
                    }

                    _c_clipA.SetData(true, _c_weightA, (float)_c_localTimeA, _blendMethod, _layerOrder);

                    //Clip A가 마지막에 계산되었다.
                    _lastPlayedTimelineClip = _c_clipA._timelineClip;
                    _lastPlayedLocalTime    = (float)_c_localTimeA;
                }
                else if (_c_nPlayClips == 2)
                {
                    //PlayClip이 2개일 때 (무조건 Blend)
                    _c_weightA = GetWeightOut(_c_localTimeA, _c_clipA._timelineClip.blendOutDuration, _c_clipA._timelineClip.duration);
                    _c_weightB = 1.0f - _c_weightA;

                    _c_clipA.SetData(true, _c_weightA, (float)_c_localTimeA, _blendMethod, _layerOrder);
                    _c_clipB.SetData(false, _c_weightB, (float)_c_localTimeB, _blendMethod, _layerOrder);

                    //Clip B가 마지막에 계산되었다.
                    _lastPlayedTimelineClip = _c_clipB._timelineClip;
                    _lastPlayedLocalTime    = (float)_c_localTimeB;
                }



                //3. 클립데이터 확인하여 Link/Unlink 및 Update
                for (int i = 0; i < _nClipData; i++)
                {
                    _c_curClipData = _clipData[i];
                    if (!_c_curClipData._isCalculated)
                    {
                        //업데이트가 안되었다면 Release
                        if (_c_curClipData._isCalculatedPrev)
                        {
                            //이전 프레임에서는 계산이 되었던 ClipData다.
                            _c_curClipData.Unlink();
                        }
                    }
                    else
                    {
                        //업데이트가 되었으면 연결을 하고, 프레임과 Weight를 업데이트 한다.
                        if (!_c_curClipData._isCalculatedPrev)
                        {
                            //이전 프레임에서는 계산이 안되었다.
                            _c_curClipData.Link();

                            //Root Unit을 갱신할 수도 있다.
                            animPlayManager.SetOptRootUnit(_c_curClipData._linkedRootUnit);
                        }

                        //업데이트 <중요!>
                        _c_curClipData.UpdateTimelineClipAndPlayUnit();
                    }

                    //Prev 갱신
                    _c_curClipData._isCalculatedPrev = _c_curClipData._isCalculated;
                }
#endif
            }
            public bool SetTrack(string trackName, int layerIndex, apAnimPlayUnit.BLEND_METHOD blendMethod, apPortrait portrait, apAnimPlayManager animPlayManager)
            {
#if UNITY_2017_1_OR_NEWER
                //PlayableDirector playDirector = _parentTrackSet._playableDirector;
                PlayableAsset playAsset = _parentTrackSet._playableAsset;
#endif

                _trackName  = trackName;
                _layerIndex = layerIndex;
#if UNITY_2017_1_OR_NEWER
                _layerOrder = _layerIndex;
#endif
                _blendMethod = blendMethod;

                if (string.IsNullOrEmpty(_trackName))
                {
                    //이름이 빈칸이거나 null이다.
                    return(false);
                }

                _clipData = new List <TimelineClipData>();
#if UNITY_2017_1_OR_NEWER
                _timelineClips   = new List <TimelineClip>();
                _clipDataByTrack = new Dictionary <TimelineClip, TimelineClipData>();
#endif

                _nClipData = 0;

                //연결을 하자
                bool isFind = false;
#if UNITY_2017_1_OR_NEWER
                _animationTrack = null;
#endif

                //그 전에 AnimClip <-> AnimationClipAsset을 서로 연결해야한다.
                apAnimClip    curAnimClip           = null;
                AnimationClip curAnimationClipAsset = null;
                Dictionary <AnimationClip, apAnimClip> animClipAsset2AnimClip = new Dictionary <AnimationClip, apAnimClip>();

                for (int i = 0; i < portrait._animClips.Count; i++)
                {
                    curAnimClip = portrait._animClips[i];
                    if (curAnimClip == null)
                    {
                        continue;
                    }
                    curAnimationClipAsset = curAnimClip._animationClipForMecanim;
                    if (curAnimationClipAsset == null)
                    {
                        continue;
                    }

                    if (animClipAsset2AnimClip.ContainsKey(curAnimationClipAsset))
                    {
                        continue;
                    }

                    animClipAsset2AnimClip.Add(curAnimationClipAsset, curAnimClip);
                }

                //apAnimClip에 해당하는 apOptRootUnit을 알아야 한다.
                //apAnimPlayData에 그 정보가 저장되어 있으니 참조하자
                apAnimPlayData curPlayData = null;
                Dictionary <apAnimClip, apOptRootUnit> animClip2RootUnit = new Dictionary <apAnimClip, apOptRootUnit>();

                for (int i = 0; i < animPlayManager._animPlayDataList.Count; i++)
                {
                    curPlayData = animPlayManager._animPlayDataList[i];
                    if (curPlayData == null)
                    {
                        continue;
                    }
                    if (curPlayData._linkedAnimClip == null || curPlayData._linkedOptRootUnit == null)
                    {
                        continue;
                    }

                    if (animClip2RootUnit.ContainsKey(curPlayData._linkedAnimClip))
                    {
                        continue;
                    }

                    //apAnimClip -> apOptRootUnit으로 연결 데이터 추가
                    animClip2RootUnit.Add(curPlayData._linkedAnimClip, curPlayData._linkedOptRootUnit);
                }


#if UNITY_2017_1_OR_NEWER
                foreach (PlayableBinding playableBinding in playAsset.outputs)
                {
#endif
#if UNITY_2018_1_OR_NEWER
                bool isAnimTrack = playableBinding.sourceObject != null && playableBinding.sourceObject is AnimationTrack;
#elif UNITY_2017_1_OR_NEWER
                bool isAnimTrack = playableBinding.streamType == DataStreamType.Animation;
#endif
                //if (playableBinding.streamType != DataStreamType.Animation)
#if UNITY_2017_1_OR_NEWER
                if (!isAnimTrack)
                {
                    //애니메이션 타입이 아니라면 패스
                    continue;
                }

                AnimationTrack animTrack = playableBinding.sourceObject as AnimationTrack;
                if (animTrack == null)
                {
                    continue;
                }
                //if(animTrack.isEmpty)
                //{
                //	//클립이 아예 없는데용
                //	continue;
                //}

                if (!animTrack.name.Equals(_trackName))
                {
                    //이름이 다르다.
                    continue;
                }

                if (animTrack.isEmpty)
                {
                    //클립이 아예 없는데용
                    //continue;
                    Debug.LogWarning("AnyPortrait : ( Warning ) No Clip in the requested track. [ " + trackName + " ]");
                    //일단 처리는 하자
                }

                //이름도 같고 유효한 트랙을 찾았다!
                isFind          = true;
                _animationTrack = animTrack;


                AnimationClip animClipInTrack = null;
                apAnimClip targetAnimClip     = null;
                apOptRootUnit targetRootUnit  = null;

                foreach (TimelineClip timelineClip in _animationTrack.GetClips())
                {
                    //Track의 TimelineClip 중에서 유효한 AnimationClip만 선택한다.
                    animClipInTrack = timelineClip.animationClip;

                    if (!animClipAsset2AnimClip.ContainsKey(animClipInTrack))
                    {
                        //유효한 AnimationClip이 아니다.
                        continue;
                    }

                    targetAnimClip = animClipAsset2AnimClip[animClipInTrack];

                    if (targetAnimClip == null)
                    {
                        //animClip이 비어있다.
                        continue;
                    }

                    if (!animClip2RootUnit.ContainsKey(targetAnimClip))
                    {
                        //apAnimClip -> apOptRootUnit을 조회할 수 없다.
                        continue;
                    }

                    targetRootUnit = animClip2RootUnit[targetAnimClip];
                    if (targetRootUnit == null)
                    {
                        //RootUnit이 null이다.
                        continue;
                    }


                    TimelineClipData newClipData = new TimelineClipData(timelineClip, targetAnimClip, targetRootUnit);
                    _clipData.Add(newClipData);

                    _timelineClips.Add(timelineClip);
                    _clipDataByTrack.Add(timelineClip, newClipData);
                    //_clipDataByAnimClip.Add(targetAnimClip, newClipData);
                    _nClipData++;
                }

                //Debug.Log("Track [" + trackName + "] Added");

                //<<추가>> 시간대에 따라서 Sort
                _clipData.Sort(delegate(TimelineClipData a, TimelineClipData b)
                {
                    return((int)((a._timelineClip.start - b._timelineClip.start) * 100.0));
                });

                if (isFind)
                {
                    break;
                }
            }
#endif
                if (!isFind)
                {
                    Debug.LogError("AnyPortrait : No track with the requested name. [" + trackName + "]");
                }
                return(isFind);
            }