這篇文章的應用場景是這樣子的:
首先我們要做的是一個帶有LBS定位服務(比如高德地圖、百度地圖等)AR功能,在這個場景中,會有一些地圖上的”點“(如派出所、學校)是我們需要顯示在我們的AR鏡頭上的,如下圖:
圖片摘自wuyt2008的博客:《unity3d 嘗試 基於地理定位的 增強現實》
本文要解決的問題就是,如何判斷這些Point的東南西北,即坐標。
博主采用的開發環境是
- Unity3D: 5.3.5;
- EazyAR: SKD v1.3.0;
- GyroDroid :這個Unity3D 的傳感器插件包上網搜一下就有了。
要應用本博客的內容之前,必須先看過wuyt2008的博客《unity3d 嘗試 基於地理定位的 增強現實》。
開坑:
實際上我們要實現功能的原理就是根據定位返回的自身(Location)坐標(XL,ZL),跟我們需要標注顯示出來的Marker的坐標(XM,ZM)進行坐標系的運算,很簡單,
X∆=XL-XM,
Z∆=ZL-ZM,
然后我們再把我們的主攝像機的Position的x、z軸(Y是控制高的,與物體平面定位沒有關系)設置為(0,0),這樣呢,Marker在Unity中得坐標,就是(X∆,Z∆),並且經過我的測試,Unity中在使用ARCamera的情況下,+X軸指的方向是東90°,+Z軸指的方向是北90°。我們根本不需要做任何其他判斷,只需要根據這個特性,再根據經緯度的數據特性,如果X∆的值為負,則表示Marker位於東邊(相對自身),如果Z∆的值為負,則表示Marker位於北邊(相對自身),所以只需要按照(-X∆,-Z∆)設置Marker的(X,Z)坐標,即可准確的安放Marker的位置。
首先,我們使用EazyAR SDK 中提供的AR攝像機,為什么說它是AR攝像機呢,因為它本身已經根據AR應用的特性,進行了一些優化,還有添加了一些C# Script,所以直接拿來用,你會發現比你自己寫一大堆亂七八糟的代碼好多了。然后呢,再將GyroDroid插件包中的“MinimalSensorCamera”腳本,綁定到攝像機上,讓AR攝像機鏡頭隨着手機的旋轉而旋轉。
然后就是最重要的一個環節,這里要結合wuyt2008博主的博客中得代碼來介紹,我把代碼貼一下,並且我自己加了一些注釋,助於觀看:
1 using UnityEngine; 2 using System.Collections; 3 using System.Collections.Generic; 4 using UnityEngine.UI; 5 6 public class ARMange : MonoBehaviour { 7 8 public List<PlaceInfo> places = new List<PlaceInfo>();//Marker的集合(Marker是什么,請學習一下高德地圖api的應用,簡單的說,就是你想要標記在地圖上的點,比如一些餐廳或景點之類,甚至可以是自定義的點) 9 public GameObject perfab; 10 public PlaceInfo location = new PlaceInfo ();//根據高德API定位后傳遞過來的自身坐標信息 11 12 public void ShowPlaces(){ 13 ClearPlace (); 14 15 for (int i = 0; i < places.Count; i++) { 16 17 GameObject newPlace = Instantiate<GameObject> (perfab); 18 newPlace.transform.parent = this.transform; 19 20 double posZ = places [i].Latitude - location.Latitude;//計算相對距離,z軸(Unity中的坐標系) 21 double posX = places [i].Longitude - location.Longitude;//計算相對距離,x軸(Unity中的坐標系) 22 23 float z = 0; 24 float x = 0; 25 float y = 0; 26 27 if (posZ > 0) { 28 z = 500f; 29 } else { 30 z = -500f; 31 } 32 33 if (posX > 0) { 34 x = 500f; 35 } else { 36 x = -500f; 37 } 38 39 z = z + (float)(posZ * 1000); 40 x = x + (float)(posX * 1000); 41 y = y + i * 20; 42 43 newPlace.transform.position = new Vector3 (x, y, z);//設置Marker 44 newPlace.transform.LookAt (this.transform); 45 newPlace.transform.Rotate (new Vector3 (0f, 180f, 0f)); 46 47 newPlace.gameObject.GetComponentInChildren<Text> ().text = places [i].Name; 48 } 49 } 50 51 private void ClearPlace(){ 52 GameObject[] oldPlaces = GameObject.FindGameObjectsWithTag ("Place"); 53 for (int i = 0; i < oldPlaces.Length; i++) { 54 Destroy (oldPlaces [i].gameObject); 55 } 56 } 57 }
然后我們把Unity3D中,ARCamera(AR攝像機)的Position,設置為(0,0,0)這么做呢,是方便等會兒設定Marker的坐標,只有相機坐標設置為這樣子,X∆和Z∆的值才是Marker的直接坐標,否則還得進行一些運算。不過這里值得注意的是,坐標系的設定,應該在CameraDevice對象上,否則是無效的。
然后我們修改上述的代碼,修改起來,並不會太難,只需要修改第43行,改成:
20 double posZ = places [i].Latitude - location.Latitude;//計算相對距離,z軸(Unity中的坐標系) 21 double posX = places [i].Longitude - location.Longitude;//計算相對距離,x軸(Unity中的坐標系)
43 newPlace.transform.position = new Vector3 (-x, y, -z);//設置Marker
這樣就完事兒了。。。wuyt2008的博客《unity3d 嘗試 基於地理定位的 增強現實》最后所提及的偏移問題,貌似沒有這種情況,可能是跟EazyAR提供的ARCamera有關,以及鏡頭自動會有東南西北的方向感。最后感謝wuyt2008,最近在做AR的項目CityHunter,一直在研究如何將高德定位整合進Unity3D來,雖然應用方面與其所描述的不太相干(實際上我要運用的是高德API的電子圍欄的功能),但是在操作中可舉一反三,果斷是學習到了。