在Unity中使用层和位掩码与Raycast

Pro*_*mer 4 c# bitmask unity-game-engine raycasting

Unity的Raycast函数有一个参数可用于光线投射到特定的GameObject.您还可以使用该参数来忽略特定的GameObject.

例如,Raycast功能:

public static bool Raycast(Vector3 origin, Vector3 direction, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);
Run Code Online (Sandbox Code Playgroud)

layerMask参数用于指定哪些对象应该/不应该接收光线投射.


1.如何光线投射到名为"立方体"的图层中的特定 GameObject?

2.如果你在场景中有10个 GameObjects,但是你只想光线投射到2个 GameObjects并忽略其余的那些?你是怎样做的?

假设那些对象的层是"立方体"和"球体".

3.如果你想要对所有 GameObjects 进行光线投射但忽略1,那该怎么办?

假设要忽略的GameObject位于"立方体"层中.

4.如果你想要对所有 GameObjects 进行光线投射但忽略2个(多个)GameObjects,那该怎么办?

同样,要忽略的层是"立方体"和"球体"层.

Pro*_*mer 20

Raycast我看到的大多数问题使用Layermask不正确.虽然它运气很好,但是当他们真正想要从中排除GameObject时,它们通常会遇到问题Raycast.

这个答案是为了涵盖一个人在执行光线投射时想要使用Layer来过滤GameObjects的所有场景.

1.如何光线投射到名为"立方体"的图层中的特定 GameObject?

首先,您使用LayerMask.NameToLayer("cube")将图层名称转换为图层编号.如果图层不存在,则LayerMask.NameToLayer返回该函数-1.您必须在执行任何图层按位操作之前检查此项.

Raycast到特定图层(仅限"立方体"):

//Convert Layer Name to Layer Number
int cubeLayerIndex = LayerMask.NameToLayer("cube");

//Check if layer is valid
if (cubeLayerIndex == -1)
{
    Debug.LogError("Layer Does not exist");
}
else
{
    //Calculate layermask to Raycast to. (Raycast to "cube" layer only)
    int layerMask = (1 << cubeLayerIndex);

    Vector3 fwd = transform.TransformDirection(Vector3.forward);

    //Raycast with that layer mask
    if (Physics.Raycast(transform.position, fwd, 10, layerMask))
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

上面例子中最重要的部分是int layerMask = (1 << cubeLayerIndex);.

为了简化这个答案,我不会检查其余答案的错误.


2.如果你在场景中有10个 GameObjects,但是你只想光线投射到2个 GameObjects并忽略其余的那些?你是怎样做的?

假设那些对象的层是"立方体"和"球体".

Raycast到"立方体"和"球体"层并忽略其余部分:

//Convert Layer Name to Layer Number
int cubeLayerIndex = LayerMask.NameToLayer("cube");
int sphereLayerIndex = LayerMask.NameToLayer("sphere");

//Calculate layermask to Raycast to. (Raycast to "cube" && "sphere" layers only)
int layerMask = (1 << cubeLayerIndex) | (1 << sphereLayerIndex);
Run Code Online (Sandbox Code Playgroud)

3.如果你想要对所有 GameObjects 进行光线投射但忽略1,那该怎么办?

假设要忽略的GameObject位于"立方体"层中.

Raycast给所有人但忽略了"立方体"层:

//Convert Layer Name to Layer Number
int cubeLayerIndex = LayerMask.NameToLayer("cube");

//Calculate layermask to Raycast to. (Ignore "cube" layer)
int layerMask = (1 << cubeLayerIndex);
//Invert to ignore it
layerMask = ~layerMask;
Run Code Online (Sandbox Code Playgroud)

4.如果你想要对所有 GameObjects 进行光线投射但忽略2个(多个)GameObjects,那该怎么办?

同样,要忽略的层是"立方体"和"球体"层.

Raycast对所有人都忽略了"立方体"和"球体"层:

//Convert Layer Name to Layer Number
int cubeLayerIndex = LayerMask.NameToLayer("cube");
int sphereLayerIndex = LayerMask.NameToLayer("sphere");

//Calculate layermask to Raycast to. (Ignore "cube" && "sphere" layers)
int layerMask = ~((1 << cubeLayerIndex) | (1 << sphereLayerIndex));
Run Code Online (Sandbox Code Playgroud)

要么

//Convert Layer Name to Layer Number
int cubeLayerIndex = LayerMask.NameToLayer("cube");
int sphereLayerIndex = LayerMask.NameToLayer("sphere");

//Calculate layermask to Raycast to. (Ignore "cube" && "sphere" layers)
int layerMask = (1 << cubeLayerIndex);
layerMask |= (1 << sphereLayerIndex);
layerMask |= (1 << otherLayerToIgnore1);
layerMask |= (1 << otherLayerToIgnore2);
layerMask |= (1 << otherLayerToIgnore3);
//Invert to ignore it
layerMask = ~layerMask;
Run Code Online (Sandbox Code Playgroud)

最后,如果您知道图层索引/编号,则无需使用该LayerMask.NameToLayer功能.只需在那里插入那个图层索引.例如,让我们将光线投射到索引#9中的"立方体"图层.你可以做到int layerMask = (1 << 9);.

请参阅" 图层"手册以阅读有关此主题的更多信息.

  • @MohammadFaizanKhan你问过如何"只为一个特定的GameObject"进行光线投射.你的问题已经是关于SO的许多**问题的重复,包括我以前回答过的问题(甚至没有指望这个问题).我可以将它标记为[重复](http://stackoverflow.com/questions/31920743/raycasting-only-to-a-particular-object),但由于类似的问题(例如排除)被提出并被忽略,我决定根据提出的问题解释所有可能的方法.帖子用线条分隔,因此更容易找到您要找的内容. (2认同)