「Unity3D」(8)Rigidbody2D卡頓問題和重心旋轉模擬

本文主要討論,在Unity中使用物理引擎Physics2D的三個方面的內容:

  • 如何讓Rigidbody2D物理模擬看起來更加的順滑。
  • 介紹幾個造成運動卡頓的原因和解決方法。
  • 針對Rigidbody2D的重心旋轉模擬。

讓運動更加順滑

最直接的方法,就是設置Rigidbody2D的Interpolate屬性,面板屬性提供了下拉選項,有None,Interpolate,Extrapolate。官方文檔介紹的很清晰,這是物理模擬在Update過程中的運動插值計算,用來解決運動生澀(卡頓)的問題。

  • None 不進行平滑插值。
  • Interpolate 運動插值基於前幾幀的位置。在一個相對平穩的運動環境裏是有很好效果的。但如果是顛簸,崎嶇的運動環境,前幾幀的插值並不能很好的反應未來的趨勢。
  • Extrapolate 運動插值基於後幾幀的預測位置。根據物理公式和地形預測,可以很好的估算出未來幾幀的情況,但遇到突然的碰撞或外力影響,就無法得到很好的效果。

經過測試發現,如果Rigidbody2D的所有的父節點是固定不動的(沒有手動控制),Interpolate 和 Extrapolate 一樣順滑,並且要比None來的流暢。如果Rigidbody2D的父節點有運動(手動控制),Interpolate會有明顯的卡頓,Extrapolate 和 None 差不多,但是依然是不流暢的。

卡頓問題

拋開性能問題,我遇到的卡頓來自於兩個原因。第一,就是上面所說的Rigidbody2D的父節點發生了運動,造成了物理運動有明顯的生澀感。第二,就是手動設置了Rigidbody2D的transform屬性,如Position,Rotation,Scale等。

其實,這兩個問題是同一個原因,就是不要手動設置和Rigidbody2D相關的transform屬性,包括父類鏈的所有節點。物理引擎會接管一切運動模擬,引擎會有自己的算法預測,手動設置會造成衝突。

經過測試發現,哪怕使用了Rigidbody2D的Constraints約束,Freeze Position 或 Freeze Rotation 之後,依然不能去手動設置鎖住的屬性,否則依舊會造成卡頓。

那如果遇到了必須要手動設置的需求,應該怎麼辦呢 ? 這時候可以使用Rigidbody2D暴露的接口去控制。

Rigidbody2D.position
Rigidbody2D.rotation
Rigidbody2D.MovePosition
Rigidbody2D.MoveRotation

Rigidbody2D 暴露了兩個屬性和兩個方法,用來設置position和rotation。經過測試發現,設置屬性依然卡頓,但使用Move方法就消除了卡頓的現象。所以,手動改變Rigidbody2D的position和rotation使用其暴露的Move方法是最好的辦法。

重心旋轉

在使用Rigidbody2D的過程中,期望能夠實現,因爲重心在運動中產生自發旋轉的效果,比如弓箭的飛行模擬。

開始使用了centerOfMass,強行把剛體的質心移動到物體邊緣或外部,期望質心能夠在重力作用下,形成旋轉力,結果不盡人意,自由落體的時候作用很小,反而碰撞接觸了產生了很大的效用。

後來,使用了Rigidbody2D的angularVelocity角速度設置,並且Freeze Rotation鎖住了剛體本身的旋轉模擬,讓angularVelocity無干擾的發揮作用。其結果是可以工作,但是效果不夠真實,angularVelocity並沒有衰減而且是一個固定的速率,難道還需要每幀去模擬angularVelocity的變化,太過繁瑣。

最終,使用了每幀去計算rotation的數值,並Freeze Rotation鎖住旋轉,得到了很好的效果。大概實現如下:

private void FixedUpdate()
{
    if (this.body2D.bodyType == RigidbodyType2D.Dynamic)
    {
        var deltaTime = Time.fixedDeltaTime * 0.5f * this.transform.localScale.x > 0 ? 1.0f : -1.0f;
        var v2        = this.body2D.velocity;
        // s = (v0 + v1) * t / 2
        this.body2D.MoveRotation(Mathf.Atan2(v2.y * deltaTime, v2.x * deltaTime) * Mathf.Rad2Deg);
    }
}

根據當前剛體的速度,計算一幀的xy方向的運動距離,通過Atan2來計算出旋轉角度,在FixedUpdate中手動設置給剛體,當然要使用MoveRotation來得到流暢的旋轉效果。


「Extrapolate」

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章