Simulator Scene in Unity3D – Collider and Rigidbody 3D version (Section 3)

簡介

根據前兩篇的敘述與實驗後,是否有更了解Unity中的Collider與Rigidbody呢?!我們再第三章講述比較複雜的Wheel Collider,通常是用在輪子相關的物件,在模擬場景中常會出現的自駕車模擬更會使用上,而如何運用這兩個功能讓車輛行駛的更貼近現實世界,就要細細的微調之中的參數了,讓我們開始吧。

Wheel Collider 細部介紹

Wheel Collider內置碰撞檢測 ,車輪物理特性和基於滑動的輪胎摩擦係數。它可以用於除車輪以外的物體,但專門設計用於帶輪車輛。 下圖是Wheel Collider的Component圖。一樣是在Scene中輪子物件按下Add Component->Wheel Collider。

我們可以參考下方Collider圖片來了解參數解釋,中間有一條綠色的線(位於wheel collider中心點的直徑) 在下方解釋會常看到 ” 車輪懸架 “,就是在說這個詞。

Mass : 輪軸物件的質量。值介於 0 – 無限。
Radius : (下圖紅色箭頭) 輪軸碰撞器的半徑。 值介於 0 – 無限。
Wheel Damping Rate : 避震器,避震值範圍。值介於 0.0001 – 無限。
Suspension Distance : (下圖橙色箭頭)車輪懸架的最大延伸距離,從輪軸中心Y軸向下延伸。 數值越大距離越遠。值介於 0 – 無限。 此值會與Wheel Damping Rate相互作用,數值調整不好會變成彈跳車。
Force App Point Distance : (下圖綠色箭頭)施力點距離 ,預設為0,最好把這個值調整到wheel Collider邊界上。
Center : (下圖青藍色箭頭)輪軸中心離地板的距離。

Suspension Spring : 這邊是更細部設定碰撞器的輪軸避震值的細部設定。懸架試圖達到目標位置,通過增加彈簧和阻尼力。
Spring : 彈力試圖到達目標位置。較大的值可使懸架更快地到達目標位置。 值介於 0 – 無限。
Damper : 降低懸架速度。較大的值會使懸架彈簧的移動速度變慢。 值介於 0 – 無限。
Target Position : 懸架沿懸架距離的靜止距離。 1映射到完全擴展的懸架,0映射到完全壓縮的懸架。默認值為0.5,與常規汽車的懸架狀態一致。

Forward Friction / Sideway Friction:車輪向前和向側面滾動時輪胎的摩擦特性。
在摩擦力的調整,可以說是在調整你輪胎的橡膠的摩擦係數,Extremum Slip / Value:在調整輪胎運動向前與向側邊的摩擦係數,值越高越滑。此參數會跟著加速度的曲線成正比,煞車亦同。Asymptote Slip / Value:曲線的結束點,此參數會與Extremum會同時運算會製成Curve圖(如下圖),當車輛行徑力道與滑動係素會將上方兩個值做即時運算。

Wheel Collider 實現在車輛中

在官方文件中,他們是把輪胎模型跟Collider是分開的,但其實可以把Collider掛載在輪胎的模型物件上(如下圖)。
Step1:你必須有既有的模型,且必須要有輪胎的獨立物件,並將所有物件包成一個GameObject。
Step2:請新增Wheel Collider在各輪胎模型上。並將碰撞器的參數透過上方解釋的各個參數調整好。

Step3:下方我提供了控制車輛移動透過鍵盤來操作。我將程式碼中的的功能都寫在程式碼註記中。先新增Create->C# Script,並將下方的程式碼貼上你新增的C# Script,要注意的一點是,程式碼的名稱要跟C#程式的Class名稱相同,否則會出錯。

Step4:將程式碼掛載在Step1 GameObject之下,並在此GameObject下新增個Rigidbody。掛載好兩個元件會如下圖所示,並將Rigidbody拉到程式碼的Center Of Gravity欄位中。

