環境
- Windows 8
- Visual Studio Express 2012
デモ
サンプル
「Ovrvision SDK for Unity Pro」をダウンロードすると ovrvisionsdk.unitypackage とサンプルプロジェクトの「unity_ar_example」が含まれています。まずはサンプルプロジェクトを開いてみます。
ArUco
Ovrvision SDK v0.3 に利用されている AR ライブラリは ArUco だと izm さん(@izm)と あるしおうねさん(@AmadeusSVX)が Twitter で教えて下さいました!ありがとうございます。
@hecomi OVRVISION SDK v0.3のAR機能はArucoというライブラリを使用しているようなので、Arucoのマーカが対応のようです。http://t.co/ojmFIGytIq
— izm (@izm) 2014年4月5日
@izm @hecomi 書き込んで、丁度被ったこと気がつきましたw 凹氏くらいの方であれば、ささっとArUcoを概観するのが一番早いと思います。具体的には、util以下のaruco_create_markerで作成可能なので、これをビルドすればマーカーは出せます
— あるしおうね (@AmadeusSVX) 2014年4月5日
ArUco について
- ArUco: a minimal library for Augmented Reality applications based on OpenCV | Aplicaciones de la Visión Artificial
- http://qpitch.net/2012/07/29/cv%E3%83%99%E3%83%BC%E3%82%B9ar%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA-aruco-1/
ArUco は OpenCV ベースの軽量な C++ ベース、BSD ライセンスな AR ライブラリです。1024 個までのマーカに対応しています。マーカは下記のような形になります。
本家のデモは以下の様な感じです。
素晴らしい...。
マーカ生成プログラムのビルド
マーカを生成するには、あるしおうねさんが教えて下さったように aruco_create_marker を利用すると楽です。手順は以下になります(※ 今回は Windows で作業したので Windows 用の手順になってます)。
- 本家サイト(http://www.uco.es/investiga/grupos/ava/node/26)から Download をたどって aruco_msvc10.zip と aruco-1.2.4.tgz をダウンロード
- OpenCV のサイト(http://opencv.org/downloads.html)から OpenCV 2.4.1 をダウンロード
- Visual Studio で新規に空のプロジェクトを作って追加のインクルードディレクトリに OpenCV と ArUco(aruco_msvc10/include)を追加
- 追加の依存ファイルに aruco124.lib(aruco_msvc10/lib)、opencv_core241.lib、opencv_highgui241.lib(opencv/build/x86/vc10/lib) を指定
- ソースに aruco-1.2.4/utils/aruco_create_maker.cpp を追加
- Release ビルド
- 出来た実行ファイルと同じディレクトリに aruco_msvc10/bin/*.dll をコピー
- コマンドラインから以下を実行
# ArUco.exe <markerid> <output_file_name> <pixels> $ ArUco.exe 123 123.jpg 128
これでマーカが生成できるようになります。
Ovrvision SDK v0.3 について
いよいよ Unity のサンプルプロジェクトを見ていきます。
シーンのオブジェクトについて
- OvrvisionSDK
- Ovrvision.cs がアタッチされたオブジェクトで、DeviceCameraLeft(左カメラ) > CameraPlane(Ovrvision の左カメラ画テクスチャ描画用プレーン)、DeviceCameraRight(同右) > CameraPlane(同右) が子としてぶら下がっています。
- CameraPlane はレイヤが設定されており、DeviceCameraLeft は左の CameraPlane のみ、DeviceCameraRight は右の CameraPlane のみが見えるようになっています。
- OVRCameraController
- Ovrvision で見る世界はテクスチャ自体に歪みがかかっているため樽型でなく長方形で描画しています。一方、AR オブジェクトは通常の OVRCamera 越しに見ることで樽型の歪みをかけています。
- OvrvisionView
- AR で描画されるオブジェクトです。
つまり、カメラ画の現実世界 x 2、AR オブジェクト用に歪みをかけて見るバーチャルな世界 x 2 の計 4 個のカメラで世界を見ていることになります。
AR 部分のコードについて
とてもシンプルです。
OvrvisionEx.cs
using UnityEngine; using System.Collections; using System.Runtime.InteropServices; public class OvrvisionEx { [DllImport("ovrvision_ex", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] static extern void ovExSetImage(System.IntPtr pImgSrc, int w, int h); [DllImport("ovrvision_ex", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] static extern void ovExRender(); [DllImport("ovrvision_ex", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] static extern int ovExGetData(System.IntPtr mdata, int datasize); public int Render(System.IntPtr pImgSrc) { // float[] を渡して ArUco から AR オブジェクトの位置や姿勢情報などをもらう // DLL 経由で情報をもらうので GC 対象外にしている // これでアンマネージな世界へポインタを渡せるようになる float[] markerGet = new float[10]; GCHandle marker = GCHandle.Alloc(markerGet, GCHandleType.Pinned); // 解析対象の画像をセット // (pImgSrc は Ovrvision.cs 側で受け取った歪みなしの左カメラ画) ovExSetImage (pImgSrc, 640, 480); // 解析 ovExRender (); // 解析結果の受け取り // 見つからなかった場合は ri == 0、見つかったら ri == 1 int ri = ovExGetData(marker.AddrOfPinnedObject(), 10); // AR オブジェクト Transform gb = GameObject.Find ("OvrvisionView").transform; if (ri > 0) { // 見つかった場合は位置・姿勢をセット gb.localPosition = new Vector3 (markerGet [1], markerGet [2], markerGet [3]); gb.localRotation = new Quaternion (markerGet [4], markerGet [5], markerGet [6], markerGet [7]); } else { // 見つからなかった場合は遠くへ飛ばす gb.localPosition = new Vector3 (-10000.0f, -10000.0f, -10000.0f); } // GCHandle の解放 marker.Free (); return ri; } }
複数のマーカのハンドル
現状は同時に複数のマーカのハンドルは出来ないようです。ただ、マーカの ID は見れるので、マーカ側の配置を予め決めておけばロバスト性の高いデモは作れそうです。マーカ ID は ovExGetData 経由で得た配列の 0 番目に入っています。
if (ri > 0) { Debug.Log(markerGet[0]); // <-- ID が分かる }
高速化について
プロファイラを見ると、Ovrvision.Update が結構な時間を使っています(うちの PC だと 60 fps ちょっとだけ切ってました)。これは DLL 経由で Ovrvision からテクスチャを3枚分(左カメラ画、右カメラ画、ArUco に投げる歪みなし画)もらってくる処理でブロッキングしているからだと思われます。そこで以下のようにこの処理部を別スレッド化することによって高速化することが可能です。
これで 60 fps 確保出来ました(80 ~ 90 くらいになりました)。AR の姿勢の計算部分も Transform 制御する部分だけメインスレッド化して、座標情報取得を別スレッド化すれば、もう少し軽く出来ると思います。
描画順について
現状は、AR オブジェクト側のカメラの Depth が Ovrvision カメラの後ろに来ているため、影を描画したいなどの時に少し不便です。AR オブジェクト側のカメラ(OVRCameraController 下のカメラ 2 つ)の Clear Flags を Don't Clear 、Depth を 1 に設定して、Ovrvision 側のカメラの Clear Flags を Solid Color、Depth を 0 に設定すると色々と便利になると思います。冒頭のデモはこの設定で影を描画しています。
追記:
ただし、上記の手法を取るとカメラのテクスチャを貼り付けた Plane 自体が樽型に歪むため、カメラの歪みと合わせて二重に歪んでしまいます。もしくは、冒頭のデモのように OVRCameraController の Lens Collection を切るかする形になってしまいます。。
視差の問題点
現状の仕組みでは、Ovrvision を通して 2 つのカメラ画で見ている現実の世界と、左のカメラ画を解析して得られた姿勢情報を元に配置された一つのオブジェクトを OVRCamera で見ている世界の視差が異なるため、HMD で覗くと視差のズレが生じてしまっています。また、右目で見た時はマーカに対して結構ズレがあります。
なので、私は OVRCameraController の CameraRight の x 座標を 0.3 から 1.0 に増やして視差を合わせています。が、その影響でマーカの上にピッタリオブジェクトが乗るような表現は難しいです。
以前 PS Eye でやった際は、左右それぞれのカメラ画を解析してマーカの視差を AR オブジェクトの視差に利用してそこそこうまく行っていたので、今回もこの方式を取ろうかなぁと思ったのですが、現状の仕組みだと左目からの姿勢情報しか取れないようなので今後のアップデートに期待したいです。
Ovrvision SDK 以外の AR の実現方法
Ovrvision は単なる WebCam として見えるので、Unity で使える WebCamTexture をそのまま使えます。なので WebCamTexture から解析可能な NyARToolKit for Unity を使うと、AR 内部のコード含めて色々改良できるので、ユースケースに合わせて使い分けると良いと思います。
おわりに
Ovrvision SDK のお陰で AR が簡単に実験出来る基盤が出来ました!現実側に色々エフェクトを掛けたりしながら複合現実も作れそうで、色々面白いコンテンツが出来そうです。