おもちゃラボ

Unityで遊びを作ってます

「SwiftでつくるARKit超入門」を発売しました

今話題のARKitを使ってみたいけど、何から始めたら良いのかわからない・・・。そんな人のためにARKitの入門書を書きました!本書ではSwiftとXcodeを使ってプログラムを作っていきます。「ARKit超入門」はBOOTHで販売中です!

booth.pm

「ARKit超入門」では、swiftとARKitを使って次のような16個のサンプルを作成していきます。この中のいくつかのアプリについては、もう少し詳しく紹介していきますね。

f:id:nn_hokuson:20181008001126j:plain:w350

ARKit超入門の特徴

この本ではXcodeとSwiftを使ってARKitのサンプルを作っていきます。

UnityからでもARKit用のPluginを使えば勉強はできます。ただ、ビルドに時間がかかったり、APIが異なっていたりと、ARKitの勉強という意味では効率的ではありません。

そこで、XcodeとSwiftを使ってネイティブ環境で開発することで短いサイクルで15個のアプリを開発できるように工夫しています。それぞれの章で作るアプリはARKitの機能が分かりやすいように簡単なものになっています。
f:id:nn_hokuson:20190607213337j:plain:w320f:id:nn_hokuson:20190607213343j:plain:w320
また、ARKitで使用する3Dモデルの表示にはSceneKitというAppleが開発したフレームワークを使用しています。初めての方でも簡単に理解できるように、必要な考え方はTIPSや表なども使って詳しく説明しています。
f:id:nn_hokuson:20190607213740j:plain:w320f:id:nn_hokuson:20190607213747j:plain:w320

ARKit2.0にも対応

ARKit超入門では2018年にリリースされたばかりのARKit2.0にも対応しています。ARKit2.0では、次のような機能が追加されました。

  • 環境マッピング
  • ARの永続化
  • 複数人でのAR空間の共有
  • 画像トラッキング

ARKit入門ではこれらの4つの機能についても詳しく説明しています。もちろんこれらの機能を使ったサンプルアプリケーションもついています!
f:id:nn_hokuson:20190607214611j:plain:w320f:id:nn_hokuson:20190607214619j:plain:w320
また、ARの永続化や複数人でのAR空間の共有など、少し理解しにくい部分については、イラストなどを使ってわかりやすく解説しているので、安心して読み進めていただけます。
f:id:nn_hokuson:20190607214337j:plain:w320f:id:nn_hokuson:20190607214343j:plain:w320

作れるアプリケーションと目次

「ARKit超入門」の目次は次のようになります。最後の2章では少し実践的な「距離測定アプリ」と「メジャーアプリ」を作成します。これらの章については、XcodeやInterface Builderの使い方も含めてしっかり説明しています!

目次は次のようになります。

1章 ARKitとは
2章 サンプルを動かしてみる
3章 ARKitで特徴点を検出
4章 ARKitで平面の上に球を置く
5章ARKitで平面を表示する
6章 壁を検出する
7章 タップした平面に3Dモデルを置く
8章 オリジナルの3Dモデルを置く
9章 光源を推定する
10章 環境マッピング
11章 画像マーカーを使ってARを表示
12章 面の形状に沿った平面の検出
13章 ARKitと物理挙動の連携
14章 AR空間の永続化
15章 複数人でARを共有する
16章 距離測定アプリを作る
17章 メジャーアプリを作る

本書はPDFのダウンロード版のみの販売です。全128ページで販売価格は2000円になります。ダウンロードは次のBOOTHのサイトからお願いします!

2019年秋に予定されているARKit3への対応も順次行う予定です。一度ご購入いただくと、PDFのアップデートは無料でダウンロードできます。安心してお買い求めください。

booth.pm

Unityで始めるARKit超入門 平面をシェーダで描画する

UnityのARKitについてくる平面検出マーカーって、見やすいですけどイケてないですよね。そこで、Unityのシェーダを使って、ARKitの平面検出マーカーを少しだけかっこよくする方法を紹介します。今回は上のようなドットで書かれた平面マーカーを作ってみましょう。

f:id:nn_hokuson:20181001192028j:plain

平面描画用の水玉シェーダを作成する

 上のようなドット柄の平面検出マーカーを作るだけなら、ドット模様(水玉模様)のテクスチャを用意して貼り付ければ良い気もしますね。ただ、平面が大きくなるとテクスチャも引き伸ばされるため、あまりきれいな表示になりません。

f:id:nn_hokuson:20181001185311p:plain:w300

シェーダを使って描画することで、平面の大きさによらず一定の間隔でドットを打てるのでシェーダを使った方法をオススメします。

 

水玉シェーダを作成する

まずはシーンビューで右クリックして「Create」→「Shader」→「Standard Surface Shader」を選択してシェーダファイルを作成します。ファイル名はARPlaneShaderにしておきます。

次のプログラムを入力してください。

Shader "Custom/ARPlaneShader"
{
  properties
  {
    _Ratio("Ratio", float) = 1
  }
  SubShader {
    Blend SrcAlpha OneMinusSrcAlpha
    Pass {
      Tags { "Queue"="Transparent" "RenderType" = "Transparent" }

      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
       #include "UnityCG.cginc"

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

      struct v2f
      {
        float4 position : SV_POSITION;
        float2 uv     : TEXCOORD0;
      };

      v2f vert (appdata input)
      {
        v2f output;
        output.position = UnityObjectToClipPos(input.vertex);
        output.uv = input.uv;
        return output;
      }

     float _Ratio;
      fixed4 frag (v2f input) : SV_Target
      {
        float2 v = float2(input.uv.x * 200 * _Ratio, input.uv.y * 200) ;

        float  f = 5 * ( (sin(v.x) * 0.5 + 0.5) + (sin(v.y) * 0.5 + 0.5) );
        return fixed4(fixed3(0.1, 0.9, 1.0),  1-f);        
      }
      ENDCG
    }
  }
}

 
 

