AR Foundation では、画像から現実の光源を推定し Scene 内のライティングを現実の光源に似た色・強さに調整する実装ができます。
試してみたので備忘録を残します。
▼実装後はこのようになります
環境
Windows 11
Unity 2022.2.11
AR Core XR Plugin 5.0.6
ARKit XR Plugin 5.0.6
AR Foundation 5.0.6
AR Foundation Remote 2.0.30-release.0
テスト機 HUAWEI Mate 20 lite, iPhone 13 Pro
URP
参考にさせて頂きました
Unityマニュアル
- UnityEngine.XR.ARFoundation
公式サンプル
- AR Foundation Samples
- 【AR Foundation】 光源推定をする
- AR Foundation 4.0 入門
光源推定で得られる項目
Ammbient Intensity | 平均的な明るさの推定値 |
Ambient Color | 平均的な色温度の推定値 |
AmbientSphericalHarmonics | 球面調和関数の推定値 |
Main Light Direction | メインライトの方向の推定値 |
Main Light Intensity | メインライトの明るさの推定値 |
球面調和関数は、よりリアルな環境の光の表現をするために使う数学的な手法のようです。
(反射の表現など)
メインライトの項目は対応環境が少ないので、今回はシンプルに平均的な明るさ・色を反映する実装をしていきます。
Unity公式の AR Foundation Samples にあるデモシーン「BasicLightEstimation」をもとにしています。
メインライトの項目も使ったデモシーンは「HDRLightEstimation」です。
光源推定機能を実装する
Camera
XR Origin > Main Camera にある ARCameraManager コンポーネントを設定します。
Light Estimation の使用したい項目にチェックを入れます。
(先程の表と同じものが並んでいます。)
Directional Light
Light の Type が Directional で、Mode が Realtime になっていることを確認して下さい。
Script 作成
ARCameraManager がカメラ画像をもとに現実の光源を推定しその値を保持しているので、それをDirectional Light と環境光に反映するScriptを作成していきます。
今回は Directional Light にこのScriptをアタッチし、ARCameraManager の参照を渡す形で実装しています。
光源の推定値を反映させる Script
内容
カメラ画像が更新される度に推定値を反映させる実装する場合のScriptの例です。
この後、解説していきます。
using UnityEngine; using UnityEngine.XR.ARFoundation; public class LightEstimate : MonoBehaviour { [SerializeField] ARCameraManager aRCameraManager; private Light light; void Awake() { light = GetComponent<Light>(); } private void OnEnable() { //有効時、アクション関数に追加する if (aRCameraManager != null) aRCameraManager.frameReceived += OnCameraFrameChanged; } private void OnDisable() { //無効時、アクション関数から削除する if (aRCameraManager != null) aRCameraManager.frameReceived -= OnCameraFrameChanged; } void OnCameraFrameChanged(ARCameraFrameEventArgs args) { //明るさ (float) if (args.lightEstimation.averageBrightness.HasValue) { float brightness = args.lightEstimation.averageBrightness.Value; Debug.Log("明るさ: " + brightness); light.intensity = brightness; //DirectionalLight に反映 RenderSettings.ambientIntensity = brightness; //環境光に反映 } //色温度 (float) if (args.lightEstimation.mainLightColor.HasValue) { float colorTemperature = args.lightEstimation.averageColorTemperature.Value; Debug.Log("色温度:" + colorTemperature); light.colorTemperature = colorTemperature; //DirectionalLight に反映 } //色補正 (Color) if (args.lightEstimation.colorCorrection.HasValue) { Color colorCorrection = args.lightEstimation.colorCorrection.Value; Debug.Log("色補正:" + colorCorrection); light.color = colorCorrection; //DirectionalLight に反映 } } //光源推定を止めたい場合に使う関数 public void StopLightEstimation() { //アクション関数から削除する if (aRCameraManager != null) aRCameraManager.frameReceived -= OnCameraFrameChanged; aRCameraManager.requestedLightEstimation = LightEstimation.None; this.enabled = false; }
解説
ARCameraManager (クラス)
frameReceived
新しいカメラ画像を取得するたびに発生するアクション関数。
ここに追加されたメソッドは、カメラ画像を取得するたびに呼ばれることになる。
requestedLightEstimation
記事前半で設定した LightEstimation を取得したり設定したりできるプロパティ。
例えば、下記のようにして光源推定する処理自体を止められる。
ARCameraManager.requestedLightEstimation = LightEstimation.None;
ARCameraFrameEventArgs (構造体)
frameReceived で情報を伝達するために使用される構造体。
lightEstimation
このフレームでのARLightEstimationDataを取得できるプロパティ。
ARLightEstimationData (構造体)
光源推定の値を保持する構造体。下記のプロパティから、値を取得できる。
下記はどれもプロパティ.HasValue
で値の取得が可能かどうか判定できる。
変数宣言して取得する際、float?
のようにNull許容型にするかプロパティ.Value
のようにして取得する。
averageBrightness | 平均的な明るさの推定値 (float) |
averageColorTemperature | 平均的な色温度の推定値 (float) |
colorCorrection | 色味を補正する値 (Color) |
ambientSphericalHarmonics | 球面調和関数を使用した照明の推定値 (SphericalHarmonicsL2) |
mainLightDirection | メインライトの方向の推定値 (Vector3) |
mainLightColor | メインライトの色味の推定値 (Color) |
averageMainLightBrightness | メインライトの明るさの推定値 (Color) |
ライティングが現実世界と馴染み、より自然なAR体験になりました!
プレイスタイルによっては、光源推定・ライトへの反映が済んだ後は光源推定をOFFにして軽量化してしまうのも良いかも。
▼ ARにおける影表現については、下記で紹介しているのでご参考ください。