Adaptive Probe Volumesを動的に変更する方法

# はじめに

従来のProbe Voumeより実装が簡単になったAdaptive Probe Volumes(次回以降APV)を使用してみた。しかし、参考記事が少なく、内容も実装のみが多かった。明るい部屋から暗い部屋にシーン実行の途中で変更したくても変え方が分からなかったが何とか実装できたので、同じようなことしたい人の手助けになれば嬉しい。また、徐々に変更も可能なので使えるところは多いと思う。

# 環境

Unity : 6000.0.26f1 (HDRP)
RenderPipline : HDRP

# 実装
適当なシーンを作成。今回はこのような感じ。4つのライトのうち、4つのライトがついている状態から3つが消える状態を作成予定。
![My project - OutdoorsScene - Windows, Mac, Linux - Unity 6 (6000.0.26f1)_ _DX12_ 2024_12_16 11_41_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/4189739e-7b5c-b55e-76f0-c18233955b8f.png)

:::note info
今回はAdaptiveProbeVolumesの導入はカット。導入方法は[こちら](https://qiita.com/asiram/items/e1d1f40b0702cc16114b)を参考に
:::

Edit -> ProjectSettings -> QualityのHDRP -> Lightingの欄のLightProbeLightのLightingScenarioとScenarioBlendingをオンに
![My project - OutdoorsScene - Windows, Mac, Linux - Unity 6 (6000.0.26f1) _DX12_ 2024_12_16 12_43_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/68426d96-8ba1-f59a-cbf3-be1926fe7d12.png)

そのようにすると、ライティングのウィンドウにLightingScenarioの欄が追加されている。**Bright**と**Dark**のシナリオを追加。

![My project - OutdoorsScene - Windows, Mac, Linux - Unity 6 (6000.0.26f1)_ _DX12_ 2024_12_16 12_48_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/84d0cc95-91f8-77a5-5ae3-2dd45b5ad506.png)

Brightをアクティブにし、シーン内のライトをオンにしてGenerate Lighting。次に、Darkをアクティブにし、シーン内のライトをオフにして同じことを。

![My project - OutdoorsScene - Windows, Mac, Linux - Unity 6 (6000.0.26f1)_ _DX12_ 2024_12_16 16_55_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/b4775e46-ec96-6130-a96d-ba21dd414ba5.png)

アクティブを変更するとベイク結果を簡単に変更できるようになる。
![無題の動画 ‐ Clipchampで作成 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/57369a4e-3953-29d6-7e9e-3efd636771bd.gif)

次に、動的に変更を実装
LightingManager.cs作成。はじめに全体を
```c#:LightingManager.cs
using UnityEngine;
using UnityEngine.Rendering;

public class LightingManager : MonoBehaviour
{
    private ProbeReferenceVolume probeReferenceVolume;
    [SerializeField] private string[] scenarioKey;
    private int currentNum = 0;
    private int nextNum = 1;

    [SerializeField][Range(0, 1)] private float blendVolume = 1.0f;
    [SerializeField][Min(1)] private int blendCell = 1;

    public void SetRoom(int id)
    {
        probeReferenceVolume.BlendLightingScenario(scenarioKey[id], blendVolume);
        currentNum = id;
    }

    void Start()
    {
        probeReferenceVolume = ProbeReferenceVolume.instance;
        probeReferenceVolume.lightingScenario = scenarioKey[currentNum];
        probeReferenceVolume.numberOfCellsBlendedPerFrame = blendCell;
    }

    void Update()
    {
        if(Input.GetKey(KeyCode.Space))
        {
            SetRoom(nextNum);
        }
    }
}
```

最初にProbeReferenceVolumeのインスタンスを取得(シングルトン)

```c#
probeReferenceVolume = ProbeReferenceVolume.instance;
```

ライティングシナリオは２つのライティングを混ぜ合わせることでライティングを決めるので現在のライティングと次のライティングを決める必要がある。そのため、最初のシナリオキーを代入(Bright)。
```c#
probeReferenceVolume.lightingScenario = scenarioKey[currentNum];
```

現在のシナリオと変更したいシナリオの比率。(1に近づくと変更したいシナリオになる。0に近づくと現在のシナリオになる。)(2色の絵の具の混ぜ合わせのイメージ)
```c#
private float blendVolume = 1.0f;
```

1Frame時に何セル分処理をするか(箱が積まれていて何箱を1Frameで処理するかのイメージでいいと思う。間違っていたらコメントしてください。)
```c#
private int blendCell = 1
```

変更の関数
```c#
public void SetRoom(int id)
{
    probeReferenceVolume.BlendLightingScenario(scenarioKey[id], blendVolume);
    currentNum = id;
}
```

適当なオブジェクトにLightingManagerをアタッチ。ScenarioKeyの要素0に **Bright** を代入、要素1に **Dark** を代入。

![My project - OutdoorsScene - Windows, Mac, Linux - Unity 6 (6000.0.26f1) _DX12_ 2024_12_16 18_06_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/091f8834-f37a-cb22-e440-21afc3eb36ea.png)

 **シーン再生中にスペースで変更ができる！！！**
![無題の動画 ‐ Clipchampで作成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961601/bf68d434-b3d6-1ce4-f571-dd78bf7c157e.gif)

:::note warn
グラフィックレベルによって設定が変わるため、グラフィックレベルの変更を導入するような方はグラフィックレベルすべてに最初の設定で行ったLightingScenarioとScenarioBlendingをオンにしておくように
:::

# まとめ
変更自体は簡単だが数値の調整の問題なのか正直少し粗が見える。Unity公式の[動画](https://www.youtube.com/watch?v=4eIAWo-Gmiw)ではかなり綺麗だが...ライティングは思いがけない形になったりして難しいや。
粗が分かりやすいところはLightMapを使って綺麗にするのが一番かな。その場合、LightMapの変更を実装しないといけないけど。APVはとにかくライティング時間が短いから失敗してもかなりストレスフリーで出来るのがいい。変更するのもクリック1つで変更できるのもAPVの良さですね。

何か意見、感想や相談あれば気軽にコメントしてください。
これまで閲覧して頂き、ありがとうございました。

# 参考
https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@14.0/api/UnityEngine.Rendering.ProbeReferenceVolume.html

https://docs.unity3d.com/6000.0/Documentation/Manual/urp/probevolumes-bakedifferentlightingsetups.html