首页 > 解决方案 > 检查游戏对象在当前相机上是否可见

问题描述

我一直在搜索堆栈溢出和互联网,试图寻找解决此问题的方法,每次我尝试使用 OnBecameVisible() 或 OnBecameInvisible() 或 TestPlanesAABB 来检查对象是否通过墙壁不可见时,相机仍然可以通过实心墙看到物体。

问题视频在这里: https ://youtu.be/3HiEugm6On8

正如你所看到的,如果我看着他,他会停止移动,如果我转身并且他“卸载”或“变得隐形”,他会靠近,但如果我绕过一个角落仍然看着他的方向,他会停止移动,因为如果我能看到他并且那里没有墙,这就是我要解决的问题

这是一个四处游荡的敌人,我希望他只有在我看不见他的情况下才移动,我认为这很简单,但可惜它似乎没有我想的那么简单

我当前的代码是基本的:

public bool IsSeen = false;

    public void OnBecameVisible()
    {
        Debug.Log("I can now see you");
        IsSeen = true;
    }

    public void OnBecameInvisible()
    {
        Debug.Log("I can't see you");
        IsSeen = false;
    }

这附加到我希望通过墙壁检测/不检测的对象上,我相信这会检查对象是否可以被我选择的相机看到。

有人对我如何解决/实现这一点有任何想法吗?

标签: unity3d

解决方案


如前所述,一般的“问题”Renderer.OnBecameVisible

请注意,当需要在场景中渲染对象时,它被认为是可见的。它可能实际上不会被任何相机看到,但仍需要为阴影进行渲染。此外,在编辑器中运行时,场景视图摄像机也会导致调用此函数

所以它对你不是真的有用。

有没有一种简单的方法来对整个屏幕进行光线投射?

不幸的是不是真的:/

您可以避免使用这种方法GeometryUtility.CalculateFrustumPlanes来获得相机截锥体的四个平面。然后你可以检查对象是否真的在视锥体内GeometryUtility.TestPlanesAABB

var cam = Camera.main;
var planes = GeometryUtility.CalculateFrustumPlanes(cam);
var objCollider =  GetComponent<Collider>();

if (GeometryUtility.TestPlanesAABB(planes, objCollider.bounds))
{
    Debug.Log("I am inside the camera frustrum!");
}
else
{
    Debug.Log("I am out of sight...");
}

但是,这仍然没有覆盖目标对象前面的任何其他对象,因此实际上覆盖了它。

您需要准确定义可见的含义(例如,网格的任何部分?对象的中心是否足以测试?等)。

例如,仅测试对象的中心,您可以使用Physics.Linecast类似的方法,例如

if (GeometryUtility.TestPlanesAABB(planes, objCollider.bounds))
{
    Debug.Log("I am inside the camera frustrum!");

    if(Physics.LineCast(cam.transform.position, objCollider.GetComponentInChildren<Renderer>().bounds.center, out var hit)
    {
        if(hit.gameObject != objCollider.gameObject)
        {
            Debug.Log("..but something else is in the way..");
        }
        else
        {
            Debug.Log("Now you see me, muhaha!");
        }
    }
}

如果您希望它更精确并且可以看到网格的任何部分的跟踪,那么它实际上会变得很棘手。根据您的需要,您需要对边界框的多个关键点(例如每个角、边缘的中心等)进行光线投射。


推荐阅读