如何检测相机 FOV 内的所有游戏对象? Unity3D

How to detect all GameObjects within the Camera FOV? Unity3D

我想检测由 "Wall_[0-24]" 标记的所有游戏对象,它们都在相机 FOV 内。我已经尝试过 Raycasting,但因为它只是一条光线,所以它不会同时捕捉到多个物体。 我试过这个:

void Update() {
    GameObject walls = GameObject.FindGameObjectWithTag ("Wall");
    Renderer[] renders = walls.GetComponentsInChildren<Renderer> ();

    for (int i = 1; i < renders.Length; i++) {
        if (walls.GetComponentInChildren<Renderer> ().isVisible) {
            Debug.Log (renders[i] + " is detected!");
        } else {
            Debug.Log ("Nothing's detecetd!");
        }
    }
}

我得到的只是每一面墙一次又一次 - 并不真正取决于相机的位置。当我的相机沿着特定路径移动时,可见的墙壁应该会发生变化。在图像中,绿色部分可见,红色部分 不再 (因为相机已经通过它们)。

那么我如何通过这个特定的相机实现所有可见墙的输出

感谢您的帮助!

第 1 步:Calculate the camera's frustum planes.

第 2 步:Test each wall's collider against them,该页面上的示例脚本几乎包含您需要的一切。

如果对象位于平面定义的体积内,则它对相机可见(并且 TestPlanesAABB(...) returns 为真),否则不可见。

如果您想知道某个对象是否可以从 "camera" 中看到(也就是说,不是相机组件,而是一个类似于安全摄像头但不进行任何实际渲染的对象),可以从任意点 (Vector3)、视图方向 (Vector3) 和视野(比率,作为浮点数)计算平面。我手头没有我写的代码,但如果需要可以拿来。

这里的技巧是您是要检测该游戏对象的第一个可见 部分,还是要从对象的中心 'detect' 检测它。

如果您想对可见部分执行此操作,将脚本附加到这些对象以检查可见性可能会更简单。

如果您对 "detecting" 满意,一旦中心可见,您就可以通过相机完成。

无论哪种方式,我要做的第一件事就是使用 GameObject。 FindGameObjectsWithTag。 FindGameObjectsWithTag

然后,检查每个 Renderer.isVisible。 Renderer is Visible

您可以通过检查对象是否在相机后面来进一步优化它,首先通过它的变换,然后再检查渲染器,因为这是一个更昂贵的操作。
Is that transform behind me?

如果这些不能解决您的问题,请告诉我们更多关于您最终希望实现的目标。

编辑:根据您的新编辑,我认为您需要改用 Raycast All,

RaycastAll

使用Draco18s',下面是如何实现他说的。

创建一个新脚本并将其命名为 CheckWalls 并附上以下代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckWalls : MonoBehaviour
{
    Renderer[] renderers;

    void Awake ()
    {
        GameObject walls = GameObject.FindGameObjectWithTag ("Wall");
        renderers = walls.GetComponentsInChildren<Renderer> ();
    }

    void Update() 
    {
        OutputVisibleRenderers(renderers);
    }

    void OutputVisibleRenderers (Renderer[] renderers)
    {
        foreach (var renderer in renderers)
        {
            // output only the visible renderers' name
            if (IsVisible(renderer)) 
            {
                Debug.Log (renderer.name + " is detected!");    
            }           
        }

        Debug.Log ("--------------------------------------------------");
    }

    private bool IsVisible(Renderer renderer) 
    {
        Plane[] planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);

        if (GeometryUtility.TestPlanesAABB(planes , renderer.bounds))
            return true;
        else
            return false;
    }
}