【Unity】CullingGroupでカメラから見えていない位置にオブジェクトを配置する

投稿者: | 2024-04-01

CullingGroupを使って、カメラから見ていない位置を検索してゲームオブジェクトをインスタンス化してみました。

概要

シーンに、配置位置を表すゲームオブジェクトを置きます。同じ位置にBoundingSphereを設定しCullingGroupでカメラからの可視性を判定をします。

CullingGroup.QueryIndicesメソッドを使って、カメラから見えていないBoundingSphereを簡単に検索できます。

カメラから見えていないところでゲームオブジェクトが出現します。

シーン

シーンにはSphereゲームオブジェクトを複数配置しています。ここにプレハブをインスタンス化します。

Sphereのメッシュレンダラーを無効にして非表示にしています。

スクリプト

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

public class InvisibleSpawner : MonoBehaviour
{
    // シーンのゲームオブジェクト
    [SerializeField] Transform[] spawnPoints;

    // プレハブ
    [SerializeField] MeshRenderer spherePrefab;
    
    CullingGroup cullingGroup;
    float elapsedTime;

    // Start is called before the first frame update
    void Start()
    {
        // CullingGroupをインスタンス化
        cullingGroup = new CullingGroup();

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

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

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

        // BoundingSphereの配列を設定
        cullingGroup.SetBoundingSpheres(spheres);

        // BoundingSphereの個数を設定
        cullingGroup.SetBoundingSphereCount(spheres.Length);
    }

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

    // Update is called once per frame
    void Update()
    {
        elapsedTime += Time.deltaTime;

        // 3秒ごとに処理
        if(elapsedTime >= 3f)
        {
            elapsedTime = 0f;

            // 結果のBoundingSphereインデックスの配列
            int[] resultIndices = new int[spawnPoints.Length];

            // 結果の個数
            int numResults = 0;

            // カメラから見えないBoundingSphereを検索
            numResults = cullingGroup.QueryIndices(false, resultIndices, 0);
        
            // 結果の個数が0なら終了
            if (numResults == 0) return;

            // 配列のなかからインデックスをランダムで一つ選ぶ
            var index = resultIndices[Random.Range(0, numResults)];

            // 同じインデックスの位置にプレハブをインスタンス化
            Instantiate(spherePrefab, spawnPoints[index].position,Quaternion.identity);
        }
    }
}

スクリプトにはシーンのゲームオブジェクトと配置するプレハブがアタッチされています。

CullingGroupの設定はCullingGroupでカメラから見えているかどうかを判定すると同じです。

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

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

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

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

        // BoundingSphereの配列を設定
        cullingGroup.SetBoundingSpheres(spheres);

        // BoundingSphereの個数を設定
        cullingGroup.SetBoundingSphereCount(spheres.Length);
    }

CullingGroupはクリーンアップされるようにしています。

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

Updateメソッドで3秒ごとにゲームオブジェクトを配置します。

        elapsedTime += Time.deltaTime;

        // 3秒ごとに処理
        if(elapsedTime >= 3f)
        {
            elapsedTime = 0f;

CullingGroup.QueryIndicesメソッドで、条件を指定してBoundingSphereを検索できます。引数にint型の配列を渡すと、条件に合致したBoundingSphereのインデックスが先頭から埋まります。残りの部分は初期値の0になっています。

条件に合うBoundingSphereの個数が返るので、インデックスの0と初期値を区別できます。

            // 結果のBoundingSphereインデックスの配列
            int[] resultIndices = new int[spawnPoints.Length];

            // 結果の個数
            int numResults = 0;

            // カメラから見えないBoundingSphereを検索
            numResults = cullingGroup.QueryIndices(false, resultIndices, 0);

結果の配列からランダムでインデックスを選びます。同じインデックスのゲームオブジェクトの位置にプレハブをインスタンス化しています。

            // 結果の個数が0なら終了
            if (numResults == 0) return;

            // 配列のなかからインデックスをランダムで一つ選ぶ
            var index = resultIndices[Random.Range(0, numResults)];

            // 同じインデックスの位置にプレハブをインスタンス化
            Instantiate(spherePrefab, spawnPoints[index].position,Quaternion.identity);

これでカメラから見えない位置にオブジェクトを配置できました。

参考:
https://docs.unity3d.com/ja/2019.4/Manual/CullingGroupAPI.html

コメントを残す

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