シェーダで水玉模様を作る原理

ここでは、ドットを打たないところ以外は透明にしたいのでBlendのタイプとQueue、Render Typeを指定しています。この辺は次のUnity Shaderの記事も参考にしてください。
 
nn-hokuson.hatenablog.com

重要なのはfragメソッドの中に書いているフラグメントシェーダです。少しややこしく見えるかもしれませんが、キモはsin(v.x)+sin(v.y)を計算しているところです。z = sin(x)+ sin(y)の計算結果は次のようになります。

f:id:nn_hokuson:20181001190113j:plain:w300

この山の高さを透明度にすることで頂上付近のみがドットとして表示されるという仕組みです。山の頂上だけをピックアップするからドットに見える、というのは上の図を横から見て考えたほうが分かりやすいかもしれません。

f:id:nn_hokuson:20181001185859p:plain:w400

Unityでシェーダを使って、その他の図形を書きたい場合は次の記事も参考にして下さい。

nn-hokuson.hatenablog.com

Prefabのシェーダを差し替える

シェーダができたところで、既存の平面検出シェーダと差し替えましょう。まずは今作成したシェーダをアタッチしたマテリアルを作成します。ARPlaneShaderを選択した状態で、右クリックして「Create」→「Material」を選択してください。

f:id:nn_hokuson:20181001190557p:plain:w200

このマテリアルをARKItの検出平面のPrefabに設定します。UnityARKitPlugin/Examples/Common/Prefabs/の中にあるdebugPlane→Planeオブジェクトのシェーダを今作成したCustom/ARPlaneShaderに変更してください。

f:id:nn_hokuson:20181001190801j:plain

これで、ビルドしてARKitを実行して平面を検出すると、次のように水玉模様が描かれた平面が検出されます。

f:id:nn_hokuson:20181001192028j:plain

Unityで始めるARKit入門 光源推定編

前回はUnityとARKitを使って、タップしたところにリンゴを配置するサンプルを作りました🍎

nn-hokuson.hatenablog.com

今回はARKitで光源推定をする方法を紹介します。ARでライトを配置する場合、そのままライトをおいただけでは光源の強さや色合いが決まっているため、モデルが映像になじまず違和感がある絵になってしまいます。

ARKitでは撮影された映像から光源の強さと色合いを推定できる機能があるので、それを使用してみましょう。

f:id:nn_hokuson:20180925231804j:plain

ARKitの光源推定でできること

 ARは様々な環境で撮影するため、その環境に応じたライトの設定をすることで、より自然なARに見せることができるようになります。ARKitでもARKit1.5からは光源推定ができる機能が提供されるようになりました。

このARKitの光源推定で推定できる値は次の2つになります。

  • ライトの強さ
  • ライトの色温度

どちらからライトが当たっているか、というライトの位置と方向は推定できないことに注意してください。ARKitで得られる光源の推定値をUnityのライトに設定することで、より自然なARを実現できます。

f:id:nn_hokuson:20180925233222p:plain:w450

光源推定を使ってみる

といってもUnityの場合はデフォルトで光源推定が有効になっているので、やることはありません(笑)1からシーンを作る場合を考えて、設定する項目を見ておきましょう。必要なのは次の二点です。

  1. Enable Light Estimationのチェックを入れる
  2. ライトにUnityARAmbientスクリプトをアタッチする

まずはヒエラルキーウインドウのARCameraManagerの中の「Enable Light Estimation」のチェックボックスにチェックを入れます。

f:id:nn_hokuson:20180925204013p:plain:w350

続いてヒエラルキーウインドウのDirectional lightに、Assets/UnityARKitPlugin/Plugins/iOS/UnityARKitHelpers/に含まれるUnityARAmbientスクリプトをアタッチします。

f:id:nn_hokuson:20180925204042p:plain:w350

このスクリプトの中身を見ておきましょう。

using System.Runtime.InteropServices;
using UnityEngine.XR.iOS;

namespace UnityEngine.XR.iOS
{
  public class UnityARAmbient : MonoBehaviour
  {

    private Light l;

    public void Start()
    {
      l = GetComponent<Light>();
			UnityARSessionNativeInterface.ARFrameUpdatedEvent += UpdateLightEstimation;
    }

    void UpdateLightEstimation(UnityARCamera camera)
    {
      if (camera.lightData.arLightingType == LightDataType.LightEstimate) {
        float newai = camera.lightData.arLightEstimate.ambientIntensity;
        l.intensity = newai / 1000.0f;
        l.colorTemperature = camera.lightData.arLightEstimate.ambientColorTemperature;
      }
    }

    void OnDestroy() {
      UnityARSessionNativeInterface.ARFrameUpdatedEvent -= UpdateLightEstimation;
    }
  }
}

Startメソッドの中では、ARKit側でARFrameUpdatedEventが呼びだれたタイミング(フレーム更新時)でUnityのUpdateLightEstimationが実行されるようにイベントを追加しています。

UpdateLightEstimationではARKitで得られたライトの推定強度(ambientIntensity)と推定色温度(ambientColorTemperature)をUnityのDirectional lightに設定しています。

実行結果

Unityでビルドして実行してみましょう。部屋のライトをつけたときと消したときで見え方が変わったら成功です。

f:id:nn_hokuson:20180925232049g:plain:w500