本文へスキップ

シェーダーとして深度情報にアクセスし表示する方法

このハウツーでは、テクスチャとして使用するためのデプスバッファへのアクセスについて説明します。 この例では、シェーダーが深度情報を取り込み、オーバーレイとして画面に表示します。

この入門ガイドでは、以下の内容について説明します。

  1. 深度バッファにアクセスし、シェーダーを使って画面に表示する。
  2. 回転やアスペクト比を設定できるように、カメラからディスプレイのtransformを取得する。
  3. 生の深度テクスチャと行列をシェーダーに渡す。
  4. ディスプレイ行列を使用して、深度テクスチャ上の適切なサンプリングポイントを算出する。
  5. 深度情報の使用例として、テクスチャを数学的にカラースケールに変換する。
結果

前提条件

ARDKがインストールされたUnityプロジェクトと、セットアップされた基本的なARシーンが必要です。 詳細については、 ARDK 3のインストール および ARシーンの設定を参照してください。 また、NianticはUnityエディターでテストできるようにPlaybackを設定することを推奨しています。

ARオクルージョンマネージャーの追加

ARFoundationでは、AR Occlusion ManagerMonoBehaviourが深度バッファへのアクセスを提供します。 プロジェクトにARオクルージョンマネージャーを追加する:

  1. メインカメラの GameObjectに AROcclusionManagerを追加します:

    1. Hierarchyで、 XROriginCamera Offsetを展開し、 Main Camera オブジェクトを選択します。 次に、 Inspectorで、 Add Component をクリックし、 AROcclusionManagerを追加します。
    AROcclusionManager

オクルージョンマネージャーからデプスバッファーにアクセスする

コードで深度バッファにアクセスするには、カメラとオクルージョンマネージャをポーリングするスクリプトが必要です:

  1. プロジェクトウィンドウで、AssetsフォルダにC#スクリプトファイルを作成します。

  2. Depth_HowToと名付ける。

  3. ファイルエディターでDepth_HowTo.csを開き、以下の手順の後にスニペットのコードを追加します。

  4. スクリプトの準備ができたら、Hierarchy からMain Cameraを選択し、Inspector に Component として追加します。 カメラマネージャーフィールドの横の丸をクリックし、メインカメラを選択します。 オクルージョンマネージャーのフィールドも同じようにします。

    デプス_ハウツー
デプスのハウツーコードを表示するにはクリックしてください。

using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class Depth_HowTo : MonoBehaviour
{
public ARCameraManager _cameraManager;
public AROcclusionManager _occlusionManager;
private Matrix4x4 _displayMat = Matrix4x4.identity;

void OnEnable()
{
_cameraManager.frameReceived += OnCameraFrameUpdate;
}

private void OnDisable()
{
_cameraManager.frameReceived -= OnCameraFrameUpdate;
}

void Update()
{
if (!_occlusionManager.subsystem.running)
{
return;
}
var depth = _occlusionManager.environmentDepthTexture;
//テクスチャで何かする
}

private void OnCameraFrameUpdate(ARCameraFrameEventArgs args)
{
if (!_occlusionManager.subsystem.running)
{
return;
}.
_displayMat = args.displayMatrix? Matrix4x4.identity;

#if UNITY_ANDROID && !UNITY_EDITOR
_displayMat = _displayMat.transpose;
#endif
} }.
}

スクリプト・チュートリアル

  1. スクリプトはARCameraManagerと AROcclusionManagerを取り込む。
  2. frameReceivedイベントを購読することで、スクリプトはカメラの表示トランスフォームを取得し、フレームごとにカメラを更新します。
    • 表示変換は、深度テクスチャをサンプリングするために使用される。 詳しくはDepth機能のページを参照)。
  3. その後、UpdateメソッドでAROcclusionManagerから深度が読み込まれる。

深度バッファを表示するための生画像の追加

シーンに生画像を追加し、深度バッファを変換してスクリーンと位置合わせするマテリアルを添付することで、ライブの深度情報を表示できます。

