おもちゃラボ

Unityで遊びを作ってます

【AR Foundation】モデルに影をつける

ARのモデルを表示するとき、現実感を出すためには「影」の存在が重要になります。
影があることで床との接地面が分かりやすくなり「そこに置かれている感」がアップします。

f:id:nn_hokuson:20200804201438j:plain

この記事では次の流れでモデルに影を付ける方法を紹介します。

  1. 丸影を表示する
  2. 投影テクスチャシャドウを表示する
  3. 影のパラメータ設定について

AR Foundationを使って影付きのモデルを表示する方法はこちらの記事を参照下さい。

nn-hokuson.hatenablog.com

また、AR Foundationの基礎になっているARKitについては「swiftで作る ARKit超入門」がオススメです!こちらも、ぜひご参照ください。
booth.pm

丸影

一番手軽に影を表示する方法は、モデルの足元に影のテクスチャを配置しておくことです。一般的に丸影と呼ばれる方法で、レンダリングのコストも小さく昔から使われている手法です。

f:id:nn_hokuson:20200804172707p:plain:w350

ここでは、まず丸影の作り方から始めましょう。次のような影のテクスチャを用意するか、下の画像をダウンロードしてお使い下さい。

f:id:nn_hokuson:20200804172914p:plain:w200

影のテクスチャをプロジェクトウインドウにドラッグ&ドロップします。影のテクスチャはアルファレイヤ(透明レイヤ)を含んでいるため、影のテクスチャを選択して、インスペクタから「Alpha Is Transparency」にチェックを入れて「Apply」を押して下さい。

f:id:nn_hokuson:20200804173159j:plain:w300

次に影を表示する平面オブジェクトを作成します。ヒエラルキーウインドウの「+」→「3D Object」→「Plane」を選択してPlaneを生成し、サイズを調節してからモデルの足元に移動します。移動したPlaneはモデルにドラッグ&ドロップして子要素にしておきましょう。

f:id:nn_hokuson:20200804173501j:plain

作成したPlaneに影のテクスチャをドラッグ&ドロップします。透明度を反映させるため、インスペクタからShaderを変更します。Particle/Standard Unlitを選択して、「Rendering Mode」を「Fade」に設定して下さい。

その下の「Color Mode」は「Multiply」のままでOKです。これにより下の色と乗算されるため、必ず影の部分が周りの部分に比べて暗くなります。

f:id:nn_hokuson:20200804174028j:plain

これで丸影付きのモデルが作成できました。

投影テクスチャシャドウ

丸影は作成するのも簡単ですし、描画コストも安いのですが、いかんせん見た目がイマイチです。

そこで、もう少しちゃんとした影を付ける場合、Unityが描画してくれる影を利用します。先程の丸影と同じように足元にPlaneを配置すると、下図左のように影が表示されますね。この影の部分だけを残して、その他の部分は透明(下図右)になるようなシェーダを作ります。

f:id:nn_hokuson:20200804181730j:plain

プロジェクトウィンドウで右クリックして「Create」→「Shader」→「Unlit Shader」を選択し「ARShadow」という名前で保存して下さい。

f:id:nn_hokuson:20200804180549p:plain:w100

作成できたら、次のシェーダプログラムを入力して下さい。

Shader "Custom/ARShadow"
{
    SubShader {
        Pass {
            Tags { "LightMode" = "ForwardBase" "RenderType"="Opaque" "Queue"="Geometry+1" "ForceNoShadowCasting"="True"  }
	    LOD 150
	    Blend Zero SrcColor
	    ZWrite On
        
            CGPROGRAM
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc" 
            #pragma multi_compile_fwdbase
            #include "AutoLight.cginc"
  
            struct v2f
            {
                float4 pos : SV_POSITION;
                LIGHTING_COORDS(0,1)
            };
  
            v2f vert(appdata_base v) {
                v2f o;
                o.pos = UnityObjectToClipPos (v.vertex);
                TRANSFER_VERTEX_TO_FRAGMENT(o);                 
                return o;
            }
 
            fixed4 frag(v2f i) : COLOR {
                float attenuation = LIGHT_ATTENUATION(i);
                return fixed4(1.0,1.0,1.0,1.0) * attenuation;
            }
 
            ENDCG
        }
    }
    Fallback "VertexLit"

}

このシェーダの中ではv2f構造体の中でLIGHTING_COORDSを使ってライトマップとシャドウマップ用のTEXCOORDを生成しています。フラグメントシェーダではLIGHT_ATTENUATIONを使って、先程適宜したライトマップとシャドウマップから光の減衰具合を調べています。これにより影のある場所だけが不透明になり、その他の部分は透明な画像になります。

Unityのシェーダに関しては次の記事も合わせてご覧ください。

nn-hokuson.hatenablog.com

ARShadowシェーダファイルを選択した状態で右クリックして、「Create」→「Material」を選択してください。これによりARShadowが適用されたマテリアルが作成できます。このマテリアルを足元のPlaneにドラッグ&ドロップして下さい。

f:id:nn_hokuson:20200804184408j:plain

影の調整

最後に影の見栄えについて調整をしていきます。ここでは「影の解像度」と「影の濃さ」についての設定方法を紹介します。

影の解像度

Unityでモデルの影を表示したとき、次図のようにガタガタで粗い影になってしまうことがあります。

f:id:nn_hokuson:20200804185357p:plain:w300

この場合は、UnityのメニューバーからEdit→Project Settingsを選択してProject Settingsウインドウを開いて下さい。左カラムから「Quality」を選択し、「Shadow Distance」を 10程度の値に設定してみて下さい。

f:id:nn_hokuson:20200804185857j:plain:w500

影の濃さ

デフォルトでは影が真っ黒で濃すぎることが多いです。そこで影の色を薄くします。
f:id:nn_hokuson:20200804190605g:plain

影の濃さはDirectional Lightのインスペクタから設定します。ライトを選択した状態でインスペクタのRealtime Shadows → Strengthを0.5程度に下げてみましょう。
f:id:nn_hokuson:20200804190312j:plain:w350

【AR Foundation】平面上にモデルを置く

前回はAR Foundationを使って平面を検出しました。今回は検出した平面上にARのオブジェクトを配置する方法を紹介します。アプリを起動し、検出した平面をタップすると、タップした場所にオブジェクトが表示されます。

f:id:nn_hokuson:20200731152019j:plain

作成の流れは次のようになります。

AR Foundationの基礎になっているARKitについては「swiftで作る ARKit超入門」がオススメです!ぜひご参照ください。
booth.pm

AR Foundationのセットアップ

Unityを起動して、3Dのプロジェクトを作成します。プロジェクトが出来たらPackage ManagerからAR FoundationとARKIt XR Pluginをインストールして下さい。AR Foundationのインストール手順については、次の記事で詳しく説明しているので、こちらを参照下さい。

nn-hokuson.hatenablog.com

AR Foundationがインストールできたら、シーンにAR SessionとAR Session Originを追加します。ヒエラルキーウインドウの「+」をクリックして「XR→AR Session Origin」と「XR→AR Session」を追加しましょう。

f:id:nn_hokuson:20200706161216p:plain:w300 f:id:nn_hokuson:20200706161241p:plain:w300

AR Session Originの子要素にはAR用のカメラが追加されているため、最初からあるMain Cameraは不要です。削除しておきましょう。これで、UnityでAR Foundationを使うための準備が整いました。

平面検出

次にAR Foundationで平面を検出できるようにします。AR Session Originオブジェクトを選択して、インスペクタのAdd Componentボタンをクリックし、AR Plane Managerコンポーネントをアタッチします。

f:id:nn_hokuson:20200706161519p:plain:w300

今回、Plane PrefabはNoneのままにしておきましょう。これをNoneにすると、AR Foundationでは内部的に平面が行われるようになり、検出した平面は表示されなくなります。

タップした場所にオブジェクトを配置する

次にタップした場所にうさぎのモデルを配置するためのスクリプトを作成します。プロジェクトウィンドウで右クリックして、「Create→C# Script」を選択し、Spawnという名前で保存して下さい。

f:id:nn_hokuson:20200731113814p:plain:w240

ファイルができたら、次のスクリプトを入力して下さい。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

[RequireComponent(typeof(ARRaycastManager))]
public class Spawn : MonoBehaviour
{
    [SerializeField]
    GameObject objectPrefab;

