【Unity】CullingGroupでカメラから見えているかどうかを判定する

投稿者: | 2024-03-30

CullingGroupを使って、カメラからの可視性や距離を判定してみました。距離はLODのような距離幅のインデックスとして得られます。

概要

シーンに複数のSphereゲームオブジェクトを配置します。カメラから見えているかどうかによって色を変えてみます。

CullingGroupの設定

CullingGroupを使うには、CullingGroupをインスタンス化し、カメラとBoundingSphereを設定します。このカメラからのBoundingSphereの可視性を判定します。

    CullingGroup group;

    // シーンのゲームオブジェクト
    [SerializeField] MeshRenderer[] meshRenderers;

    BoundingSphere[] spheres;

    void Start()
    {
        // インスタンス化
        group = new CullingGroup();

        // カメラを設定
        group.targetCamera = Camera.main;

        // BoundingSphereの配列を初期化
        spheres = new BoundingSphere[meshRenderers.Length];

シーンに配置したSphereゲームオブジェクトのメッシュレンダラーをインスペクタでアタッチしています。各メッシュレンダラーを配列内のBoundingSphereのインスタンスと一つずつ対応させています。

        // ゲームオブジェクトの位置でBoundingSphereをインスタンス化
        for (int i = 0; i < meshRenderers.Length; i++)
        {
            spheres[i] = new BoundingSphere(meshRenderers[i].transform.position, 1f);
        }

        // BoundingSphereを設定
        group.SetBoundingSpheres(spheres);

        // BoundingSphereの個数を設定
        group.SetBoundingSphereCount(meshRenderers.Length);

メモリを解放

無効になったときにCullingGroup.DisposeメソッドでCullingGroupをクリーンアップしています。

    private void OnDisable()
    {
        group?.Dispose();
        group = null;
    }

onStateChanged

CullingGroup.onStateChangedにコールバックを設定します。それぞれのBoundingSphereの可視性や距離が変わったときに呼び出されます。

        group.onStateChanged = StateChangedMethod;

引数のCullingGroupEvent構造体のメンバーからステートを確認できます。CullingGroupEvent.indexと同じインデックスのメッシュレンダラーを編集しています。表示に変わったら赤、非表示に変わったら青にマテリアルの色を変えてみました。

    private void StateChangedMethod(CullingGroupEvent evt)
    {
        if (evt.hasBecomeVisible)
        {
            meshRenderers[evt.index].material.color = Color.red;
        }
        if (evt.hasBecomeInvisible)
        {
            meshRenderers[evt.index].material.color = Color.blue;
        }
        
    }

ゲームビューでは赤い球だけが表示されます。

Gameビュー
Sceneビュー

BoundingSphereを移動

シーンのSphereゲームオブジェクトと一緒に、対応するBoundingSphereを移動させてみました。

    float elapsedTime;

    private void Update()
    {
        // 基準点を設定
        group.SetDistanceReferencePoint(group.targetCamera.transform.position);

        elapsedTime += Time.deltaTime;

        // Sphereゲームオブジェクトを移動
        meshRenderers[0].transform.position = new Vector3(Mathf.Cos(elapsedTime) *  5f, 4f, Mathf.Sin(elapsedTime) * 5f);
         
        // BoundingSphereの位置を更新
        spheres[0].position = meshRenderers[0].transform.position;

    }

キャラクターのカメラの後ろでは青に変わりました。

距離幅を取得

距離幅を配列で設定します。配列には各幅の最大の距離が含まれています。

        group.SetBoundingDistances(new float[] { 6f, 12f, 25f });

距離幅を測定するための基準底は動かないようです。CullingGroup.SetDistanceReferencePointメソッドで基準点としてカメラの位置を毎フレーム設定しました。また、可視性と距離幅によって色を変更します。

    private void Update()
    {
        // 基準点を設定
        group.SetDistanceReferencePoint(group.targetCamera.transform.position);

        // 可視性と距離幅によって色を変える
        for (int i = 0; i < meshRenderers.Length; i++)
        {
            if (group.IsVisible(i))
            {
                switch (group.GetDistance(i))
                {
                    case 0:
                        meshRenderers[i].material.color = Color.red;
                        break;
                    case 1:
                        meshRenderers[i].material.color = Color.yellow;
                        break;
                    case 2:
                        meshRenderers[i].material.color = Color.green;
                        break;
                    default:
                        meshRenderers[i].material.color = Color.black;
                        break;
                }
            }
            else
            {
                meshRenderers[i].material.color = Color.blue;
            }
        }        
    }
参考:
https://docs.unity3d.com/ja/2019.4/Manual/CullingGroupAPI.html
https://docs.unity3d.com/ja/2018.4/ScriptReference/CullingGroupEvent.html
https://docs.unity3d.com/ja/2018.4/ScriptReference/CullingGroup.SetBoundingDistances.html

コメントを残す

メールアドレスが公開されることはありません。