Unity版本2020.3.32f1c1
目錄
Ray
RaycastHit
Physics.Raycast()
RaycastHit[]
??Layer
應用
1.對Bad層級的物體進行著色
2.從相機發(fā)射射線與地面進行射線交互
3.運動的物體在場景中進行避障
總結(jié)
參考資料
Ray
原理是發(fā)射一條射線,傳入起始點和起始方向當做射線的起點和方向。
Ray ray = new Ray(transform.position, transform.forward);
在OnDrawGizmos()函數(shù)中畫出來
private void OnDrawGizmos()
{
Ray ray = new Ray(transform.position, transform.forward);
Gizmos.color = Color.blue;
Gizmos.DrawRay(ray);
}
RaycastHit
之后我們在場景中添加兩個包含Collider的物體,我希望其中一個物體發(fā)出射線可以感知到另一個物體。Unity中通過RaycastHit結(jié)構(gòu)體來存儲射線的交互信息,結(jié)構(gòu)如下所示:
Physics.Raycast()
Physics.Raycast()返回true,可以用它來表示射線是否與游戲?qū)ο蟀l(fā)生交互.Physics.Raycast一共有16個重載方法,可以按需選擇。
public static bool Raycast(Ray ray, out RaycastHit hitInfo, [Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);?
上面的參數(shù)分別是射線,射線交互結(jié)構(gòu)體,檢測的最大距離(默認最大),層模板(默認所有),查詢觸發(fā)器交互(默認全局)。
如果設置了LayerMask參數(shù)的話,射線只會和游戲?qū)ο笫沁@個Layer的交互,其他的游戲?qū)ο蟛粫c射線發(fā)生交互;QueryTriggerInteraction默認參數(shù)表示查詢使用全局 Physics.queriesHitTriggers 設置,還有兩個可選值,Ignore表示忽略,當游戲?qū)ο蟮腃ollider組件下的Is Trigger被勾選后,射線檢測也將不會與其交互;Collider參數(shù)表示始終報告觸發(fā)器命中。
if (Physics.Raycast(ray, out hit,Mathf.Infinity,badMask,QueryTriggerInteraction.Ignore))
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, hit.point);
}
RaycastHit[]
除了聲明單個RaycastHit外,還可以設置RaycastHit[]數(shù)組,Physcis.RaycastAll可以獲得所有的與射線交互的信息,這里我傳入了第三個參數(shù)LayerMask,將下圖中紅框內(nèi)的物體的層級設置為了badMask,這樣射線檢測只會與這個層級的物體發(fā)生交互,最后打印出了三個物體的名稱,以及RaycastHit[]數(shù)組的大小。
RaycastHit[] hits;
hits = Physics.RaycastAll(ray,Mathf.Infinity,badMask);
for (int i = 0; i < hits.Length; i++)
{
Debug.Log(hits[i].collider.gameObject.name);
}
Debug.Log(hits.Length);
?Layer
?在寫的時候發(fā)現(xiàn)從不同地方獲取到的LayerMask的int值不同。
[SerializeField] private LayerMask badMask這樣通過面板獲得的值是2^value ,value是在Unity面板中Layer的數(shù)值,插一嘴Layer中用四個字節(jié)也就是32位來表示,每一個Layer占據(jù)其中一位,如此來說badMask.value返回的就是十進制表示的數(shù);通過結(jié)構(gòu)體hit.collider.gameObject.layer獲得的就是上文中說的value,也就是占據(jù)哪一位的數(shù)值。
如果想要比較二者是否相同,需要進行轉(zhuǎn)換:
if (Mathf.Pow(2,(hit.collider.gameObject.layer)) == badMask.value)
應用
1.對Bad層級的物體進行著色
看效果圖,有的沒有被著色,是因為被前面的對象遮住了,一個解決辦法是順帶更改前面對象的層級,讓它不再被射線交互。
public class Sphere : MonoBehaviour
{
[SerializeField] private Material recordBad;
[SerializeField] private Material originBad;
[SerializeField] private LayerMask badMask;
private void OnDrawGizmos()
{
Ray ray = new Ray(transform.position, transform.forward);
Gizmos.color = Color.blue;
//Gizmos.DrawRay(ray);
RaycastHit hit;
Gizmos.color = Color.blue;
Gizmos.DrawLine(transform.position, transform.TransformPoint(Vector3.forward * 10));
//Gizmos.color = Color.black;
//Gizmos.DrawLine(transform.position, Vector3.forward);
RaycastHit[] hits;
hits = Physics.RaycastAll(ray,Mathf.Infinity,badMask);
for (int i = 0; i < hits.Length; i++)
{
Debug.Log(hits[i].collider.gameObject.name);
}
Debug.Log(hits.Length);
if (Physics.Raycast(ray, out hit,Mathf.Infinity,badMask,QueryTriggerInteraction.Ignore))
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, hit.point);
hit.collider.gameObject.GetComponent<Renderer>().material = recordBad;
}
}
}
2.從相機發(fā)射射線與地面進行射線交互
Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, ground))
{
Vector3 point = hit.point;
controller.LookAt(point);
}
public void LookAt(Vector3 lookPoint)
{
Vector3 heightCorrectedPoint = new Vector3(lookPoint.x, transform.position.y, lookPoint.z);
transform.LookAt(heightCorrectedPoint);
}
還有一種方式是通過Plane來接收射線,返回的distance表示沿射線與平面相交的距離。如果射線平行于平面,函數(shù)返回false
并設置enter
為零。如果射線指向與平面相反的方向,則函數(shù)返回false
并設置enter
為沿射線的距離(負值)。
Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);
float distance;
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
if (groundPlane.Raycast(ray, out distance))
{
Vector3 point = ray.GetPoint(distance);
//Debug.DrawLine(ray.origin, point, Color.red);
controller.LookAt(point);
}
射線檢測
3.運動的物體在場景中進行避障
以物體為圓心,規(guī)定半徑和生成的點的數(shù)量,近似以點來近似球表面
public static class BoidHelper {
const int numViewDirections = 300;
public static readonly Vector3[] directions;
static BoidHelper () {
directions = new Vector3[BoidHelper.numViewDirections];
float goldenRatio = (1 + Mathf.Sqrt (5)) / 2;
float angleIncrement = Mathf.PI * 2 * goldenRatio;
for (int i = 0; i < numViewDirections; i++) {
float t = (float) i / numViewDirections;
//對應二維的半徑R
float inclination = Mathf.Acos (1 - 2 * t);
float azimuth = angleIncrement * i;
//球坐標轉(zhuǎn)直角坐標
float x = Mathf.Sin (inclination) * Mathf.Cos (azimuth);
float y = Mathf.Sin (inclination) * Mathf.Sin (azimuth);
float z = Mathf.Cos (inclination);
directions[i] = new Vector3 (x, y, z);
}
}
}
Vector3 ObstacleRays()
{
rayDirections = BoidHelper.directions;
if (rayDirections != null)
{
flag = true;
}
for (int i = 0; i < rayDirections.Length; i++)
{
Vector3 dir = cachedTransform.TransformDirection(rayDirections[i]);
Ray ray = new Ray(position, dir);
if (!Physics.SphereCast(ray, settings.boundsRadius, settings.collisionAvoidDst, settings.obstacleMask))
{
return dir;
}
}
return forward;
}
void OnDrawGizmosSelected()
{
if (flag)
{
DrawGizmos();
}
}
void DrawGizmos()
{
Debug.LogFormat("進入DraGizmos");
Debug.LogFormat("進入DraGizmos Flag");
Gizmos.color = Color.red;
foreach (var go in rayDirections)
Gizmos.DrawSphere(position + go, 0.02f);
Gizmos.color = Color.green;
foreach (var go in rayDirections)
{
Vector3 dir = cachedTransform.TransformDirection(go) * SpherePointsRadius;
Gizmos.DrawSphere(position + dir, radius);
}
}
總結(jié)
- 想要一個物體被射線檢測到,就必須加上Collider組件,Is Trigger并不影響射線檢測
- 生成一個射線需要五個參數(shù),起始點,方向,碰撞信息結(jié)構(gòu)體,范圍距離,檢測層
- 起始點一般使用transform.position來表示
- 方向一般使用transform.forward,表示當前物體正前方
- 碰撞信息使用RaycastHit結(jié)構(gòu)體來存貯,需要事先聲明
- 檢測范圍是float型,可不寫,默認無限長
- 檢測層可不寫,默認全檢測
- 如果你使用Debug.DrawLine()畫了一條線而沒有顯示出來,不妨看看Gizmos有沒有被關(guān)閉
- Raycast返回值是Bool,而RaycastAll返回值則是RaycastHit結(jié)構(gòu)體數(shù)組
- 混淆點
- Ray是一個類,表示射線
- RaycastHit是一個結(jié)構(gòu)體,記錄射線的碰撞信息
- Raycast和RaycastAll是函數(shù),使用射線來檢測碰撞,通過Physics來調(diào)用
參考資料
夢小天幼:詳解Unity中的射線與射線檢測文章來源:http://www.zghlxwxcb.cn/news/detail-725477.html
Coding Adventure: Boids文章來源地址http://www.zghlxwxcb.cn/news/detail-725477.html
到了這里,關(guān)于Unity 的射線檢測的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!