    public TrackableType type;

    ARRaycastManager raycastManager;
    List<ARRaycastHit> hitResults = new List<ARRaycastHit>();

    void Start()
    {
        raycastManager = GetComponent<ARRaycastManager>();
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            if (raycastManager.Raycast(Input.GetTouch(0).position, hitResults, TrackableType.All))
            {
                Instantiate(objectPrefab, hitResults[0].pose.position, Quaternion.identity);
            }
        }
    }
}

このスクリプトではAR Raycast Managerコンポーネントを使用するため、classの宣言の手前にRequireComponentを使ってARRaycastManagerを指定しています。こうすることで、このスクリプトをアタッチしたときに、自動的にAR Raycast Mangerコンポーネントもアタッチされるようになります。

タップした場所にモデルを配置するため、ARRaycastManagerクラスのRaycastメソッドを使用しています。このメソッドは画面上のタップした座標を指定すると、そこからRayを飛ばして平面とぶつかった座標をARRaycastHitのリストに詰めて返してくれます。

第三引数で指定しているTrackableTypeでは、Rayが当たる対象を指定できます。指定できる値には次のようなものがあります。

Type 意味
None 検出しない
PlaneWithinPolygon 形状に沿った平面
PlaneWithinBounds 矩形平面
PlaneWithinInfinity 無限遠の平面
Planes すべての種類の平面
FeaturePoint 特徴点
All 全てのタイプを検出

スクリプトが入力できたら、AR Session Originオブジェクトにドラッグ&ドロップしてアタッチしておきましょう。RequireComponentを指定したので、ARRaycastManagerコンポーネントも自動的にアタッチされます。

f:id:nn_hokuson:20200731132233j:plain

モデルの準備

表示するモデルには、自分の好きなPrefabを指定できます。とりあえず試したい方ようにうさぎのPrefabを用意しました。次のリンクからダウンロードできます。

https://app.box.com/s/cuuoaqejxr9w4xztudm9folrassfi9hl

パッケージがダウンロードできたら、ダウルクリックしてプロジェクトに追加しておきましょう。Assets/Rabbit/RabbitPrefabが今回使用するPrefabです。これを先程のスクリプトのSpawnObject欄にドラッグ&ドロップして下さい。

f:id:nn_hokuson:20200731130912j:plain

また今回、平面をタップしたことを検出したいので、SpawnコンポーネントのType欄には「Plane Within Bounds」を設定しておきましょう。

f:id:nn_hokuson:20200731130242p:plain:w350

ビルドする

最後にプロジェクトをビルドして、スマートフォンにインストールしましょう。ビルドするための設定は次ページの「ビルドする」の項目を参照して下さい。

nn-hokuson.hatenablog.com

インストールできたらアプリを起動して、端末を動かして平面を検出します。次に検出した平面をタップすると、そこに指定したモデルが表示されることを確認して下さい。

f:id:nn_hokuson:20200731151654g:plain

【AR Foundation】セットアップから平面検出まで

これまでUnityからARKitを使いたい場合は、Unity ARKIt Pluginを使うのが一般的でした。ただ、Unity2019からはUnity ARKIt Pluginに変わってAR Foundationが公式でサポートされるようになりました。そのため、これからUnityでARを始めたい人は、AR Foundationを使うのが一般的になるでしょう。

そこで、この記事ではUnityでAR Foundationを使うための基本的なセットアップ方法を紹介します。また、初回の今回はAR Foundationを使って平面検出を行ってみます。

f:id:nn_hokuson:20200707221306j:plain:w650

AR Foundationを使った平面検出の流れは次のとおりです。

プロジェクトの作成

UnityでAR関連のアプリを作りたい場合は、Templeteから3Dのプロジェクトを作成します。プロジェクト名や保存場所は任意のもので構いません。

f:id:nn_hokuson:20200706160128p:plain:w500

AR Foundationのインストール

AR Foundationはパッケージという形で配布されています。したがって、UnityからAR Foundationを使うにはPackage Managerからインストールする必要があります。

