Unity下實現彈簧骨骼(Spring Bone)


關於這個效果的名稱,我一直沒找到一個比較正式的說法。Spring Bone這個說法是來自於Anima2D這個插件中的一個演示用的腳本,我直接譯成彈簧骨骼。

一般常見於對人物的頭發的模擬上。

當然也可以直接用在普通物體上

效果的實現是通過改變物體的旋轉進行的。在LateUpdate執行代碼。我們在腳本中保存上一幀的骨骼末端位置,當運行當前幀時,如AnimatorController之類的組件會在Update中將物體的旋轉設置為指定值。我們在LateUpdate中,通過保存的上一幀的骨骼末端位置以及當前的旋轉值,進行計算,得到一個類似的插值位置,然后轉化為旋轉值,將物體旋轉到對應位置。

部分代碼如下:

        currentTipPos = transform.TransformPoint(springEnd);

        currentTipPos = Vector3.Lerp(lastFrameTip, currentTipPos, Time.deltaTime);

        currentTipPos = springLength * (currentTipPos - transform.position).normalized + transform.position;    //clamp length.

        transform.rotation =
            Quaternion.FromToRotation(transform.TransformDirection(springEnd), (currentTipPos - transform.position).normalized)
            * transform.rotation;
        currentTipPos = springLength * (currentTipPos - transform.position).normalized + transform.position;    //clamp length.

        transform.rotation =
            Quaternion.FromToRotation(transform.TransformDirection(springEnd), (currentTipPos - transform.position).normalized)
            * transform.rotation;

這樣的實現快速有效,但是最終效果僅僅是物體的運動變為慢慢靠近目標點,顯得不夠真實。

想要加入類似彈簧的效果,我們需要進行真實的力、速度的計算。我們保存當前的速度,根據位置計算當前受到的力,然后根據力修改速度,通過這個速度去修改目標位置。

        currentTipPos = transform.TransformPoint(springEnd);

        var force = bounciness * (currentTipPos - lastFrameTip);  //spring force.

        force += stiffness * (currentTipPos - transform.position).normalized;  //stiffness

        force -= dampness * velocity;               //damp force. 

        velocity = velocity + force * Time.deltaTime;       //v = v0 + at. we don't need integration here, you won't notice any "wrong".

        currentTipPos = lastFrameTip + velocity * Time.deltaTime; //s = s0 + vt

        currentTipPos = springLength * (currentTipPos - transform.position).normalized + transform.position;    //clamp length.

        transform.rotation =
            Quaternion.FromToRotation(transform.TransformDirection(springEnd), (currentTipPos - transform.position).normalized)
            * transform.rotation;

我設置了3個力的選項,分別是bounciness彈性力,提供“歸位“的力,力由當前骨骼末端指向歸位時的骨骼末端,stiffness剛性力,提供保持原狀的力,力方向往骨骼方向延長,以及dampbess阻力,沿着速度反方向。

通過設置三個力的大小,可以實現不同的效果。最終效果如文章開篇的圖2

此外還有一個細節需要注意,骨骼更新的順序應該嚴格的遵守從父物體的骨骼更新到子物體。不然可能會出現奇怪的情況。

github: https://github.com/yangrc1234/SpringBone


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM