深度情報を取得して表示する
この入門ガイドでは、深度バッファにアクセスする方法と使用例をご紹介します。 この例では、シェーダーで深度情報を取得し、カラーフィルターとして画面上に表示します。
この入門ガイドでは、以下の内容について説明します。
- 深度バッファにアクセスし、シェーダーを使って画面に表示する。
- 回転やアスペクト比を設定できるように、カメラからディスプレイのtransformを取得する。
- 生の深度テクスチャと行列をシェーダーに渡す。
- ディスプレイ行列を使用して、深度テクスチャ上の適切なサンプリングポイントを算出する。
- 深度情報の使用例として、テクスチャを数学的にカラースケールに変換する。
前提条件
ARDKがインストールされたUnityプロジェクトと、セットアップされた基本的なARシーンが必要です。 詳細については、 ARDK 3のインストール および ARシーンの設定を参照してください。
ARオクルージョンマネージャーの追加
Lightshipの ARオクルージョンマネージャーを使って深度情報を表示しやすくする:
AROcclusionManager
を メインカメラに追加します。GameObject
:- Hierarchyで、
XROrigin
と Camera Offsetを展開し、 Main Camera オブジェクトを選択します。 次に、 Inspectorで、 Add Component をクリックし、AROcclusionManager
を追加します。
- Hierarchyで、
Raw Imageの追加
Raw Imageを追加して深度情報を表示するには、次のように行います。
- AR シーン下の Hierarchy に Raw Image を追加します:
- メインシーン下の Hierarchy で右クリックし、 UI にマウスオーバーし、 Raw Imageを選択します。
- 画像変換ツールを使って、 生画像 を中央に配置し、後で見えるように画面全体に引き伸ばす(下の画像を参照)。
- すべてのパラメータ(左、上、Z、右、下)を0に設定する。
マテリアルとシェーダーを追加します。
マテリアルとシェーダーを作成するには、次のように行います。
- Assets(アセット)ウィンドウで右クリックし、 Create(作成) の上にカーソルを合わせ、 Material(マテリアル) を選択します。 DepthMaterial という名前を付けます。
- この作業を繰り返しますが、 Shader(シェーダー) にカーソルを合わせ、 Standard Surface Shader を選択します。 DisplayDepth.
- シェーダーをマテリアルにドラッグして、それらを接続します。
- DisplayDepth Shader Code のコードを DisplayDepth シェーダに追加します。
ここをクリックしてDisplayDepthのコードを表示します。
DisplayDepth Shader Code
Shader "Unlit/DisplayDepth"
{
プロパティ
{
_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,0.8);
}
ENDCG
}
}
}
深度データを取得するスクリプトを作成する
- Assets(アセット) ウィンドウで C#スクリプト ファイルを作成します。
- Depth_HowTo という名前を付けます。
- ファイルエディターで Depth_HowTo を開き、 深度スクリプトのコード のコードを追加します。
深度スクリプトのコード
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
public class Depth_HowTo :MonoBehaviour
{
public ARCameraManager _cameraManager;
public AROcclusionManager _occlusionManager;
public RawImage _rawImage;
public Material _material;
private Matrix4x4 _displayMat = Matrix4x4.identity;
void OnEnable()
{
_cameraManager.frameReceived += OnCameraFrameUpdate;
}
private void OnDisable()
{
_cameraManager.frameReceived -= OnCameraFrameUpdate;
}
void Update()
{
if (!_occlusionManager.subsystem.running)
{
return;
}
//raw imageに素材を追加します。
_rawImage.material = _material;
//シェーダーに変数を設定する
//注意:深度テクスチャの更新はUpdate()関数内で行う必要があります
_rawImage.material.SetTexture("_DepthTex", _occlusionManager.EnvironmentDepthTexture)EnvironmentDepthTexture);
_rawImage.material.SetMatrix("_DisplayMat",_displayMat);
}
private void OnCameraFrameUpdate(ARCameraFrameEventArgs args)
{
if (!_occlusionManager.subsystem.running)
{
return;
}
// ディスプレイ・マトリックスを取得
_displayMat = args.displayMatrix? Matrix4x4.identity;
#if UNITY_ANDROID && !UNITY_EDITOR
_displayMat = _displayMat.transpose;
#endif
} }.
}
すべてを組み合わせる
テスト用にすべての部品を接続して試すには、次の手順を行います。
- Empty GameObject を作成します。
- Depth_HowTo スクリプトを Empty GameObject にドラッグします。
- Inspector:
- メインカメラを Camera Manager のスクリプトにドラッグします。
- メインカメラを Occlusion Manager のスクリプトにドラッグします。
- マテリアルを Material のスクリプトにドラッグします。
- Raw Imageを Raw Image のスクリプトに渡します。
- Build Settings(ビルド設定) を開き、シーンをデバイスにビルドして試してみましょう。
出力
シェーダーに加える変更によっては、サンプルシーンの表示が異なる場合があります。