Step5:調整上圖Car Controller程式碼中的public參數,並將Wheel Collider拖曳到上圖紅框框處,大致上是這樣,剩下的細節可以看到下方程式碼中的註解。

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine.UI;
 
 public class CarController : MonoBehaviour {
     //輪胎旋轉的標準值與最大值
     public float idealRPM = 500f;
     public float maxRPM = 1000f;

     //車輛物件的Rigidbody,重量中心點的物件放置於此
     public Transform centerOfGravity;

     //Wheel Collider放置於此
     public WheelCollider wheelFR;
     public WheelCollider wheelFL;
     public WheelCollider wheelRR;
     public WheelCollider wheelRL;

     //輪胎運算參數
     public float turnRadius = 6f;
     public float torque = 25f;
     public float brakeTorque = 100f;
 
     public float AntiRoll = 20000.0f;
     //車輛的行車方向,向前與向後
     public enum DriveMode { Front, Rear, All };
     public DriveMode driveMode = DriveMode.Rear;
 
     //在程式的生命週期Start時定位車輛中心點的重量
     void Start() {
         GetComponent<Rigidbody>().centerOfMass = centerOfGravity.localPosition;
     }
     //車輛速度運算,透過輪子RR的collider參數運算
     public float Speed() {
         return wheelRR.radius * Mathf.PI * wheelRR.rpm * 60f / 1000f;
     }
 
     public float Rpm() {
         return wheelRL.rpm;
     }
 
     void FixedUpdate () {
         //鍵盤控制input的按住時間,運算加速度
         float scaledTorque = Input.GetAxis("Vertical") * torque;
 
         if(wheelRL.rpm < idealRPM)
             scaledTorque = Mathf.Lerp(scaledTorque/10f, scaledTorque, wheelRL.rpm / idealRPM );
         else 
             scaledTorque = Mathf.Lerp(scaledTorque, 0,  (wheelRL.rpm-idealRPM) / (maxRPM-idealRPM) );
 
         //開始運算前後排輪胎的轉向與轉速
         DoRollBar(wheelFR, wheelFL);
         DoRollBar(wheelRR, wheelRL);
 
         //輪胎左轉右轉鍵盤輸入
         wheelFR.steerAngle = Input.GetAxis("Horizontal") * turnRadius;
         wheelFL.steerAngle = Input.GetAxis("Horizontal") * turnRadius;
 
         //開始控制每個輪胎的運動方向
         wheelFR.motorTorque = driveMode==DriveMode.Rear  ? 0 : scaledTorque;
         wheelFL.motorTorque = driveMode==DriveMode.Rear  ? 0 : scaledTorque;
         wheelRR.motorTorque = driveMode==DriveMode.Front ? 0 : scaledTorque;
         wheelRL.motorTorque = driveMode==DriveMode.Front ? 0 : scaledTorque;
 
         //鍵盤控制Wheel Collider
         if(Input.GetButton("Fire1")) {
             wheelFR.brakeTorque = brakeTorque;
             wheelFL.brakeTorque = brakeTorque;
             wheelRR.brakeTorque = brakeTorque;
             wheelRL.brakeTorque = brakeTorque;
         }
         else {
             wheelFR.brakeTorque = 0;
             wheelFL.brakeTorque = 0;
             wheelRR.brakeTorque = 0;
             wheelRL.brakeTorque = 0;
         }
     }
 
     //輪胎轉動運算函式
     void DoRollBar(WheelCollider WheelL, WheelCollider WheelR) {
         WheelHit hit;
         float travelL = 1.0f;
         float travelR = 1.0f;
         
         bool groundedL = WheelL.GetGroundHit(out hit);
         if (groundedL)
             travelL = (-WheelL.transform.InverseTransformPoint(hit.point).y - WheelL.radius) / WheelL.suspensionDistance;
         
         bool groundedR = WheelR.GetGroundHit(out hit);
         if (groundedR)
             travelR = (-WheelR.transform.InverseTransformPoint(hit.point).y - WheelR.radius) / WheelR.suspensionDistance;
         
         float antiRollForce = (travelL - travelR) * AntiRoll;
         
         if (groundedL)
             GetComponent<Rigidbody>().AddForceAtPosition(WheelL.transform.up * -antiRollForce,
                                          WheelL.transform.position); 
         if (groundedR)
             GetComponent<Rigidbody>().AddForceAtPosition(WheelR.transform.up * antiRollForce,
                                          WheelR.transform.position); 
     }
 
 }
 

小結

要在Unity中模擬出真實車輛移動的狀態,就必須要使用到本篇所介紹的Wheel Collider,因為他這邊所有的Componment係項都是有經過物理運算以及Unity的Project Setting中重力的交互才顯示出每一個Frame的動態效果,雖然參數是有點難懂,但大家可以透過Try Test來感受每個數值變化所帶來的汽車移動效果。而有關程式的部分其實可以先略過,大家只需要知道哪個坑要丟入哪個對應的物件即可,漫漫長路,總有一天會講的更深入的。

Reference:https://docs.unity3d.com/Manual/class-WheelCollider.html

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *