Unity - 射線檢測


本文簡要分析了Unity中各類 射線檢測 的基本原理及用法,及不同檢測手段的性能對比。內容包括:

  • Ray 射線
  • RaycastHit 光線投射碰撞信息
  • Raycast 光線投射
  • BoxCast/SphereCast/CapsuleCast 體投射
  • OverlapBox/OverlapSphere/OverlapCapsule 相交體
  • OverlapBoxNonAlloc/OverlapSphereNonAlloc/OverlapCapsuleNonAlloc 無GC相交體
  • 常用射線Debug方法
  • GC消耗分析

博客園Unity - Raycast
項目地址Raycast - SouthBegonia


Ray 射線

  • 含義:官方解釋為一條無窮的線,開始於origin點,朝向direction方向(但是,根據項目驗證來看其默認長度為單位向量,只有對direction進行乘以倍率,才可實現延長射線,而非無窮)
  • 用法:
    • Ray ray = new Ray(transform.position,transform.forward):從物體中心創建一條指向前方的射線ray
    • Ray camerRay = Camera.main.ScreenPointToRay(Input.mousePosition):產生一條從攝像機產生、經過屏幕上光標的射線。當相機為perspective模式,射線在相機梯形視野內發散;若為orthoGraphic,則為垂直與相機面的直線段(見上圖)

RaycastHit 光線投射碰撞信息

  • 含義:取得從Raycast函數中得到的碰撞信息(注意不是collider哈,是包含collider信息)
  • 關鍵變量:point、collider、rigidbody、transform

檢測方法 - 線型檢測

Physics.Raycast 光線投射

  • 功能:在已有一條射線(也可無)的基礎上,使用射線(新建射線)進行一定距離內的定向檢測。可修改射線長度,限制其檢測的Layer層,並且可以得到射線檢測到的碰撞信息。但僅能檢測到第一個被射線碰撞的物體,后面的物體無法被檢測到
  • 用法:
    • Raycast(transform.position, Vector.forward, distance, LayerMask.GetMask("Enemy")): 從物體中心點起,朝向Vector3.forward方向發射一條射線,該射線長度為distance,射線可檢測到的層為Enemy層,返回bool類型
    • Raycast(transform.position, Vector.forward, distance, out RaycastHitInformation ,LayerMask.GetMask("Enemy")):從物體中心點起,朝向Vector3.forward方向發射一條射線,該射線長度為distance,將碰撞信息反饋到RaycastHitInformation上,射線可檢測到的層為Enemy層,返回bool類型
    • Raycast (MyRay, distance, LayerMash.GetMask("Enemy")):從已有的射線MyRay出發,長度延伸至distance,射線可檢測到的層為Enemy層,返回bool類型
    • Raycast (MyRay, out RaycastHitInformation, distance, LayerMask.GetMask("Enemy"))
  • 適用場合:配合相機坐標轉換實現各類交互

Physics.RaycastAll 所有光線投射

  • 功能:機理用法大致同Raycast,區別在於可檢測射線路徑上的所有物體返回RaycastHit[] 。其他帶All后綴的方法也同理
  • 用法:
    • RaycastHit[] hits = RaycastAll(Vector3.zero, Vector.forward, distance, LayerMask.GetMask("Enemy"))
    • RaycastHit[] hits = RaycastAll(MyRay, distance, LayerMash.GetMask("Enemy"))
  • 適用場合:穿透性檢測

Physics.Linecast 線段投射

  • 功能:建立某兩點之間的射線進行檢測,返回bool類型
  • 用法:
    • Linecast(startPos, endPos, LayerMask.GetMask("Enemy"))
    • Linecast(startPos, endPos, out RaycastHit, LayerMask.GetMask("Enemy"))
  • 適用場合:特定地點局部距離射線檢測

檢測方法 - 體型檢測

Physics.XXXCast 體投射

  1. BoxCast 立方體投射
    • 功能:檢測范圍是正立方,返回bool。但是該投射用法需要萬分小心,見下
    • 用法:BoxCast(originPos, halfExtents, direction, out RaycastHit, distance, LayerMask.GetMask("Enemy")):含義是在originPos點創建半徑halfBoxLength的立方體(Vector3型,代表為正立方體在三個方向上的大小,一般用localScale/2);以朝向direction方向的平面為起始面(另一面舍棄),移動distance距離,期間經過的區域即為檢測區域。(見下補充分析)
    • 適用場合:檢測目的地是否可抵達,從而判斷可移動性
  2. SphereCast 球體投射
    • 功能:擴展檢測范圍為球形,返回bool類型。
    • 用法:
      • SphereCast(originPos, radius, direction, out RaycastHit, distance, LayerMask.GetMask("Enemy")):含義是在originPos點創建半徑為radius的球體;以朝向direction方向的球面為起始面(另一面舍棄),移動distance距離,期間半球面經過的區域即為檢測區域。那么originPos到originPos+radius內的半球區域呢?答案是舍棄,用官方的話來說,是邊界而不是包圍體 。(立體結構:以左右球球心為軸線,建立半徑為radius、高為distance的圓柱體,左球挖去右半體積,右球添加右半體積)
      • SphereCast (Ray, radius, out RaycastHit, distance, LayerMask.GetMask("Enemy"))
  3. CapsuleCast 膠囊體投射
    • 功能:檢測范圍是膠囊體,返回bool
    • 用法:Physics.CapsuleCast(pos1, pos2, radius, direction, out RaycastHit, maxDistance, LayerMask.GetMask("Anchor")):機理和SphereCast類似,在pos1、pos2兩點創建半徑為0.5f的球體,以此作為膠囊體模型兩端;以朝向direction方向的半膠囊體面為起始面,移動maxDistance距離,期間該面經過的區域即為檢測區域。(注:maxDistance和上面的distance必須非0否則無用)
    • 項目示例:見下圖,pos1、pos2均為膠囊體兩球坐標,視角右側為forward,移動距離為0.1f,從實驗結果我們不僅可以直觀感受maxDistance的含義,更印證上面所說的 是邊界不是包圍體 ,代碼:Physics.CapsuleCast(pos1, pos2, 0.5f, Vector3.forward, out RaycastHit, 0.1f, LayerMask.GetMask("Anchor"))
  4. XXXCastAll 穿透投射
    • 功能:上述三種投射都只返回bool,只能檢測單個物體,但是All方法的可檢測射線上的所有物體,返回 RaycastHit[]產生GC極多


Physics.OverlapXXX 相交體

  1. OverlapBox 相交盒
    • 功能:檢測與正立方體接觸、重疊、或者處於其內的所有collider
    • 用法:Collider[] hits = OverlapBox(Pos, halfExtents, Quaternion.identity, LayerMask.GetMask("Enemy")):以Pos點為中心創建三維半徑halfExtents的正立方體,不對其進行旋轉,檢測層為Enemy
    • 適用場合:檢測掛載物體范圍內是否存在碰撞,常用方法
  2. OverlapSphere 相交球
    • 功能:檢測與球體接觸、重疊、或者處於其內的所有collider,即包圍體。但注意,自身collider也會被檢測到(下列Overlap方法都是)
    • 用法:Collider[] hits = Physics.OverlapSphere(Pos, radius, LayerMask.GetMask("Enemy")):以Pos為原點,創建半徑為radius的球形,檢測區域為整個球形包圍體(實心),檢測Enemy層上的物體,返回所有碰撞物體的collider而不是RaycastHit(注意:存在於球內部的物體也會被檢測到)
  3. OverlapCapsule 相交膠囊體
    • 功能:檢測與膠囊體接觸、重疊、或者處於其內的所有collider
    • 用法:Collider[] hits = OverlapCapsule(pos1, pos2, radius, LayerMask.GetMask("Enemy")):在pos1、pos2兩點創建半徑為radius的球體,加上中間部分組成膠囊體,檢測Enemy層

Physics.OverlapXXXNonAlloc 無GC相交體

  1. OverlapBoxNonAlloc 無GC相交盒
    • 功能:實現OverlapBox的所有功能,但是另傳遞進colliders[]返回相交物體數量,從而杜絕GC的產生
    • 用法:CollAmount = Physics.OverlapBoxNonAlloc(Pos, halfExtents, colliders, Quaternion.identity, LayerMask.GetMask("Enemy"))
  2. OverlapSphereNonAlloc 無GC相交球
    • 功能:參考上面
    • 用法:CollAmount = OverlapSphereNonAlloc(Pos, radius, colliders, LayerMask.GetMask("Enemy"))
  3. OverlapCapsuleNonAlloc 無GC相交膠囊體
    • 功能:參考上面
    • 用法:CollAmount = OverlapCapsuleNonAlloc(pos1, pos2, radius, colliders, LayerMask.GetMask("Enemy"))

Physics.CheckXXX 檢驗體

  1. CheckBox 檢驗盒
    • 功能:創建檢測盒,檢測是否被碰撞。較比與上面的檢測方法,該類方法特點在於檢驗是否發生了碰撞,而不是取得碰撞體信息,效率最高。注此方法同樣也會檢驗自身collider
    • 用法:IsOverlapAnyCollider = Physics.CheckBox(transform.position, transform.localScale / 2, Quaternion.identity, LayerMask.GetMask("Enemy")):在物體中心創建檢驗盒,一定大小,不旋轉,檢測Enemy層,若有檢測到碰撞則返回True
  2. CheckSphere 檢驗球
    • 功能:參考上面
    • 用法:IsOverlapAnyCollider = Physics.CheckSphere(transform.position, radius, LayerMask.GetMask("Enemy"))
  3. CheckCapsule 檢驗膠囊體
    • 功能:參考上面
    • 用法:IsOverlapAnyCollider = Physics.CheckCapsule(pos1, pos2,radius, LayerMask.GetMask("Enemy"))

Physics.IgnoreCollision 忽略碰撞

  • 功能:屏蔽兩個collider的碰撞,第三個參數為bool
  • 用法: IgnoreCollision (collider1, collider2, ignore)

DEBUG手段

  • 繪制線段
    • DrawLine(startPos, endPos, color):繪制一條從startPos到endPos點、顏色為color的線段
  • 繪制射線
    • DrawRay(startPos, direction, color):繪制一條從startPos出發,指向direction的、顏色color的射線(默認長度為單位向量,再乘以倍率即可邊長;在下一次繪制才會覆蓋上一次的射線)
    • Debug.DrawRay(startPos , direction, color, duration) :同理繪制一定方向射線,但射線持續時間為duration :
  • Gimos.DrawXXX方法
    • void OnDrawGizmos() { Gizmos.DrawCube(transform.position, transform.localScale );}

GC開銷問題

從上面對幾種檢測方法的分析及對比其返回值不難發現,不同方法產生GC情況相差甚遠,因此在工程項目上應該慎重使用。此處引用網友 HONT的測試作為GC情況參考:

  • 同方法下不同模型GC開銷:Box < Sphere < Capsule
  • 同模型下不同方法GC開銷:CheckXXX < OverlapXXX < XXXCast

參考


免責聲明!

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



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