ARToolKit for Unity Scripting and Low-Level API
ARToolKit for Unity 程式碼編寫以及底層 API
Unity 的上層程式碼編寫環境
Unity 為開發互動應用提供了一個豐富的程式設計介面。指令碼可以使用C#或是Javascript語言編寫並且可以呼叫大量的函式庫。基本來說,任何可以手動新增到Unity editor 中的物體都可以被程式設計。這些指令碼也十分緊密的結合到編輯器中。舉例來說,指令碼中的public 資料會在編輯器的UI上自動地表示為一個輸入框,方便調整數值和配置。
Unity 的C#使用Mono 框架支援,它提供了微軟.Net 框架的跨平臺實現。C#是一個流行的面嚮物件語言,由於它的流行度,網路上有很多學習C#語言的教程。Mono 的框架沒有提供.Net 在Windows 平臺上的所有特性,但是所有的核心特性全都擁有。
另外一個Mono 執行環境的特點是對原生程式碼的支援,也就是那些針對指定CPU編譯的,直接與該平臺作業系統程式設計介面(API)通訊的程式碼。Mono 管理的C# 執行環境中的程式碼通過平臺呼叫服務(P/Invoke)與原生的程式碼進行資料通訊。這允許Unity 中的一個C# 指令碼可以呼叫使用C/C++程式碼實現的函式。這就是ARToolKit for Unity 以及其他外掛實現的原理。ARToolKit 與作業系統通訊獲取攝像頭捕獲的影象,執行大量的計算並進行marker 跟蹤,甚至將捕獲影象處理為原生貼圖,全都是使用原生程式碼實現的。然後,一個簡化的用來配置,執行,終止的函式集以庫的形式展示出來。這些函式可以使用DllImport的方式對映到C#指令碼中,並直接在Unity中直接呼叫。
在Windows,OS X,和Android系統上libARWrapper 作為動態連結庫出現(分別打包為.dll檔案、.dylib檔案和.so檔案)。由於iOS系統不支援動態連結庫,libARWrapper 將作為靜態庫(.a檔案)連線到最終應用中。
下面的圖展示了組成ARToolKit for Unity 的不同部件間的關係:
如果想獲得ARToolKit 在Unity平臺上的總體資訊,請檢視Getting Started with ARToolKit for Unity這篇文章。
控制ARToolKit的主要操作
你可以通過將ARController 指令碼附加到場景中的一個GameObject 上來將ARToolKit 新增到你的專案中。這個GameObject在場景的任何位置都沒關係,在ARToolKit 給出的樣例中,ARController 都是附加在一個獨立無父物體的GameObject上的。
這裡十分推薦使用Unity Editor將ARController 新增到場景中,因為使用程式進行ARController 的配置十分複雜。如果你不想聽從建議,我們鼓勵你去檢查一下ARController 的Public 屬性以及它們在Unity Editor的指令碼中的配置方式。
預設情況下,ARController 實現了Start(),Stop(),和Update() 這些MonoBehaviour,並且分別呼叫下面這些函式:StartAR()——開始識別跟蹤已經配置好的AR場景。UpdateAR()——執行識別跟蹤以及各種常務處理。StopAR()——停止識別跟蹤。
預設情況下,StartAR()在Start()函式執行過程中被呼叫。如果你不希望它自動開始工作,可以設定AutoStartAR 這個Public 屬性
GameObject myARObject;
ARController myARController = myARObject.GetComponent《ARMarker》();
myARController.AutoStartAR = false;
然後你就可以在需要的時候手動呼叫StartAR()和StopAR()函數了。
Marker的新增,移除,尋找和查詢
ARMarker 指令碼是在Unity 中使用的marker 的抽象表示。
新增一個新的marker
為了動態地載入一個要跟蹤的marker,你應該在場景中例項化一個GameObject 並給它附加一個ARMarker 指令碼。通常來說,所有的ARMarker 例項都要和ARController 指令碼附加到同一個GameObject 上:
GameObject myARObject;
myMarker = myARObject.AddComponent("ARMarker") as ARMarker;
// 配置
myMarker. myMarker.Tag = "myMarker1";
myMarker.MarkerType = MarkerType.SquareBarcode;
myMarker.BarcodeID = 0;
myMarker.PatternWidth = 0.08f;
// 以米為單位,如0.08 = 8cm
myMarker.Load();
你可以檢視ARMarker 的原始碼來找到更多的選項。
這裡有一些在通過程式碼新增ARMarker時需要注意的事情:
除非ARController.StartAR()函式已經被呼叫,實際上將marker 載入到ARToolKit 中的操作要推遲到StartAR()執行後,而且像丟失資料(missing data)這種錯誤只有那時候才會顯示出來。
If you are using pattern-based square markers, you must supply the contents of the pattern file yourself (for an ARMarker added in the Unity Editor, this is done by the ARMarkerEditor script which runs in the Unity Editor.)如果你在使用基於圖案的Square Marker,你必須自己手動提供這個圖案檔案(?有待實踐考察)(對於在Unity Editor 中新增的ARMarker來說,這件事已經被ARMarkerEditor 這個執行在Unity Editor中的指令碼完成了)。
如果你在使用NFT marker 或是 multi-marker 集,你必須確保這些marker 的資料檔案在應用的檔案系統中是可以獲取的,通常都放在你專案中的”StreamingAssets”資料夾下。
獲取所有Marker 的列表
// 注意,FindObjectsOfType函式十分的佔用資源,不要每一幀都呼叫它
ARMarker[] markers = FindObjectsOfType(typeof(ARMarker)) as ARMarker[];
移除一個Marker
// 如果你要獲取這個marker GameObject myARObject; ARMarker myMarker = myARObject.GetComponent《ARMarker》(); // 現在銷燬它 Destroy(GetComponent(myMarker)); // 或者禁用它 myMarker.enabled = false;
查詢一個Marker 的可見性和位置
ARMarker myMarker;
if (myMarker.Visible) Debug.Log("Marker is visible.");
// Pose 是一個在左手座標系中的4x4齊次座標變換(transform)
// Pose 表示了marker 相對於觀察攝像頭的變換。
// 想獲得觀察攝像頭關於marker 的相對變換,可以使用pose.inverse方法;
Matrix4x4 pose = myMarker.TransformationMatrix;
Vec3 position = ARUtilityFunctions.PositionFromMatrix(pose);
Quaternion orientation = ARUtilityFunctions.QuaternionFromMatrix(pose);
將Marker 與場景連線起來
使用ARTrackedObject 和ARCamera
連線ARMarker(這個marker可以是一個圖案,一個二維碼,一個Multi-Marker集或是一個NFT marker)與Unity 場景的一個簡單方式是使用ARCamera 指令碼。這個指令碼必須附加到擁有AROrigin 指令碼的GameObject 的子物體上。
ARTrackedObject 與ARMarker 通過將各自的Tag 設定為相同值來構建聯絡。當ARMarker 出現並被跟蹤時,附加了ARCamera 的Unity Camera 將顯示出真正攝像機相對真正marker 位置上看到的畫面,當ARMarker 消失時,這個攝像機的所有虛擬畫面將隱藏。
通過將GameObject 放到指定Layer中並設定Camera 僅僅顯示那些需要的物體所在的Layer 可以讓這些內容很容易的根據marker 決定顯示和隱藏。通常來說,所有的marker 和它們對應的AR內容都放在被我們稱為foreground 的Layer 中。
// 通常情況下,你應該使用一個tag或是其他方法來將你要修改的camera 標記出來。
Camera[] Cameras = FindObjectsOfType(typeof(Camera)) as Camera[];
myCamera = Cameras[0];
// 為這個camera 設定culling mask 引數來分辨那些要顯示或隱藏的Layer。切記,這些一定要在新增ARCamera指令碼前完成。
myARForegroundLayer = 9;
// 0 是起始編號,所以9代表user layer 2。
myCamera.cullingMask = 1<< myARForegroundLayer;
myCamera.AddComponent("ARCamera") as ARCamera;
配置ARTrackedObject:
myARTrackedObject = arToolKitRoot.GetComponent();
myARTrackedObject.MarkerTag = "myMarker1";
// 就像前面的例子裡設定的一樣
為了讓對GameObject 的控制不被它們的是否可見而影響,你可以將GameObject 連線到ARTrackedObject 指令碼的eventReceiver 屬性上。當marker 出現,被跟蹤或是消失時,這些函式就會對應的被Unity 的BroadcastMessage 系統呼叫。
// 所有的訊息函式。
OnMarkerFound(ARMarker marker);
OnMarkerTracked(ARMarker marker);
OnMarkerLost(ARMarker marker);
ARCamera 的projection 和viewport 屬性都會在AR指令碼啟動自動設定。目前你還不能在StartAR()函式被呼叫之後新增ARCamera,除非去修改ARController。
使用外掛的底層介面
最後,所有的關於AR功能的函式都會呼叫原生外掛,也就是libARWrapper中的API。當然,你也可以完全自由地使用這些API。
我們的網站上有基於C語言的libARWrapper的完整的API文件。官方網站