在 Unity 中将图层和位掩码与光线投射一起使用

Using Layers and Bitmask with Raycast in Unity

Unity 的 Raycast 函数有一个参数,您可以使用该参数将光线投射到特定的 GameObject。您还可以使用该参数来忽略特定的游戏对象。

例如 Raycast 函数:

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

layerMask 参数用于指定哪些对象 should/should 不接收光线投射。


1。如何将光线投射到位于名为 "cube" 的层中的 特定 游戏对象?

2。如果场景中有 10 个游戏对象,但您只想将光线投射到 2 怎么办? GameObjects 并忽略其余部分?你是怎么做到的?

假设那些 Object 的图层是 "cube" 和 "sphere"。

3。如果你想光线投射到 all GameObjects 但忽略 1.

怎么办

假设要忽略的游戏对象在 "cube" 层中。

4。如果你想光线投射到 所有 个游戏对象但忽略 2(多个)游戏对象怎么办。

同样,要忽略的图层是 "cube" 和 "sphere" 图层。

我看到的大多数 Raycast 问题都错误地使用了 Layermask。虽然它对他们有用,但他们通常 运行 当他们真正想要从 Raycast.

中排除一个游戏对象时会遇到问题

这个答案是为了涵盖人们在执行光线投射时想要使用图层来过滤游戏对象的所有场景。

1.How do you raycast to a particular GameObject which is in a layer called "cube"?

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

光线投射到特定层(仅"cube"):

//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))
    {

    }
}

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

为了使这个答案简短,我不会检查其余答案的错误。


2.What if you have 10 GameObjects in the scene but you only want to raycast to just 2 GameObjects and ignore the rest? How do you do that?

Let's say that those Object's layers are "cube" and "sphere".

光线投射到 "cube" 和 "sphere" 层并忽略其余部分:

//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);

3.What if you want to raycast to all GameObjects but ignore 1.

Let's say that the GameObject to ignore is in the "cube" layer.

向所有人投射光线,但忽略 "cube" 层:

//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;

4.What if you want to raycast to all GameObjects but ignore 2(multiple) GameObjects.

Again, the layers to ignore are the "cube" and "sphere" layers.

对所有人进行光线投射,但忽略 "cube" 和 "sphere" 层:

//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));

//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;

最后,如果知道图层index/number,就没有必要使用LayerMask.NameToLayer功能了。只需在此处插入该图层索引即可。例如,我们将光线投射到索引 #9 中的 "cube" 层。你可以做 int layerMask = (1 << 9);.

请参阅 Layers 手册以了解有关此主题的更多信息。

添加到@Programmer 的综合答案中...

1. How do you raycast to a particular GameObject which is in a layer called "cube"?

如果你想Raycast看看你是否击中了一个特定的对象,调用object .collider.Raycast(...).

object 可以是 GameObject 或您的 MonoBehaviour 派生脚本 (this)。