理解Unity的Timesteps(步長)和實現平滑移動-創(chuàng)新互聯

首先不知道有沒有像我一樣,一直不是很清楚Timesteps具體怎么解釋的,稍微找了一下:

專注于為中小企業(yè)提供網站設計、成都網站制作服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)向陽免費做網站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯網行業(yè)人才,有力地推動了上千余家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網站建設實現規(guī)模擴充和轉變。

理解Unity的Timesteps(步長)和實現平滑移動

上面說的是兩個物理檢測幀之間的時間間隔

如果不是物理的話,可以直接理解為,兩幀之間的時間間隔

-----

接下來開始翻譯原文

原文:http://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8

在Unity社區(qū)里,其中有一個辯論的最為激勵的話題,就是何如去除游戲中生澀的動作,讓它顯得自然。這個問題不只是在Unity引擎才有,所有引擎都有這個問題,而且他的產生的原因來自于你的引擎用怎么樣的timesteps。

并沒有哪種解決方案能解決所有的這些情況,不過有一種直接的方法解決問題。許多開發(fā)者遇到這個問題是在移動的過程中,發(fā)現物體一抖一抖的,而且想要改善很難。令人驚訝的是,外面關于unity的timesteps有很多誤傳,許多unity論壇的回答者,即使他說對了,也沒有綜合的分析,并且留下了許多理解上的空白讓人無法完全解決這些問題。本文旨在在更深層次的解釋unity的timesteps來解決這個問題,解釋為什么會產生抖動,并提供一個解決方案來解決這個問題。并且發(fā)布了一個AssetPackage來演示這個解決方案

理解Unity的Timesteps(步長)和實現平滑移動

額!這種類型的抖動是不是很熟悉?

上面的這個圖片就是一種簡單的運動抖動。很明顯這并不是我們想要出現在游戲里的畫面。如果你要重現這個非常簡單:

  1. 創(chuàng)建一個新project

  2. 導入一個默認的第一人稱角色控制器,放在一個新場景

  3. 放置一些物件,并選擇一個朝著它畫圓

刪除掉頭的擺動,放置一個游戲平板在地面使得觀察效果更佳明顯。一般情況下,你能注意到,當你繞著它轉時,這里會有特別明顯的抖動。

現在看看這種情況,當我使用了稍后會討論的這些技術。和第一個例子對比,你能明顯看到在順滑上的重要的變化。

理解Unity的Timesteps(步長)和實現平滑移動

 如絲般順滑,好多了!

在解決這個問題之前,先去理解Unity(Mono)的生命周期是很重要的。特別是,我們必須去探索Update和FixedUpdate背后的邏輯。下面的鏈接是一遍來自Unity官方文檔的,關于Unity生命周期的小的摘錄:

https://docs.unity3d.com/Manual/ExecutionOrder.html

特別提醒一下,如果你以前沒有注意過Update的執(zhí)行順序,那么你需要特別的研究一下,因為接下來的部分與這個密切相關。

理解Unity的Timesteps(步長)和實現平滑移動

Unity的各個Update的執(zhí)行順序,原文:https://docs.unity3d.com/Manual/ExecutionOrder.html

先了解這個流程圖(生命周期)。

這個流程圖概括了Unity的各個Update執(zhí)行順序中,一幀里面哪些函數會被調用。這部分我們需要注意的是FixedUpdate和Update函數,圖上綠色和紅色的部分。

Unity實現的是半固定的timestep。這意味著主游戲循環(huán)用一個可變的timestep跑在任何幀率上,這個在Unity里叫做deltaTime。并且用來控制一個使用固定timesteps的內部的循環(huán)。

這里有一些好處:

首先,在游戲中物理在固定幀率的檢測下,可以進行游戲中畫面上的高幀率的Update,只要硬件允許。

相反的,這里也有一些壞處,容易出現上面所說的抖動。

下面是簡單的用代碼來解釋一下Unity的Update循環(huán)的結構:

float currentSimulationTime = 0; float lastUpdateTime = 0; while (!quit) // variable steps {         while (currentSimulationTime  < Time.time) // fixed steps         {               FixedUpdate();               Physics.SimulationStep(currentState, Time.fixedDeltaTime);               currentSimulationTime += Time.fixedDeltaTime;         }  Time.deltaTime = Time.time - lastUpdateTime;  Update();  Render();  lastUpdateTime = Time.time; }

這個Update函數對你來說應該很熟悉了,它在Monobehaviours的每幀里,在輸入已經執(zhí)行后,在渲染前的中間這段時間里被調用。

如果垂直同步關閉了的話,當一幀結束以后,Unity會立刻執(zhí)行下一幀,這樣子去獲得盡可能高的幀率。

當每幀的硬件和計算量在不停的變化時,幀率也會不停的變化,即使垂直同步打開了,由于Unity嘗試去讓每個幀率盡量相同,也不會真的固定不變。

由于以上這些,Update函數能在一秒內被調用任意次數。

FixedUpdate在每次Monobehaviors的物理檢測中進行。即使多個物理檢測中,他們的檢測的時間間隔不是相同的時間,Unity也會把他們放到固定的時間間隔內調用。 這是因為在游戲的物理里,尤其是加速運動中,使用固定的時間差,是最準確和最穩(wěn)定的。在Unity里,這個固定的時間差就叫做fixedDeltaTime。默認的時候,fixedDeltaTime的值為0.02,這意味著在游戲里每秒鐘總有50次FixedUpdate的調用。用這種方法,你可以理解FixedUpdate是一個獨立的幀率,它在每秒鐘被調用的次數是固定的,即使這時你的渲染幀率非常低或者非常高。重點的提出FixedUpdate和物理的循環(huán)是相關關聯的很有必要的,不是發(fā)現在不同線程的。

