シェーダーとして深度情報にアクセスし表示する方法
拡張現実アプリケーションでカメラに関連する画像を扱うには、通常、画像と対になった変換行列を扱うことが含まれる。 その理由は、カメラ画像のアスペクト比がアプリケーションのビューポートのアスペクト比と一致することが保証されていないからです。 ほとんどの場合、ビューポートはアプリケーションを実行するデバイスの画面全体をカバーする。 画像が歪むのを避けるため、表示する前にトリミング、パディング、あるいは回転させる必要がある。 AR背景画像の場合、上記の変換は表示行列を介して行われる。 このマトリクスは、深度画像とAR背景画像の縦横比が同じであれば、深度画像の表示にも使用できる。 AR Foundationを使って深度画像を取得する標準的な方法は、 Lightshipを使用する場合、さらに このハウツーでは、フルスクリーンで深度テクスチャにアクセスして表示する従来の方法とLightshipのアプローチの両方を紹介します。 このハウツーでは、次のことをカバーする:
|
前提条件
ARDKがインストールされたUnityプロジェクトと、セットアップされた基本的なARシーンが必要です。 詳細については、 ARDK 3のインストール および ARシーンの設定を参照してください。 また、NianticはUnityエディターでテストできるようにPlaybackを設定することを推奨しています。
ARオクルージョンマネージャーの追加
ARFoundationでは、AR Occlusion ManagerMonoBehaviourが深度バッファへのアクセスを提供します。 プロジェクトにARオクルージョンマネージャーを追加する:
メインカメラの
GameObjectに
AROcclusionManagerを
追加します:- Hierarchyで、
XROrigin
と Camera Offsetを展開し、 Main Camera オブジェクトを選択します。 次に、 Inspectorで、 Add Component をクリックし、AROcclusionManager
を追加します。
- Hierarchyで、
Lightship Occlusion Extensionの追加
拡張機能を追加する:
LightshipOcclusionExtension
をメインカメラGameObject
に追加します。- Hierarchy で、
XROrigin
を展開し、 Main Camera を選択します。 次に、 インスペクタ で、 コンポーネントの追加 をクリックし、Lightship Occlusion Extension
を追加します。
- Hierarchy で、
Occlusion Manager から深度テクスチャにアクセスする(アプローチA)
コードで深度テクスチャにアクセスするには、カメラとOcclusion Manager をポーリングするスクリプトが必要です:
プロジェクトウィンドウで、AssetsフォルダにC#スクリプトファイルを作成します。
Depth_HowToと
名付ける。ファイルエディターで
Depth_HowTo.csを
開き、以下の手順の後にスニペットのコードを追加します。スクリプトの準備ができたら、Hierarchy からMain Cameraを選択し、Inspector に Component として追加します。 Occlusion Manager の横の丸をクリックし、Main Cameraを選択します。
深度のHow-to コードを表示するにはクリックしてください。
using UnityEngine;
using UnityEngine.XR.ARFoundation;
public class Depth_HowTo :MonoBehaviour
{
public AROcclusionManager _occlusionManager;
void Update()
{
if (!_occlusionManager.subsystem.running)
{
return;
}
var texture = _occlusionManager.environmentDepthTexture;
var displayMatrix = CameraMath.CalculateDisplayMatrix
(
texture.width,
texture.height,
Screen.width,
Screen.height,
XRDisplayContext.GetScreenOrientation()
);
// テクスチャで何かする
// ...
}
}
スクリプト・チュートリアル
- この例では、AR FoundationのOcclusion Managerから深度画像を取得します。 この画像はAR背景画像と同じ縦横比を持ちます。
- Lightshipの数学ライブラリを使って、深度画像をスクリーンにフィットさせる表示マトリックスを計算します。 カメラマネージャのフレーム更新コールバックで提供される表示マトリックスを使うこともできますが、そのマトリックスのレイアウトはプラットフォームによって異なります。
Lightship Occlusion Extension から深度テクスチャにアクセスする(アプローチB)
コードで深度テクスチャにアクセスするには、カメラとOcclusion Managerをポーリングするスクリプトが必要です:
プロジェクトウィンドウで、AssetsフォルダにC#スクリプトファイルを作成します。
Depth_HowToと
名付ける。ファイルエディターで
Depth_HowTo.csを
開き、以下の手順の後にスニペットのコードを追加します。スクリプトの準備ができたら、Hierarchy からMain Cameraを選択し、Inspector に Component として追加します。 Camera Extension)フィールドの横の丸をクリックし、Main Cameraを選択します。
デプスのHow-Toコードを表示するにはクリックしてください。
using UnityEngine;
using UnityEngine.XR.ARFoundation;
public class Depth_HowTo :MonoBehaviour
{
public LightshipOcclusionExtension _occlusionExtension;
void Update()
{
var texture = _occlusionExtension.DepthTexture;
var displayMatrix = _occlusionExtension.DepthTransform;
// テクスチャで何かする
// ...
}
}
スクリプト・チュートリアル
- この例では、LightshipのARオクルージョン拡張機能から深度画像を取得する。 この画像の縦横比はAR背景画像と一致することを保証するものではありません。
- 深度テクスチャのほかに、オクルージョン拡張機能は、深度を画面に表示するための適切な変換行列も提供する。 このマトリックスは従来のディスプレイマトリックスとは異なり、欠落したフレームを補正するためのワーピングも含まれている。
深度バッファを表示するための生画像の追加
シーンに生画像を追加し、深度バッファを変換してスクリーンと位置合わせするマテリアルを添付することで、ライブの深度情報を表示できます。
ライブ深度表示を設定するには
階層内で右クリックし、UIメニューを開いてRaw Imageを選択します。
画像変換ツールを使って、 生画像 を中央に配置し、後で見えるように画面全体に引き伸ばします(下の画像を参照)。
- すべてのパラメータ(左、上、Z、右、下)を0に設定する。
マテリアルとシェーダーを追加します。
マテリアルとシェーダーを作成するには、次のように行います。
- Assets(アセット)ウィンドウで右クリックし、 Create(作成) の上にカーソルを合わせ、 Material(マテリアル) を選択します。 DepthMaterial という名前を付けます。
- この作業を繰り返しますが、Shaderメニュー開き、Unlit Shaderを選択します。 新しいシェーダーにDisplayDepth という名前を付ける。
- シェーダーをマテリアルにドラッグして、それらを接続します。
- DisplayDepth Shader Code のコードを DisplayDepth シェーダに追加します。
DisplayDepth Shader Code
深度表示は、vert/frag セクションを使用する標準的なフルスクリーン・シェーダーです。 シェーダーのvertセクションで、UVにディスプレイ変換を掛けてテクスチャをサンプリングする。 これは、奥行きをスクリーンに合わせるトランスフォームを提供する。
クリックするとDepthDisplayシェーダが表示されます。
シェーダ "Unlit/DisplayDepth"
{
プロパティ
{
_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
{
float3 texcoord :TEXCOORD0;
float4 vertex : SV_POSITION;
};
// デプス テクスチャ用のサンプラー
sampler2D _DepthTex;
// スクリーン空間からデプス テクスチャ空間への変換
float4x4 _DepthTransform;
inline float ConvertDistanceToDepth(float d)
{
// 近クリップ平面よりも小さい距離をクリップし、その距離からデプス値を計算します。
return (d < _ProjectionParams.y) ? 0.0f : ((1.0f / _ZBufferParams.z) * ((1.0f / d) - _ZBufferParams.w));
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
// UV座標に画像変換を適用
o.texcoord = mul(_DepthTransform, float4(v.uv, 1.0f, 1.0f)).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 深度画像変換には(ワーピングのための)再投影が含まれる可能性があるので、
// uv 座標を同次からデカルトに変換する必要がある
float2 depth_uv = float2(i.texcoord.x / i.texcoord.z, i.texcoord.y / i.texcoord.z);
// 深度値は、赤チャンネルをサンプリングすることでアクセスできます
// テクスチャ内の値は、メトリックの目の深度(カメラからの距離)です
float eyeDepth = tex2D(_DepthTex, depth_uv).r;
// 目深度をzバッファ値に変換
// zバッファ値は範囲[0, 1]の非線形値
float depth = ConvertDistanceToDepth(eyeDepth);
// z値を色として使用
#ifdef UNITY_REVERSED_Z
return fixed4(depth, depth, depth, 1.0f);
#else
return fixed4(1.0f - depth, 1.0f - depth, 1.0f - depth, 1.0f);
#endif
}.
ENDCG
}.
}
}
深度を生画像に渡す
スクリプトで生画像に深度情報を渡す:
RawImageとMaterial`を
取り込むようにスクリプトを更新する。その
マテリアルの
深度テクスチャと表示トランスフォームを設定します。スクリプトに
SetTexture
とSetMatrix
を追加して、深度とトランスフォーム情報をシェーダに渡します。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);
}.
}
セットアップのテストとデバイスへのビルド
テスト用にすべての部品を接続して試すには、次の手順を行います。
- インスペクタで、メインカメラに オクルージョンマネージャと
デプススクリプト
(マテリアルと
RawImageが
設定されている)がアタッチされていることを確認します。 これでUnity EditorでPlaybackを使ったテストができるはずです。 また、Build Settingsを開き、Build and Runをクリックしてデバイスにビルドして試すこともできる。