Unity - Ray射線檢測

一:射線

Ray射線

定義:射線是一條從原點出發,沿某一方向運動的無限直線。

//創建一條初始位置爲startPos,方向爲dir的一條射線
Ray ray = new Ray (startPos, dir);

//創建一條從攝像機通過屏幕點的光線。
//得到的光線在世界空間中,從相機的近平面開始,經過屏幕上的(x,y)像素座標(位置)。z是忽略。
Ray camerRay = Camera.main.ScreenPointToRay (Input.mousePosition);

RaycastHit : 用於存儲發射射線後產生的碰撞信息。

常用的成員變量如下:

  • collider 與射線發生碰撞的碰撞器
  • distance 從射線起點到射線與碰撞器的交點的距離
  • normal 射線射入平面的法向量
  • point 世界空間中射線與碰撞體的交點的座標(Vector3對象)

具體的可以參考官方文檔

二:線性投射

1.Raycast :

從起點開始,向最大距離的方向發射一條射線,進行碰撞檢測,但是僅能檢測到第一個被射線碰撞的物體。
可以選擇提供一個 LayerMask 來過濾掉不需要的碰撞,結合RaycastHit可以獲取到碰撞信息。

定義:

public static bool Raycast(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask);

有多個重載方法,具體參考官方文檔

示例代碼:

Ray ray = new Ray (startPos, dir);
RaycastHit hit;
Physics.Raycast(ray,out hit,distance);
//或者
Physics.Raycast(startPos,dir,out hit,distance);
Physics.Raycast(ray,out hit,distance,LayerMask.GetMask("ball"));

如圖:
在這裏插入圖片描述
ps: 對於射線的調試可以用 Debug.DrawRay() 或者 Gizmos 來繪製射線,方便調試。
如:Debug.DrawRay(startPos,dir,Color.red);

2.RaycastAll :

用法和Raycast差不多,區別在於可檢測射線路徑上的所有物體,返回一個RaycastHit[ ]
示例代碼:

//檢測所有
RaycastHit[] hits = Physics.RaycastAll(ray,distance);
RaycastHit[] hits = Physics.RaycastAll(ray,distance,LayerMask.GetMask("ball"));

3.Linecast:

如果有任何碰撞器與start和end之間的直線相交,返回true,否則false
示例代碼:

//兩點檢測: 如果有任何碰撞器與start和end之間的直線相交,返回true,否則false
bool isCrash = Physics.Linecast(startPos,endPos);
bool isCrash = Physics.Linecast(startPos,endPos,LayerMask.GetMask("ball"));

三:體型投射

1.BoxCast 立方體投射:

將方框沿射線投射,進行立方體範圍碰撞檢測,返回一個bool值。
和Raycast 一樣只能檢測第一個(ps : BoxCastAll 檢測所有, 用法和BoxCast類似)

定義:以center爲中心創建一個大小爲halfExtents的立方體線框,向direction方向發射,最大距離爲maxDistance,根據layerMask過濾碰撞體,並且通過queryTriggerInteraction指定此查詢是否應觸發觸發器,hitInfo接收碰撞信息

