首页 > 解决方案 > 如何添加额外的相机,以便在我使用电影相机时使用脚本 onBecomeInvisible() 的对象不会被破坏?

问题描述

我认为我的标题很明显。由于统一的 onbecomeinv 功能,我有一些对象设置在它们不可见时被破坏。我正在使用电影中的虚拟相机/二维相机,所以现在不可见的物体正在被破坏,他们不应该这样做吗?我怎样才能做到这一点?

标签: unity3d

解决方案


第一个普遍的“问题”OnBecameVisibleOnBecameInvisible它是基于渲染的。这意味着即使一个对象已经离开了相机视图,它也有可能仍然与渲染相关(例如投掷阴影),因此可能并不总是像预期的那样表现。

其次,无法确切知道对象在哪个相机上变得(不)可见,而是意味着它对于场景中的(所有/)任何现有相机变得(不)可见。


您可以(大约)通过GeometryUtility.CalculateFrustumPlanesGeometryUtility.TestPlanesAABB

[SerializeField] private Renderer _renderer;
[SerializeField] private Camera _camera;

private void Awake ()
{
    if(!_camera) _camera = Camera.main;
    if(!_renderer) _renderer = GetComponent<Renderer>();
}

private void Update ()
{
    var planes = GeometryUtility.CalculateFrustumPlanes(_camera);

    if (!GeometryUtility.TestPlanesAABB(planes, _renderer.bounds))
    {
        Debug.Log($"{name} is outside of {_camera.name}'s camera frustum!", this);
        Destroy(gameObject);
    }
}  

当然,这种方法可以通过不让每个对象独立计算,而是使用通用控制器来改进。

在您的对象/预制件上有一个类

// Keeps track of existing instances of this component
// Provides a cached reference to the Renderer component
public class CheckVisibilityTarget : MonoBehaviour
{
    // Each instances will (un)register itself here
    private static readonly HashSet<CheckVisibilityTarget> _instances = new HashSet<CheckVisibilityTarget>();

    // public readonly access to all existing instances of this component
    // returns a copy of _instances
    public static HashSet<CheckVisibilityTarget> Instances =>  new HashSet<CheckVisibilityTarget>(_instances);

    // Reference this already in the Inspector
    [SerializeField] private Renderer _renderer;

    // public readonly access
    public Renderer Renderer => _renderer;

    private void Awake ()
    {
        // As fallback get it once on runtime
        if(!_renderer) _renderer = GetComponent<Renderer>();

        // Add yourself to the instances
        _instances.Add(this);
    }

    private void OnDestroy ()
    {
        // remove yourself from the instances
        _instances.Remove(this);
    }
}

然后如您所说的场景中的中央控制器

public class DestroyInvisibleTargets : MonoBehaviour
{
    // Reference this via the Inspector
    [SerializeField] private Camera _camera;

    private void Awake ()
    {
        // As fallback get it once on runtime
        if(!_camera) _camera = Camera.main;
    }

    private void Update ()
    {
        // Get the planes once per frame
        var planes = GeometryUtility.CalculateFrustumPlanes(_camera);

        // Check all existing instances whether they are still within the frustum
        foreach(var target in CheckVisibilityTarget.Instances)
        {
            if (!GeometryUtility.TestPlanesAABB(planes, target.Renderer.bounds))
            {
                Debug.Log($"{target.name} is outside of {_camera.name}'s camera frustum!", this);
                Destroy(target.gameObject);
            }
        }
    }
}

推荐阅读