[Unity]Animation WarpMode

參考資料:Animation.wrapModeWrapMode
Unity版本:3.5.6f4

在Unity內Animation的WrapMode可以透過Script來變更。以下針對各個參數進行說明:

1.WrapMode.Default:
        直接拿Amination Clip內設定的wrapMode來進行動畫播放。預設的wrapMode為WrapMode.Once。

2.WrapMode.Once:
        當動畫時間軸到達Animation Clip終點時,正在播放中的Animation Clip會被自動的停止播放,並且時間軸會被重設回Animation Clip的一開始。

         不過當Animation Clip是從終點反向播放到起點時,雖然在播放到起點時會也會被自動停止,但是時間軸並不會被重置回終點,而是留在起點。

3.WrapMode.Loop:
        當動畫時間軸到達Animation Clip的終點時,時間軸會又回到起點的位置,並且繼續播放動畫。如果將播放模式設為反向時(即將Animation[ClipName].speed設為負值),則會從反向播放動畫,而播放的起點與終點都會跟正向播放時相反。

Note:根據官方的說法,將AnimationState.speed設為負值時,Animation Clip就會被反向播放(A negative playback speed will play the animation backwards.)。但目前測試由3dMax匯出的Animation以及使用Unity Animation所做出的Clip,在播放移動Animation時,把AnimationState.speed設為-1,播放的結果是物件直接跳到起始位置,並沒在從終點移動到起點位置。這邊還需要再確認問題點在那邊。

Note(2012/11/20):
        今找到原因了,原先測試時,只有變更AnimationState.speed,而沒有去變更AnimationState.time。所以播放時,時間軸就已經在0的位置了,也因此看不到動畫做動。如要反向播放動畫則需變更AnimationState.Speed為負值以及設定AnimationState.time不為起點。

4.WrapMode.PingPong:
        當動畫時間軸到達Animation Clip的終點時,時間軸會在往起點的方向前進。這個動畫效果會使物件重複的在Animation Clip的起點與終點之間來回的播放動畫。對於需要來回反複播放的動畫而言,就可以設定成此狀態。

5.WrapMode.ClampForever:
        當動畫時間軸到達Animation Clip的終點時,時間軸將會停止在Animaiton Clip的終點,且動畫播放狀態依然是播放中,也就是Animation不會停止Animation Clip的動畫播放。而如果設定為反向播放時,時間軸到達起點時,也一樣會停止在起點,且Animaiton Clip也是在播放中的狀態。也因此,此設定會使Animation Clip只播放一次。

        根據官方文件的說法,這個設定可以用在播放時間軸到達終點後不打算結束的Additive Animation上。根據測試的結果為,動畫物件是會停在時間軸的結束狀態下,但AnimationStates[].time還是會持續的增加或是減少(依據設定的播放時間值)。


        在Animation以及Animation Clip上都有WrapMode的屬性,而透過Script去設定時,卻有些許的不同。對於wrapMode這個屬性,在Animation本身上,是可以在播放中就去設定,而且會立即生效;但是當Animation Clip正在播放中的時後,AnimationClip.wrapMode是不能被變更的(唯讀狀態)。


以下為操作測試:
I.在Script內去變更Animation.wrapMode時,WrapMode會立即的套用在Animation Clip的播放上(如果是透過Inspector來變更,則WrapMode不會立即的套用在Animation Clip的播放上),但Animation Clip.warpMode還是保持原本的設定。

例如:Animation.wrapMode原本設定為WrapMode.Once,Animation Clip.wrapMode也設定為WrapMode.Once。在Animation.Play()之後,且Animation Clip播放完畢之前,將 Animation.wrapMode改為WrapMode.PingPong。則此時看到的動畫效果就變成來回播放,但是Animation Clip.wrapMode還是依舊為WrapMode.Once。

II.在Script內去變更Animation Clip.wrapMode時,WrapMode會立即套用到Animation Clip.wrapMode,但是並不會影響到正在播放的Animation。

例如:Animation.wrapMode原本設定為WrapMode.Once,Animation Clip.wrapMode也設定為WrapMode.Once。在Animation.Play()之後,且Animation Clip播放完畢之前,將 Animation.wrapMode改為WrapMode.PingPong。則此時看到的動畫還是播完後就停止了,但此時又再重新播放動畫的話,動畫效果還是一樣只播一次。不過在Animation Clip.wrapMode的設定上,是有被變更為WrapMode.PingPong。


例外原因:
        會出現上面的狀況是因為Animation是透過AnimationState來控制動畫的播放。根據目前的測試,在編輯模式下,AnimationStates是一個空的陣列(圖1.)。當啟用Play模式時,Animation會把在Animations內所指定的Animation Clip的name以及wrapMode新增到AnimationStates內(圖2.)(Animation Clip的設定請參考圖3.)。由這邊看出Unity看起來是在Animation初始化的時候取得AnimationClip.wrapMode,並加到AnimationState內。

圖1.編輯模式下的Animation States

圖2.Play模式下的Animation States

圖3.AnimationClip的設定

        在上述的狀況下,變更Animation Clip.wrapMode(圖4.),此時卻發現一開始加到AnimationStates的wrapMode卻沒有變更。所以由此推測,這邊的wrapMode是從AnimationClip.wrapMode複製來的,而不是取得參考。這也可以指出,為什麼在Animation沒有重新取得AnimationClip時,播放的結果總是不同於設定的值。所以之後再怎麼變更AnimacionClip.wrapMode,Animatoin也不可能知到目前指定的AnimationClip已經有任何的變化。

                   圖4.變更AnimationClip.wrapMode           圖5.[圖4.]狀態下的Animation資訊

解決方案:
i.在使用Unity Editor的模式下,僅需再重新Play Game Mode,就可以使用到變更後的WrapMode。

ii.在使用編譯後的執行檔時,有三種方法可以使用變更後的WrapMode:
     1.重新載入場景。
     2.刪除目前GameObject所持有的Animation元件,並再重新加入Animation元件與Animation Clip
        後。如要用這方法,則需在刪除Animation後的下一個Frame才可以再新增Animation元件,
        不然Unity會跳出物件還存在且不可重複加入的錯誤訊息。原因是Object.Destroy()所說的
       「物件的刪除總是在Update loop結束之後以及rendering之前發生」。
     3.直接將新的Animation Clip.wrapMode指定給Animation[Animation Clip.name].wrapMode。     

結論:
1.在Inspector修改Animation.wrapMode並不會立刻套用到目前的播放上。(AnimaitonStates不會被立即變更)

2.透過Script修改Animation.wrapMode會立即套用到所有的AnimationClip(包含目前的播放)在Animation Component內的wrapMode上。(AnimationStates會被立即變更)

3.變更過的AnimationClip.wrapMode需要Animation Component進行重載後,才會更新到AnimaitonStates。

4.播放中的Animation Clip是不能進行wrapMode的變更。

Comments

Popular Posts