基于這點,一起來觀察一下幾個關于更新時機的例子。

理解Unity的Timesteps(步長)和實現平滑移動

上面是當每秒有50個FixedUpdate和60個Update的時候的更新時機??墒?,在實際中由于幀率是不固定所以不會這么完美,下面這個圖這個就是現實中的,一點點夸大的時間軸。注意到,有一些Update之間是沒有FixedUpdate的,這種情況一般出現在渲染簡單畫面的時候。另一方面一些Update之間有還幾次FixedUpdate,這個一般出現在加載資源的過程中。這意味著,即使你盡可能的讓Update和FixedUpdate次數相同,這也很難做到對齊。

理解Unity的Timesteps(步長)和實現平滑移動

根據我們對Unity的timesteps的知識,我們可以理解下面的這個案例。這個場景里,一個球和照相機繞著同一個支點。這個球的transform的改變放在Update循環(huán)里,與此同時,左邊照相機的transform改變放在FixedUpdate循環(huán)里,右邊的照相機放在Update循環(huán)里。左邊這個看起來就有很明顯的抖動,右邊的就很順滑

理解Unity的Timesteps(步長)和實現平滑移動

左邊的照相機在FixedUpdate里移動,右邊的在Update里

由于Update和FixedUpdate的調用不在通過頻率上,當球在移動的時候照相機依然還在原地。這就導致了球相對于照相機移動的不同步,產生了抖動。當在慢鏡頭下,這些行為就更為明顯。

理解Unity的Timesteps(步長)和實現平滑移動

和上面一樣的模型,5%的速度

所以,我們能看到導致抖動的緣由是因為移動不同的objects的時候,有的在Update里有的在FixedUpdate里。所以簡單的修復方法就是必須把所有移動transform的地方,要不放在Update里,要不放在FixedUpdate里。

然而,這時事情開始變得棘手了,這個常見的回答會使很多Unity開發(fā)者把游戲中的許多游戲內的運動放在Update里,而FixedUpdate只放小部分物理邏輯。雖然這有它的優(yōu)點,比如簡化了你的操作,但是由于很多原因,它是有問題的。也許大的問題是讓你的游戲依靠畫面的幀率進行。這就導致了有很多bug和連貫性的行為不一致的問題,打開了這些錯誤大門。此外,它會影響很多決策,包括幾乎所有的實時策略類型。當你需要執(zhí)行加速度運動時,比如玩家的重力,這也會出現問題。像這些物體就應該使用FixedUpdate,但由于其他的物體使用了Update,所以你會看到很多抖動。(請參考標準assets里面的第一人稱控制器來管著這個問題)

因此,一個常見的且有時是必要的選擇是,把所有的狀態(tài)和游戲邏輯放在固定的timestep里像FixedUpdate,嚴格的把畫面和輸入信息放在Update里。

然而,這里面不是只有它自己產生的問題,首先,你可能希望你游戲的物理幀也不同于游戲邏輯幀的節(jié)奏出現。這個操作非常簡單,Unity給了你很多操作的空間,允許你自己去選擇和優(yōu)化。接著,輸入信息只在Update里也會有問題,當兩個FixedUpdate直接出現了多個Update時,只有最后那一個Update里的輸入信息會影響到后面的FixedUpdate。這個特然容易出現在上下按鈕事件,因為它們支隊單一幀有用。這個問題的解決方案是,在下一個FixedUpdate前,把輸入信息用一個input buffer進行緩沖。將此行為集成到您使用的任何輸入控制器中是一種相當無縫的方式來執(zhí)行此操作,并將緩沖保留在一個位置。

然而,一個更大的問題是,一般來說FixedUpdate的調用會比Update少,所以移動物件的頻率跟不上畫面渲染的頻率,導致雖然畫面是流暢的,但是移動的時候斷斷續(xù)續(xù)的。

有很多種方法可以借鑒這種問題,比如用差值和推測的方法解決,使得可以平滑的移動。差值,可以很方便的流暢的使物體從一個狀態(tài)移動到另一個狀態(tài),很容易使用。不過這會導致有一個fixedDeltaTime的延時。這個延時在大部分游戲內的一般情況下,是能被接受的,即使是射擊游戲的射手也可以使用這種方法獲得平滑的移動。推測,是預測物體的下個狀態(tài)會在哪個位置,避免了延時,但是本質是更難做到無縫的滑動并且還帶來了性能的壓力。

理解Unity的Timesteps(步長)和實現平滑移動

攝像頭和球都在FixedUpdate中移動,右邊使用了差值計算

以上是演示差值的另一個比較案例。左邊這個圖,鏡頭和球的transform設置都在FixedUpdate里。右邊也是,不過右邊在FixedUpdate的兩次調用之間用了差值計算是的移動的時候更順滑。注意到兩邊的物件都基本保持了一致性,不過右邊的移動更流暢更少抖動。

所以,怎么在Unity用差值計算呢?我做了一個assetPackage,鏈接在下面:

http://ksblogcontent.s3-website-us-east-1.amazonaws.com/TimeStepBlog/Timesteps.unitypackage

此外,您可以獲取用于創(chuàng)建上述示例的構建:

http://ksblogcontent.s3-website-us-east-1.amazonaws.com/TimeStepBlog/TimestepsBuild.zip

具體就看上面的demo了,后面懶得翻了。。。

另外有需要云服務器可以了解下創(chuàng)新互聯cdcxhl.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。

分享標題:理解Unity的Timesteps(步長)和實現平滑移動-創(chuàng)新互聯
轉載來源:http://bm7419.com/article34/dihipe.html

成都網站建設公司_創(chuàng)新互聯,為您提供外貿網站建設、標簽優(yōu)化靜態(tài)網站、ChatGPT手機網站建設、網站導航

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

成都做網站