Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Let's Start AR with ARCore & Unity

Let's Start AR with ARCore & Unity

Tutorial slide of ARcontents development using ARCore & Unity for beginner.

TakashiYoshinaga

July 17, 2018
Tweet

More Decks by TakashiYoshinaga

Other Decks in Technology

Transcript

  1. Name: Takashi Yoshinaga Affiliation: Institute of Systems,Information Technologies and Nanotechnologies

    Field of work: Application of AR for med. and edu. SNS: Twitter -> @Tks_Yoshinaga LinkedIn -> tks-yoshinaga
  2. ARCore 【Features】 (1) Motion Tracking for realize marker less AR.

    (2) Light Estimation which can estimate light strength and color. (3) Environmental Understanding to recognize floor and wall. (4) Augmented Image to recognize predefined image marker. (5) Cloud Anchor for sharing AR experience among multiple users.
  3. Covered topics in this tutorial 【Features】 (1) Motion Tracking for

    realize marker less AR. (2) Light Estimation which can estimate light strength and color. (3) Environmental Understanding to recognize floor and wall. (4) Augmented Image to recognize predefined image marker. (5) Cloud Anchor for sharing AR experience among multiple users.
  4. Create Unity Project (2/2) Click Create Project after inputting project

    name. 3D Create Project Project Name Save Directory
  5. Save Current Content Open Sample1 Input a scene name (ex.

    sample1) Save Save this scene by Ctrl + S
  6. Put a Virtual Object (1/2) ①GoogleARCore → Examples → Common

    → Prefabs ② Andy Diffuse ③Drag & Drop
  7. Enable Environmental Understanding (4/5) ①Click sample1.asset 【Plane Finding Mode】 (1)Disabled

    (2)Horizontal And Vertical (3)Horizontal (4)Vertical Choose a mode from(2)~(4)
  8. Visualize Detected Planes (4/4) ①GoogleARCore → Examples → Common →

    Prefabs ③DetectedPlaneVisualizer ②Controller ④Drag & Drop to Detected Plane Prefab
  9. Script using System.Collections; using System.Collections.Generic; using UnityEngine; using GoogleARCore; public

    class PutScript : MonoBehaviour { public GameObject andy; //Variable to handle CG(Andy) void Start () { } void Update () { //(1) Detect tap. //(2) Transform 2D position to 3D position of real world. //(3) Put Andy there. } }
  10. Script void Update () { Touch touch; if (Input.touchCount <

    1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began) { return; } //Calculate touched position of detected plane. TrackableHit hit; TrackableHitFlags filter = TrackableHitFlags.PlaneWithinPolygon; if (Frame.Raycast(touch.position.x, touch.position.y, filter, out hit)) { //Move Andy to pointed position. (Next page) } } touch.position hit
  11. Script if (Frame.Raycast(touch.position.x, touch.position.y, filter, out hit)) { // If

    pointed trackable is plane if (hit.Trackable is DetectedPlane ) { //Set the position and the angle of Andy andy.transform.position = hit.Pose.position; andy.transform.rotation = hit.Pose.rotation; andy.transform.Rotate(0, 180, 0, Space.Self); //Set the anchor to fix Andy object to real space. var anchor = hit.Trackable.CreateAnchor(hit.Pose); andy.transform.parent = anchor.transform; } }
  12. Physical Size of Marker[m] ※If width is set to 0,

    marker size will be estimated automatically. Quality should be over 75 for robust detection
  13. Import Object to Unity ②sample2 ①Select Astronaut Folder ③ Drag

    and Drop Astronaut folder into sample2 folder
  14. Script using GoogleARCore; public class MarkerScript : MonoBehaviour { public

    GameObject andy;//Variable to handle Andy public GameObject astronaut;// Variable to handle astronaut //Dictionary to hold pairs of marker id and virtual object Dictionary<int,GameObject> markerDic = new Dictionary<int,GameObject>(); //List of detected marker in each frame. List<AugmentedImage> markers = new List<AugmentedImage>(); void Start() { } void Update() { //Couple marker and object } }
  15. Coupling Variable and Virtual Object ②Controller ①GoogleARCore → Examples →

    Common → Prefabs ③Andy Diffuse ④Drag & Drop to Andy
  16. void Update() { //Obtain markers which tracking state was updated

    Session.GetTrackables<AugmentedImage> (markers,TrackableQueryFilter.Updated); //Couple or remove marker and virtual object foreach (var image in markers) { int index = image.DatabaseIndex; //marker id GameObject obj = null; markerDic.TryGetValue(index, out obj);// get virtual object with id if (image.TrackingState == TrackingState.Tracking && obj == null) { //Couple marker and virtual object. } else if (image.TrackingState == TrackingState.Stopped && obj != null) { //Remove information of marker and virtual object. } } }
  17. void Update() { //Obtain markers which tracking state was updated

    Session.GetTrackables<AugmentedImage> (markers,TrackableQueryFilter.Updated); //Couple or remove marker and virtual object foreach (var image in markers) { int index = image.DatabaseIndex; //marker id GameObject obj = null; markerDic.TryGetValue(index, out obj); // get virtual object with id if (image.TrackingState == TrackingState.Tracking && obj == null) { //Couple marker and virtual object. } else if (image.TrackingState == TrackingState.Stopped && obj != null) { //Remove information of marker and virtual object. } } }
  18. if (image.TrackingState == TrackingState.Tracking && obj == null) { Anchor

    anchor = image.CreateAnchor(image.CenterPose); switch (index) { case 0://AndyMarker obj = GameObject.Instantiate(andy, anchor.transform); obj.transform.localPosition = new Vector3(0, 0.02f, -0.04f); obj.transform.Rotate(-90, 0, 0, Space.Self); obj.transform.localScale =new Vector3(0.3f, 0.3f, 0.3f); markerDic.Add(index, obj); break; case 1://earth obj = GameObject.Instantiate(astronaut, anchor.transform); obj.transform.localPosition = new Vector3(0.02f, 0.04f, 0); obj.transform.Rotate(90, 0, 0, Space.Self); obj.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f); markerDic.Add(index, obj); break; } }
  19. void Update() { //Obtain markers which tracking state was updated

    Session.GetTrackables<AugmentedImage> (markers,TrackableQueryFilter.Updated); //Couple or remove marker and virtual object foreach (var image in markers){ int index = image.DatabaseIndex; //marker id GameObject obj = null; markerDic.TryGetValue(index, out obj); // get virtual object with id if (image.TrackingState == TrackingState.Tracking && obj == null) { //Coupling marker and virtual object. } else if (image.TrackingState == TrackingState.Stopped && obj != null) { markerDic.Remove(image.DatabaseIndex); Destroy(obj); } } }
  20. CloudAnchor Information is shared in the same device in this

    tutorial. (Works as Area Learning of Google Tango)
  21. You can see how the application works from following link.

    https://twitter.com/Tks_Yoshinaga/stat us/1006137365239173120
  22. Preparation for Next Tutorial using UnityEngine; using GoogleARCore; public class

    AnchorScript : MonoBehaviour { public GameObject andy; // Use this for initialization void Start() { } // Update is called once per frame void Update () { Touch touch; if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began) { return; } Rename class name toAnchorScript
  23. Script public class AnchorScript : MonoBehaviour { // Use this

    for initialization void Start() { } public void HostAnchor() { } public void ResolveAnchor() { } void Update () { //Detect Button tapping or screen tapping //Put Andy on a plane if user taps screen. (Not button) //save current position of Andy } } Upload Environment Information Matching the space with Cloud Anchor
  24. Distinguish button tap or screen tap using UnityEngine.EventSystems; public class

    AnchorScript : MonoBehaviour { /*Omitted: Start,HostAnchor,ResolveAnchor*/ void Update () { if (EventSystem.current.IsPointerOverGameObject (Input.GetTouch(0).fingerId)) { return; } Touch touch; if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began) { return; } TrackableHit hit; TrackableHitFlags filter = TrackableHitFlags.PlaneWithinPolygon; /*Omitted*/
  25. Holding current position of Andy Anchor currentAnchor = null; void

    Update () { /*Ommited: Detection of screen tap */ if (Frame.Raycast(touch.position.x, touch.position.y, filter, out hit)) { if ((hit.Trackable is DetectedPlane) && Vector3.Dot(Camera.main.transform.position – hit.Pose.position,hit.Pose.rotation * Vector3.up) > 0) { //Setting position and angle of Andy andy.transform.position = hit.Pose.position; andy.transform.rotation = hit.Pose.rotation; andy.transform.Rotate(0, 180, 0, Space.Self); //Setting anchor var anchor = hit.Trackable.CreateAnchor(hit.Pose); andy.transform.parent = anchor.transform; currentAnchor = anchor; } } }
  26. Holding current position of Andy using GoogleARCore; using UnityEngine.EventSystems; using

    GoogleARCore.CrossPlatform; using UnityEngine.UI; public class AnchorScript : MonoBehaviour { public GameObject andy; Anchor currentAnchor = null; public Text txt; //Used for display the state of saving cloud anchor bool connecting = false; //state of connecting or disconnecting to CCP void Start() { } public void HostAnchor() { } Save the environmental information and cloud anchor (See next page..)
  27. Hosting current position of Andy public void HostAnchor() { if

    (connecting || currentAnchor == null) { return; } connecting = true; txt.text = "hosting..."; //uploading environmental information. XPSession.CreateCloudAnchor(currentAnchor).ThenAction(result => { connecting = false; if (result.Response != CloudServiceResponse.Success) { txt.text = "Please Try Again"; return; } txt.text = result.Anchor.CloudId; }); }
  28. 【Test】 ① Wait for planes are detected. ② Put Andy

    on a plane ③ Tap the Host button. ④ Bottom text will be hosting... ⑤ ID will shown if upload is success 【Next Step】 ① Shut down and reboot this app. ② Call Cloud Anchor API with ID ③ Match space with now and before ④ Andy will appear the same position. Enable saving ID in the next step
  29. Saving ID of Cloud Anchor using UnityEngine.EventSystems; using UnityEngine.UI; using

    System.IO; public class AnchorScript : MonoBehaviour { public GameObject andy; Anchor currentAnchor = null; public Text txt; bool connecting = false; string filePath; void Start() { filePath = Application.persistentDataPath + "/anchorID.txt"; } public void HostAnchor() { } Uploading environmental information (編集中)
  30. Saving ID of Cloud Anchor public void HostAnchor() { if

    (connecting || currentAnchor == null) { return; } connecting = true; txt.text = "hosting..."; //環境情報をアップロード XPSession.CreateCloudAnchor(currentAnchor).ThenAction(result => { connecting = false; if (result.Response != CloudServiceResponse.Success) { txt.text = "Please Try Again"; return; } txt.text = ""; StreamWriter sw = new StreamWriter(filePath, false); sw.WriteLine(result.Anchor.CloudId); sw.Close(); }); }
  31. Next Step public class AnchorScript : MonoBehaviour { // Use

    this for initialization void Start() { } public void HostAnchor() { } public void ResolveAnchor() { } void Update () { //Detect Button tapping or screen tapping //Put Andy on a plane if user taps screen. (Not button) //save current position of Andy } } Upload Environment Information Matching the space with Cloud Anchor
  32. Load ID From Text File. public void ResolveAnchor() { if

    (connecting) { return; } connecting = true; // Read ID from text file FileInfo file = new FileInfo(filePath); StreamReader sr = new StreamReader(file.OpenRead()); string cloudAnchorId = sr.ReadLine(); sr.Close(); txt.text=cloudAnchorId; }
  33. 【Test】 ① Put Andy on a detected plane. ② Tap

    Host button ③ Shut down the application. ④ Reboot this application. ⑤ Tap Resolve button. ⑥ ID will appear on the bottom of screen. 【Next Step】 ① Call Cloud Anchor API with ID ③ Match space with CloudAnchor. ④ Position of Andy will reproduced. ここにIDが表示される
  34. Matching Space with Clouc Anchor public void ResolveAnchor() { /*Omitted:

    Loading ID from text file.*/ //txt.text = cloudAnchorId; txt.text ="resolving..."; XPSession.ResolveCloudAnchor(cloudAnchorId).ThenAction(result => { connecting = false; if (result.Response != CloudServiceResponse.Success) { txt.text = "Please Try Again"; return; } txt.text = ""; andy.transform.position = result.Anchor.transform.position; andy.transform.rotation = result.Anchor.transform.rotation; andy.transform.Rotate(0, 180, 0, Space.Self); andy.transform.parent = result.Anchor.transform; }); }