Meta Questパススルーにおけるオクルージョン設定

# Meta Questパススルーにおけるオクルージョン設定




Meta Questのパススルー機能を使用する際、現実世界と仮想オブジェクトの自然な融合を実現するには、**オクルージョン（遮蔽）**の設定が非常に重要です。この設定を適切に行うことで、仮想オブジェクトが現実世界のオブジェクトに隠れる、あるいは現実世界のオブジェクトが仮想オブジェクトに隠れるといった、よりリアルな表現が可能になります。

本記事では、Meta Questにおけるパススルーのオクルージョン設定について、具体的な手順を解説します。

1. パススルーとは
1. 環境光の設定
1. OVRSceneManagerとオクルージョンオブジェクトの準備
1. オクルージョンメッシュの準備
1. DeothOnlyMaterialの作成と設定
1. カメラとパススルーレイヤーの設定



## 1. パススルーとは
Meta Questのパススルー機能は、ヘッドセットに搭載されたカメラを通して、現実世界の映像をユーザーの視界にリアルタイムで表示する技術です。これにより、ユーザーはヘッドセットを装着したままでも周囲の状況を確認でき、現実空間に仮想オブジェクトを重ね合わせて表示する「複合現実（MR）」体験を可能にします。ゲームやアプリケーション内で仮想のキャラクターが現実の家具の裏に隠れたり、壁の向こうから現れたりといった表現が可能になり、より没入感のある体験が生まれます。

## 2. 環境光の設定
まず、シーン全体の光の影響を最小限に抑え、パススルーの映像が干渉されないように設定します。

Lightingウィンドウの設定
Window > Rendering > Lighting を選択し、Lightingウィンドウを開きます。
![スクリーンショット 2025-05-25 18.08.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/4161347d-97c1-40f8-a7f5-ae6f41e24aa7.png)

SceneタブのEnvironmentセクションで、Lighting Settings AssetをNoneに設定します。これにより、シーン全体の照明設定がリセットされます。
Environmentセクション内のSkybox MaterialとSun SourceもNoneに設定します。
![スクリーンショット 2025-05-25 18.08.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/510f415d-8d63-4bd7-ae0b-ddd93cc28d30.png)

SourceをColorにし、カラーピッカーでR:0, G:0, B:0, A:0（完全に透明な黒）に設定します。


## 3. OVRSceneManagerとオクルージョンオブジェクトの準備
現実世界のメッシュを認識し、それらをオクルージョンオブジェクトとして利用するために、OVRSceneManagerを設定します。

OVRSceneManagerの追加と設定
シーン内の任意のGameObject（例えば空のGameObjectを作成）に、OVRSceneManager.csスクリプトをアタッチします。
![スクリーンショット 2025-05-25 18.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/2a488cc3-125b-4bb5-aba2-eab6f2d5daf8.png)


同じGameObjectにOVRSceneModelLoader.csスクリプトもアタッチします。

OVRSceneManagerのインスペクターで、Occluding PlaneとOccluding Volumeのチェックボックスにチェックを入れます。これにより、現実世界の平面とボリュームをオクルージョンとして利用できるようになります。


・Plane Prefabに、OccludingPlaneを設定します。
・Volume Prefabに、OccludingVolumeを設定します。

** これらのPrefabを設定する理由 **
Meta QuestのScene APIは、現実世界のスキャンデータ（壁、床、机などの平面や、部屋の形状などのボリューム）をUnity上でメッシュとして生成します。OVRSceneManagerは、これらの現実世界のメッシュをUnityオブジェクトとして表現するために、ここで指定されたPrefabを元にインスタンスを生成します。

OccludingPlaneは、床や壁、テーブルの表面といった平面構造を表現するためのPrefabです。これらの平面を仮想オブジェクトのオクルージョンとして機能させることで、例えば仮想のボールが床の下に潜り込むように見えたり、壁の向こうに隠れたりするような表現が可能になります。
OccludingVolumeは、部屋の形状や大きな家具といった立体的な構造を表現するためのPrefabです。これにより、仮想オブジェクトが現実世界の空間内に配置された際に、より複雑な形状の現実オブジェクトによっても適切に遮蔽されるようになります。
これらのPrefabには、後述するDepthOnlyMaterialが設定され、BoxColliderがアタッチされることで、現実世界と仮想オブジェクトの適切な遮蔽と物理的なインタラクションを可能にします。


## 4. オクルージョンメッシュの準備

OVRSceneManagerが生成するオクルージョンメッシュに対して、適切なマテリアルとコライダーを設定します。

Occluding Planeの設定

OVRSceneManagerがシーン内に生成するOccludingPlaneオブジェクト（通常はOVRSceneManagerの子オブジェクトとして動的に生成されます）に、OVRSceneAnchor.csスクリプトがアタッチされていることを確認します。
![スクリーンショット 2025-05-25 18.09.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/dcbe16bc-6ce1-47c7-9837-a4f0cab770f0.png)


OccludingPlaneの子オブジェクトにあるメッシュ（通常はMeshFilterとMeshRendererを持つオブジェクト）を選択します。
このメッシュに、後述のDepthOnlyMaterialを設定します。
![スクリーンショット 2025-05-25 18.09.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/6269616c-61ef-44e4-8315-ee965bf31b84.png)


