2 Vuforia in Unity
Tutorial: https://www.youtube.com/watch?v=X6djed8e4n0&t=213s
Preparation:
Download "Vuforia for Unity" from https://developer.vuforia.com/downloads/sdk?d=windows-30-16-4815&retU
import Vuforia into Unity by dragging "vuforia-unity-xxx.unitypackage" into Unity project window
AR Camera:
Assets > Vuforia > Prefabs > drag ARCamera into the scene & save as ufoScene
Add a license key in https://developer.vuforia.com/targetmanager/licenseManager/licenseListing
Select ARCamera object and Open Vuforia Configuration in the inspector window, and put in app license key
save and run, the camera is on~
Import Game Asset: http://wirebeings.com/markerless-gps-ar.html
extract it and drag it into unity
drag a flying disk into the scene; scale to 0.1; position to (4.3, 29.7, 200)
now the ufo is fixed on the center of the screen
For the purpose of fixing the position of the ufo at the geolocation in reality:
Change World Center Mode to "Device Tracking"
Open Vuforia Configuration and tick Enable device pose track
UI Text: to show the distance
add UI > Text called distance, and adjust the position and change the text color and content, change Horizontal Overflow to overflow
add a UI Image as the background for the UI Text, adjust the position and change the color and transparent
add a tag called distanceText and set the tag of Text distance to it
Script:
add a script called AugmentedScript to Flying Disk object
ref: http://wirebeings.com/markerless-gps-ar.html
using UnityEngine; using System.Collections; using UnityEngine.UI; public class AugmentedScript : MonoBehaviour { private float originalLatitude; private float originalLongitude; private float currentLongitude; private float currentLatitude; private GameObject distanceTextObject; private double distance; private bool setOriginalValues = true; private Vector3 targetPosition; private Vector3 originalPosition; private float speed = .1f; IEnumerator GetCoordinates() { // update/get device‘s gps coordinates } public void Calc(float lat1, float lon1, float lat2, float lon2) {// calculates distance between two sets of coordinates, taking into account the curvature of the earth } void Start(){ // initialization } void Update(){ // update each frame } }
Script Comments:
void start(): initialization
void Start(){ // get the reference to UIText distance to get the user gps coordinates distanceTextObject = GameObject.FindGameObjectWithTag ("distanceText"); // keep getting the gps coordinates from the phone StartCoroutine ("GetCoordinates"); // initialize target and original position, transform refers to the flying disk targetPosition = transform.position; originalPosition = transform.position; }
void update(): update each frame
void Update(){ // linearly interpolate from current position to target position transform.position = Vector3.Lerp(transform.position, targetPosition, speed); // rotate by 1 degree about the y axis every frame transform.eulerAngles += new Vector3 (0, 1f, 0); }
Vector3.Lerp(): https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
public static Vector3 Lerp(Vector3 a, Vector3 b, float t)
Linearly interpolates between the vectors a
and b
by the interpolant t (t = [0,1])
When t
= 0 returns a
. When t
= 1 returns b
. When t
= 0.5 returns the point midway between a
and b
.
IEnumerator GetCoordinates(): update/get device‘s gps coordinates
IEnumerator GetCoordinates() { // while true so this function keeps running once started. while (true) { // code from LocationService.Start documentation sample // https://docs.unity3d.com/ScriptReference/LocationService.Start.html // check if user has location service enabled if (!Input.location.isEnabledByUser) yield break; // Start service before querying location Input.location.Start (1f, 0.1f); // Wait until service initializes int maxWait = 20; while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0) { yield return new WaitForSeconds (1); maxWait--; } // Service didn‘t initialize in 20 seconds if (maxWait < 1) { print ("Timed out"); yield break; } // Connection has failed if (Input.location.status == LocationServiceStatus.Failed) { print ("Unable to determine device location"); yield break; } else { // start doing the device‘s coordinates processing // Access granted and location value could be retrieved print ("Location: " + Input.location.lastData.latitude + " " + Input.location.lastData.longitude + " " + Input.location.lastData.altitude + " " + Input.location.lastData.horizontalAccuracy + " " + Input.location.lastData.timestamp); // if original value has not yet been set, then save player‘s coordinates when app starts if (setOriginalValues) { // "private bool setOriginalValues = true;" at the start originalLatitude = Input.location.lastData.latitude; originalLongitude = Input.location.lastData.longitude; setOriginalValues = false; } //overwrite current lat and lon everytime currentLatitude = Input.location.lastData.latitude; currentLongitude = Input.location.lastData.longitude; //calculate the distance between where the player was when the app started and where they are now. Calc (originalLatitude, originalLongitude, currentLatitude, currentLongitude); } Input.location.Stop(); } }
Input.location.Start(): https://docs.unity3d.com/ScriptReference/LocationService.Start.html
public void Calc(float lat1, float lon1, float lat2, float lon2): calculates distance between two sets of coordinates, taking into account the curvature of the earth
public void Calc(float lat1, float lon1, float lat2, float lon2) { var R = 6378.137; // Radius of earth in KM var dLat = lat2 * Mathf.PI / 180 - lat1 * Mathf.PI / 180; var dLon = lon2 * Mathf.PI / 180 - lon1 * Mathf.PI / 180; float a = Mathf.Sin(dLat / 2) * Mathf.Sin(dLat / 2) + Mathf.Cos(lat1 * Mathf.PI / 180) * Mathf.Cos(lat2 * Mathf.PI / 180) * Mathf.Sin(dLon / 2) * Mathf.Sin(dLon / 2); var c = 2 * Mathf.Atan2(Mathf.Sqrt(a), Mathf.Sqrt(1 - a)); distance = R * c; distance = distance * 1000f; // meters //set the distance text on the canvas distanceTextObject.GetComponent<Text> ().text = "Distance: " + distance; //convert distance from double to float float distanceFloat = (float)distance; //set the target position of the ufo, this is where we lerp to in the update function targetPosition = originalPosition - new Vector3 (0, 0, distanceFloat * 12); //distance was multiplied by 12 so I didn‘t have to walk that far to get the UFO to show up closer }
Build:
switch platform in build settings to Android
in player settings >
Identification > packageName: com.Company.ProductName
Build
Install:
go to .../Android/sdk/platform-tools
confirm your mobile device by ./adb devices
install the signed .apk by ./adb install apk_dir
and it works!
Oh...not really. The geo-location can not be access since there is no permission for the app to access gps service
if (!Input.location.isEnabledByUser) yield break;
http://answers.unity3d.com/questions/38222/android-plugin-and-permissions.html
--> set permissions in manifest.xml
Assets > Plugins > Android > AndroidManifest.xml
add <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
https://docs.unity3d.com/Manual/android-manifest.html;
https://developer.android.com/reference/android/Manifest.permission.html
And then I figure out the solution showed above is not a solution.
what actually happened in my device is the "Time Out", rather than "isEnabledByUser"
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Monaco; color: #f4f4f4; background-color: #000000 }
span.s1 { }