ライブ深度表示を設定するには

  1. 階層内で右クリックし、UIメニューを開いてRaw Imageを選択します。

  2. 画像変換ツールを使って、 生画像 を中央に配置し、後で見えるように画面全体に引き伸ばす(下の画像を参照)。

    1. すべてのパラメータ(左、上、Z、右、下)を0に設定する。
    ストレッチ・トランスフォーム

マテリアルとシェーダーを追加します。

マテリアルとシェーダーを作成するには、次のように行います。

  1. Assets(アセット)ウィンドウで右クリックし、 Create(作成) の上にカーソルを合わせ、 Material(マテリアル) を選択します。 DepthMaterial という名前を付けます。
  2. この作業を繰り返しますが、シェーダーメニューを開き、アンリットシェーダーを選択します。 新しいシェーダーにDisplayDepth という名前を付ける。
  3. シェーダーをマテリアルにドラッグして、それらを接続します。
  4. DisplayDepth Shader Code のコードを DisplayDepth シェーダに追加します。

DisplayDepth Shader Code

深度表示は、vert/frag セクションを使用する標準的なフルスクリーン・シェーダーです。 シェーダーのvertセクションで、UVにディスプレイ変換を掛けてテクスチャをサンプリングする。 これは、奥行きをスクリーンに合わせるトランスフォームを提供する。

クリックするとDepthDisplayシェーダが表示されます。
Shader "Unlit/DisplayDepth"
{
Properties
{
_MainTex ("_MainTex", 2D) = "white" {}
_DepthTex("_DepthTex",2D) = "green" {}
}
SubShader
{
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}.
Blend SrcAlpha OneMinusSrcAlpha
// カリングや深度なし
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
float2 texcoord :TEXCOORD1;
float4 vertex : SV_POSITION;

};

float4x4 _DisplayMat;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v. vertex.vertex);
o.uv = v.uv;

#if !UNITY_UV_STARTS_AT_TOP
o.uv.y = 1-o.uv.y;
#endif

//画像を正しい回転とアスペクトに調整する必要があります。
o.texcoord = mul(float3(o.uv, 1.0f), _DisplayMat).xy;
return o;
}

sampler2D _MainTex;
sampler2D _DepthTex;

fixed4 frag (v2f i) : SV_Target
{
float depth = tex2D(_DepthTex, i.texcoord).r;

const float MAX_VIEW_DISP = 4.0f;
const float scaledDisparity = 1.0f / depth;
const float normDisparity = scaledDisparity / MAX_VIEW_DISP;

return float4(normDisparity,normDisparity,normDisparity,1.0f);
}.
ENDCG
}.
}
}

深度を生画像に渡す

スクリプトで生画像に深度情報を渡す:

  1. RawImageとMaterial`を取り込むようにスクリプトを更新する。

  2. そのマテリアルの深度テクスチャと表示トランスフォームを設定します。

  3. スクリプトにSetTextureSetMatrixを追加して、深度とトランスフォーム情報をシェーダに渡します。

  4. UnityのスクリプトにMaterialと RawImageを接続します。

    デプス_ハウツー
クリックすると、更新されたDepthDisplayシェーダーのコードが表示されます。
using UnityEngine.UI;

public class Depth_HowTo :MonoBehaviour
{
public RawImage _rawImage;

public Material _material;

...


void Update()
{
if (!_occlusionManager.subsystem.running)
{
return;
} //マテリアルを生画像に追加します。

//raw imageにマテリアルを追加
_rawImage.material = _material;

//シェーダーに変数を設定
//注意:深度テクスチャの更新はUpdate()関数内で行う必要があります
_rawImage.material.SetTexture("_DepthTex")material.SetTexture("_DepthTex", _occlusionManager.environmentDepthTexture);
_rawImage.material.SetMatrix("_DisplayMat",_displayMat);
}.

}

セットアップのテストとデバイスへのビルド

テスト用にすべての部品を接続して試すには、次の手順を行います。

  1. インスペクタでメインカメラに オクルージョンマネージャと デプススクリプトマテリアルと RawImageが設定されている)がアタッチされていることを確認します。 これでUnity EditorでPlaybackを使ったテストができるはずです。 また、Build Settingsを開き、Build and Runをクリックしてデバイスにビルドして試すこともできる。
最終セットアップ