メニューバーのWindow→Package Managerを選択して下さい。パッケージマネージャのPackages欄で「All」を選択した上で、検索欄にAR Foundationと入力します。すると、左カラムにAR Foundationのパッケージが表示されるので、インストールしたいバージョンを選択して、右下のインストールボタンをクリックして下さい。

f:id:nn_hokuson:20200706160515p:plain:w500

これにより、AR FoundationとAR Subsystemsのパッケージがインストールされます。次に、ARKitを使いたい場合は追加でARKIt XR PluginとARKit Face Tracking(顔検出を使いたい場合のみ)、ARCoreを使いたい場合はAR Core XR Pluginのパッケージをインストールして下さい。このとき、ARKIt XR PluginとAR Foundationのバージョンは揃えておくことをおすすめします。


AR Sessionを作成する

AR Foundationではセッションという単位でARの挙動を定義します。そのセッションの動きを管理するのがAR SessionとAR Session Originのオブジェクトです。

これらのオブジェクトをシーンに追加しましょう。ヒエラルキーウインドウの「+」をクリックして「XR→AR Session Origin」と「XR→AR Session」を追加して下さい。

f:id:nn_hokuson:20200706161216p:plain:w300 f:id:nn_hokuson:20200706161241p:plain:w300

AR Sessinはその名の通りセッションを管理するためのもので、AR Session OriginはAR座標系の原点とカメラの挙動を管理するためのものです。AR Session Originの子要素にはAR用のカメラが追加されているため、最初からあるMain Cameraは不要です。削除しておきましょう。

平面検出を行う

基本的にはAR Session Originオブジェクトに、様々なARのコンポーネント追加していきます。今回は平面検出をしたいので、AR Session Originオブジェクトを選択して、インスペクタのAdd Componentボタンをクリックし、AR Plane Managerコンポーネントをアタッチします。

f:id:nn_hokuson:20200706161519p:plain:w300

AR Plane ManagerのDetection Mode欄では、検出する面の方向(水平面・垂直面)を指定できます。選択できる項目の意味は次のようになります。

項目 意味
Everything 全ての平面を検出
Horizontal 水平面のみ検出
Vertical 垂直面のみ検出

また、Plane Prefabに平面のPrefabを設定することで、検出した平面を視覚化することができます。平面のPrefabを作って、検出した平面を視覚化してみましょう。

ヒエラルキーウインドウの「+」から「XR→AR Default Plane」を選択して下さい。

f:id:nn_hokuson:20200706161850p:plain:w300

作成したAR Default Planeオブジェクトをプロジェクトウィンドウにドラッグ&ドロップしてPrefabを作成します。作成したPrefabをAR Plane ManagerのPlane Prefabの欄にドラッグしてくだい。ヒエラルキーウインドウにあるAR Default Planeは削除しておいて下さい。

f:id:nn_hokuson:20200706162840j:plain

ビルドする

最後にiOS用にビルドしてみましょう。iOSのビルドには次の設定が必要になります。

  • Player Settings
  • XR/ARKit Build Settings
  • Plug-in Providers

Player Settingsの設定

メニューバーから「File → Build Setting 」を選択してBuild Settingsパネルを開き、ビルドターゲットをiOSに変更して下さい。次に「 Player Settings」ボタンをクリックして、Player項目のOhter Settingsの欄を次のように設定して下さい。

Bundle Identifire 任意の文字列
Camera Usage Description 任意の文字列
Target minimum iOS Version 13.0

f:id:nn_hokuson:20200706163129p:plain:w400

XR/ARKit Build Settingsの設定

また、Project Settingsのウインドウの左カラムからXR/ARKit Build Settingsを選択して、右カラムでCreateボタンをクリックします。

f:id:nn_hokuson:20200706163412p:plain:w400

XR Plug-in Managementの設定

最後に左カラムのXR Plug-in Managementを選択して、右カラムのiOSタブを選択、iOSタブをクリックして、Plug-in ProvidersのARKitにチェックを入れてください。

f:id:nn_hokuson:20200706163439p:plain:w400

実行してみる

Build Settingsのウインドウに戻ってBuild And Runのボタンを押して端末にインストールして下さい。アプリを起動してカメラを左右に動かすと平面が検出されて、検出された平面が黄色で表示されます。

f:id:nn_hokuson:20200707221903g:plain:w600