BoxColliderをアタッチし、現実世界の平面が仮想オブジェクトと物理的に干渉するように設定します。


Occluding Volumeの設定

OccludingVolumeオブジェクト（同様にOVRSceneManagerの子オブジェクトとして動的に生成されます）にも、OVRSceneAnchor.csスクリプトがアタッチされていることを確認します。
OccludingVolumeの子オブジェクトにあるメッシュを選択します。
![スクリーンショット 2025-05-25 18.10.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/bd8f8b2d-523f-4bde-aac9-570190c691a2.png)


このメッシュに、後述のDepthOnlyMaterialを設定します。
BoxColliderをアタッチします。
![スクリーンショット 2025-05-25 18.10.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/42786e02-ba29-4e2d-a56d-124c4582d0ec.png)


## 5. DepthOnlyMaterialの作成と設定

オクルージョンに特化したマテリアルを作成し、描画順序を調整します。

DepthOnlyShaderの作成

Assets > Create > Shader > Standard Surface Shaderを選択し、新しいシェーダーを作成します。名前をPassThroughDepthOnlyとします。
作成したPassThroughDepthOnly.shaderファイルをダブルクリックして開き、既存のコードを以下の内容に置き換えます。

```
// Copyright (c) Meta Platforms, Inc. and affiliates.

Shader "PassThrough/DepthOnly" {
    Properties {
    }
    SubShader {
        Tags{"RenderType" = "Transparent" "Queue"="Geometry-1"} // QueueをGeometry-1 (1999)に設定
        LOD 100

        // First Pass: render outside shell of hand, as depth object
        Pass {
            ZWrite On // デプスバッファへの書き込みを有効にする
            ColorMask 0 // カラーバッファへの書き込みを無効にする (描画されない)
            Blend SrcAlpha OneMinusSrcAlpha // パススルーのためのブレンド設定（ここではZWriteが優先される）
            Cull Off // オクルージョンメッシュが裏側からも機能するようにカリングをオフにする

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
            };

            struct v2f {
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            v2f vert(appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                UNITY_TRANSFER_FOG(o, o.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target {
                // clip(mask.r - 0.5); // 元のシェーダーにあったが、今回はデプスのみなのでコメントアウト
                return float4(0,0,0,0); // 色は返さない（完全に透明）
            }
            ENDCG
        }
    }
}


```

 このシェーダーは、**ZWrite On**でデプスバッファへの書き込みを有効にし、**ColorMask 0**でカラーバッファへの描画を無効にしています。これにより、画面に何も描画せず、オブジェクトのデプス情報のみをデプスバッファに書き込みます。
 
Tags内の**"Queue"="Geometry-1"**は、描画キューをGeometry（不透明オブジェクトのデフォルトキュー、値は2000）の1つ手前、つまり1999に設定しています。これにより、現実世界のメッシュが仮想オブジェクトよりも手前に存在する場合でも、デプス情報が正しく書き込まれ、仮想オブジェクトが現実世界のオブジェクトによって隠れる（オクルージョンされる）ように機能します。
![スクリーンショット 2025-05-25 18.11.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/c4cd9bf1-2f79-437e-a9d4-a32c7e54cfcc.png)


**Cull Off**は、オブジェクトの裏面もデプス情報を書き込むために設定されています。これにより、オクルージョンメッシュがどのような向きであっても適切に機能します。

次に、Assets > Create > Materialを選択し、新しいマテリアルを作成します。マテリアル名を例えばDepthOnlyMaterialとします。

このマテリアルのShaderを、先ほど作成したPassThrough/DepthOnlyに設定します。
![スクリーンショット 2025-05-25 18.11.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/1cbd850a-f928-440a-8834-42445dff3972.png)


## 6. カメラとパススルーレイヤーの設定

Meta Questのパススルー映像を適切に表示し、オクルージョンと連携させます。

OVR Camera Rigの設定

シーン内のOVRCameraRigを選択します。
OVRCameraRigにOVR PassThroughLayer.csスクリプトがアタッチされていることを確認します。もしアタッチされていなければ、追加します。
OVR PassThroughLayerコンポーネントのPlacementをUnderlayに設定します。これにより、パススルー映像が仮想オブジェクトの下に描画されます。
![スクリーンショット 2025-05-25 18.12.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/cf6a669d-9539-49ea-bbc9-8bb0ae12fd5e.png)



CenterEyeAnchor内のCameraコンポーネントの設定

OVRCameraRigの子オブジェクトであるCenterEyeAnchorを選択し、その中のCameraコンポーネントを選択します。

Clear FlagsをSolid ColorまたはSkyboxに設定します。

Backgroundの色をR:0, G:0, B:0, A:0（完全に透明な黒）に設定します。これにより、パススルー映像と仮想オブジェクトが適切に合成されます。
![スクリーンショット 2025-05-25 18.13.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4031200/eda832a7-e25f-4c89-b70c-24225180dff8.png)

以上の設定を行うことで、Meta Questのパススルー環境において、現実世界のオブジェクトと仮想オブジェクトが自然にオクルージョンされるようになります。これにより、より没入感のあるMR体験を提供することが可能になります。