Unity Physics.Raycast 似乎无法正确检测到它击中的对象

Posted

技术标签:

【中文标题】Unity Physics.Raycast 似乎无法正确检测到它击中的对象【英文标题】:Unity Physics.Raycast does not seem to properly detect object it hit 【发布时间】:2017-05-31 07:41:31 【问题描述】:

我有一个从 UnityEngine.EventSystems 实现 IDragHandler 和 IDropHandler 的 GameObject。

在 OnDrop 中,我想检查这个对象是否被放在另一个对象前面。我正在使用 Physics.Raycast,但它只在某些情况下返回 true。我使用屏幕点到射线作为射线的方向,并将此变换作为 Raycast 射线的原点。

我的代码:

 public void OnDrop(PointerEventData eventData)
 
         var screenRay = Camera.main.ScreenPointToRay(new Vector3(eventData.position.x, eventData.position.y, 0.0f));
         var thisToObjectBehind = new Ray(transform.position, screenRay.direction);
         Debug.DrawRay(thisToObjectBehind.origin, thisToObjectBehind.direction, Color.yellow, 20.0f, false);
         RaycastHit hit;
         if (Physics.Raycast(thisToObjectBehind, out hit))
         
             Debug.LogFormat("Dropped in front of 0!", hit.transform);
         
 

我正在使用透视相机。当对象从屏幕/相机直接放在对象前面时,Physics.Raycast 有时会返回 true,但“命中”包含 this,而不是后面的对象。有时它返回假。这两个结果都不是预期的,这背后有一些物体应该可以进行 Raycast。

当物体落在摄像机视野外围的前方物体上时,Physics.Raycast 会成功找到后面的物体。

Debug ray 看起来不错,它是从我放下的对象绘制的,向后到它应该击中的对象。

【问题讨论】:

注意:如果我不使用 screenRay 设置 thisToObjectBehind = new Ray(transform.position, transform.forward * -1),Raycast 成功,所以碰撞器应该没有任何问题。但是,我不想将自己限制在必须面对镜头的情况下。 成功和失败的eventData值是多少? 你不需要LayerMask吗? Fredrik 是绝对正确的,层是问题。 【参考方案1】:

临时放置放置在 IgnoreRaycast 层中的对象解决了我的问题。这也意味着我可以跳过将光线的原点设置为 transform.position。

    public void OnDrop(PointerEventData eventData)
    
        // Save the current layer the dropped object is in,
        // and then temporarily place the object in the IgnoreRaycast layer to avoid hitting self with Raycast.
        int oldLayer = gameObject.layer;
        gameObject.layer = 2;

        var screenRay = Camera.main.ScreenPointToRay(new Vector3(eventData.position.x, eventData.position.y, 0.0f));
        RaycastHit hit;
        if (Physics.Raycast(screenRay, out hit))
        
            Debug.LogFormat("Dropped in front of 0!", hit.transform);
        

        // Reset the object's layer to the layer it was in before the drop.
        gameObject.layer = oldLayer;
    

编辑:由于性能原因,从代码 sn-p 中删除了 try/finally 块。

【讨论】:

不要使用 Unity 的 API 捕获异常。仅使用 C# IO 执行此操作。您不必要地使代码变慢,具体取决于您将该代码附加到多少游戏对象。只需做一个空检查。 最后尝试,没有捕获,同样糟糕吗?我只是想确保无论发生什么,我都会将游戏对象移回它之前所在的层,以避免在调用它之后出现奇怪的行为。 The JIT doesn't perform optimization on 'protected' / 'try' blocks 好的,谢谢!我将从答案中的代码块中删除 try/finally。

以上是关于Unity Physics.Raycast 似乎无法正确检测到它击中的对象的主要内容,如果未能解决你的问题,请参考以下文章

带有 LayerMask 的 Unity Physics.Raycast 不会检测图层上的对象。使用了位移,尝试了反相层,仍然没有任何效果

Physics.Raycast方法

unity区分点击在3D物体还是2D UI上

Unity:利用 射线Ray 检测物体

Unity3D_(API)射线检测

使用 Raycast 时出错