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;
}
}
ゲームビューでは赤い球だけが表示されます。
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