//以center爲中心創建一個半徑大小爲halfExtents的立方體線框,向direction方向發射,最大距離爲maxDistance,根據layerMask過濾碰撞體,並且通過queryTriggerInteraction指定此查詢是否應觸發觸發器,hitInfo接收碰撞信息
public static bool BoxCast(Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitInfo, [Internal.DefaultValue("Quaternion.identity")] Quaternion orientation, [Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

示例代碼:

Ray ray = new Ray (startPos, dir);
RaycastHit hit;
bool isCrash = Physics.BoxCast(startPos,transform.localScale/2,dir,out hit);
bool isCrash = Physics.BoxCast(startPos,transform.localScale/2,dir,out hit,transform.rotation,distance,LayerMask.GetMask("ball"));

如圖:
在這裏插入圖片描述

2.SphereCast 球體投射:

和立方體投射類似,範圍爲球體,返回一個bool值,單一檢查。(SphereCastAll:檢測所有,返回RaycastHit[])
定義:以origin爲中心創建一個半徑爲radius的球體線框,向direction方向發射,最大距離爲maxDistance,根據layerMask過濾碰撞體,並且通過queryTriggerInteraction指定此查詢是否應觸發觸發器。

public static bool SphereCast(Vector3 origin, float radius, Vector3 direction, out RaycastHit hitInfo, [Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

示例代碼:

Ray ray = new Ray (startPos, dir);
RaycastHit hit;
bool isHit = Physics.SphereCast (startPos, transform.localScale.x/2, dir, out hit, m_MaxDistance);

演示:
在這裏插入圖片描述

3.CapsuleCast 膠囊體投射:

和上面兩種類似,檢測範圍爲膠囊體,返回一個bool值,單一檢查。(CapsuleCastAll:檢測所有,返回RaycastHit[])
定義:point1膠囊體頂端的球體中心,point2膠囊體末端的球體中心,半徑爲radius,向direction方向發射,最大距離爲maxDistance,根據layerMask過濾碰撞體,並且通過queryTriggerInteraction指定此查詢是否應觸發觸發器。

public static bool CapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitInfo, [Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

示例代碼:

RaycastHit hit;
bool isHit = Physics.CapsuleCast(point1, point2,radius, direction, out hit, maxDistance, layerMask, queryTriggerInteraction);

四:相交檢測

注意:"相交檢測” 每個方法都有對應的 “無內存分配” 方法,每次調用該方法時都是讀取緩存,不會重新分配內存,也就是說不會產生過多的內存垃圾。實際應用中也儘量採用“無內存分配”方法,可以提高一定性能。

比如:
OverlapBox 對應的 “無內存分配” 方法:OverlapBoxNonAlloc
OverlapSphere 對應的 “無內存分配” 方法:OverlapSphereNonAlloc
OverlapCapsule 對應的 “無內存分配” 方法:OverlapCapsuleNonAlloc

這些用法區別不大,詳情可以查看官網

1.OverlapBox 相交立方體:

用於檢測與立方體碰撞的所有collider信息。

**定義:以center爲中心創建一個半徑爲halfExtents的正立方體,通過layerMask過濾不需要的collider。返回一個collider集合 Collider[] **

public static Collider[] OverlapBox(Vector3 center, Vector3 halfExtents, Quaternion orientation, int layerMask);

演示:
在這裏插入圖片描述

2.OverlapSphere 相交球:

用於檢測與球體碰撞的所有collider信息。

**定義:以center爲中心創建一個半徑爲radius的球體,通過layerMask過濾不需要的collider。返回一個collider集合 Collider[] **

public static Collider[] OverlapSphere(Vector3 position, float radius, [Internal.DefaultValue("AllLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

3.OverlapCapsule 相交膠囊體:

用於檢測與膠囊體碰撞的所有collider信息。
和以上類似

定義:

public static int OverlapCapsuleNonAlloc(Vector3 point0, Vector3 point1, float radius, Collider[] results, [Internal.DefaultValue("AllLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

五:校驗檢測

相交檢測類似,區別在於該類型方法 校驗是否發生了碰撞 ,返回的是bool值,而不是碰撞體信息集合,相對於性能較好。(ps:也會校驗自身的collider)

1.CheckBox 校驗立方體:

校驗該立方體是否與其他collider重疊。返回bool值

定義:

public static bool CheckBox(Vector3 center, Vector3 halfExtents, Quaternion orientation = Quaternion.identity, int layermask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

2.CheckSphere 校驗球:

校驗該是否與其他collider重疊。返回bool值

定義:

public static bool CheckSphere(Vector3 position, float radius, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

3.CheckCapsule 校驗膠囊體:

校驗該立方體是否與其他collider重疊。返回bool值

定義:

public static bool CheckCapsule(Vector3 start, Vector3 end, float radius, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

IgnoreCollision 忽略碰撞:

使碰撞檢測系統忽略collider1和collider2之間的所有碰撞。
這對於防止投射物與發射它們的物體發生碰撞是很有用的。

public static void IgnoreCollision(Collider collider1, Collider collider2, bool ignore = true);

六:調試技巧:

一般有兩種方法:

1.Debug.DrawRay:繪製一條射線。
示例:

//start:起點,dir:射線的方向和長度, red:顏色
Debug.DrawRay(start,dir,Color.red);

2. Gizmos:用於在場景視圖中提供可視化調試或設置幫助。(以上的演示動態圖就是通過該方法繪製的)

示例:

 void OnDrawGizmos () {
 //設置顏色
 Gizmos.color = Color.red;
 //繪製射線
 Gizmos.DrawRay (transform.position, transform.forward * distance);
 //繪製立方體線框
 Gizmos.DrawWireCube (transform.position + transform.forward * distance, transform.localScale);
}

最後

引用網友HONT的性能測試總結:

射線和線段的開銷非常小,可以忽略。

性能消耗順序:

從投射物來看: Box < Sphere < Capsule
從投射方法來看: CheckXXX < OverlapXXX < XXXCast

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