Search Unity

ARFoundation, move AR Session Origin AFTER placed prefad, to new touch position in prefab

Discussion in 'AR' started by newguy123, Jan 4, 2019.

  1. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    Hi Guys

    I have an Island as my placed prefab, with 3 trees on it. I gave each tree a tag "Waypoint".

    After I place the Island on a ARPlane, I want to touch a tree (any of the trees), then the camera should move over the tree (or more accurately, the AR Sessions Originin should move, giving the appearance that we're flying to the tree). I'm having a hard time doing this. This is my code so far added to a treewaypointmanager:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Experimental.XR;
    5. using UnityEngine.XR.ARFoundation;
    6.  
    7. [RequireComponent(typeof(ARSessionOrigin))]
    8. public class WaypointZoom : MonoBehaviour
    9. {
    10.     ARSessionOrigin m_SessionOrigin;
    11.     GameObject theCam;
    12.  
    13.     public void Start()
    14.     {
    15.         theCam = GameObject.FindGameObjectWithTag("MainCamera");
    16.     }
    17.  
    18.     void Awake()
    19.     {
    20.         m_SessionOrigin = GetComponent<ARSessionOrigin>();
    21.     }
    22.  
    23.  
    24.     public void Update()
    25.     {  
    26.         if (Input.GetMouseButtonDown(0))
    27.         {
    28.             Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    29.             RaycastHit hit;
    30.             if (Physics.Raycast(ray, out hit))
    31.             {
    32.                 if (hit.transform.tag == "Waypoint")
    33.                     //m_SessionOrigin.transform.position = new Vector3(hit.transform.position.x, m_SessionOrigin.transform.position.y, hit.transform.position.z);
    34.                     m_SessionOrigin.MakeContentAppearAt(hit.transform, hit.transform.position, hit.transform.rotation);
    35.             }
    36.         }
    37.  
    38.     }
    39.  
    40. }
    41.  


    In the commented out line, you can also see the other version I tried, still with no success. Neither option does anything when the app runs.
    On the other hand, if I try the code in a simple NON AR scene, ie just a normal cam, with a cube, then the cam does move over the cube.

    So then my question is, how to make it work for AR Foundation?
     
    Suraj_Sangve likes this.
  2. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    I've now also added some text on the canvas to see if the raycast works. Again, when used with a normal cam in a non AR scene, everything works as expected. The cam moves to where the tree is and the text changes. But when its an AR Session scene with AR cam, it doesnt work.

    Between the normal scene and the AR scene, I just swop the code between theCam and m_SessionOrigin (replace m_SessionOrigin with theCam for the normal scene)
     
  3. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    Still havent figured this out yet.
    Anybody have any ideas?
     
  4. tdmowrer

    tdmowrer

    Joined:
    Apr 21, 2017
    Posts:
    605
    MakeContentAppearAt
    is meant to make the content (the first parameter) look like it is at pose (the second parameter). It does this by moving the ARSessionOrigin in the opposite direction. For example, to make the content appear 10 meters in front of me when it is actually 20 meters in front, move the session origin 10 meters forward.

    That means this code
    Code (CSharp):
    1. m_SessionOrigin.MakeContentAppearAt(hit.transform, hit.transform.position, hit.transform.rotation);
    will do nothing, because you are trying to move the session origin to make
    hit.transform
    appear as if it is at
    hit.transform
    . For instance, "make this tree, which is 10 meters in front of me, appear to be 10 meters in front of me." It is already there, so there is nothing to be done.

    The code you have commented out
    Code (CSharp):
    1. m_SessionOrigin.transform.position = new Vector3(hit.transform.position.x, m_SessionOrigin.transform.position.y, hit.transform.position.z);
    Seems correct to me. It's hard to say what is wrong without seeing more of your setup. Can you create a simple repro with a few cubes instead of a complex scene?
     
    newguy123 likes this.
  5. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    New day and fresh mind.
    So this bit:
    Code (CSharp):
    1.     ARSessionOrigin m_SessionOrigin;
    2.     GameObject theCam;
    seem to have been the problem.

    When I made that public, then dragged the objects in there in the editor and played, then it works. Not sure why that works, but findgameobjectwithtag and getcomponent doesnt.

    Anyway, next part of the problem: I don't want the move to be instant like it is now, but rather some kind of deltatime. Will deltatime still work within my if condition of waypoint:
    Code (CSharp):
    1. if (hit.transform.tag == "Waypoint")
     
    Last edited: Jan 8, 2019
  6. tdmowrer

    tdmowrer

    Joined:
    Apr 21, 2017
    Posts:
    605
    You will need to store a target pose and drive the session origin toward it each frame. Something like
    Code (CSharp):
    1. public void Update()
    2. {
    3.     if (Input.GetMouseButtonDown(0))
    4.     {
    5.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    6.         RaycastHit hit;
    7.         if (Physics.Raycast(ray, out hit))
    8.         {
    9.             if (hit.transform.tag == "Waypoint")
    10.                 m_TargetPosition = hit.transform.position;
    11.         }
    12.     }
    13.  
    14.     // Drive toward target position each frame
    15.     m_SessionOrigin.transform.position = Vector3.Lerp(m_SessionOrigin.transform.position, m_TargetPosition, .1f);
    16. }
     
    newguy123 likes this.
  7. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    Thanks, I'll give that a go and let you know....
     
  8. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    I created an empty gameobject and used that as the "target"
    I created a bool to set waypointselected to true/false

    Assigned the original position to this target inside the 1st if and set waypointselected to true

    Then used your code inside another if that checks if waypointselected is true and slightly changed your code to:

    Code (CSharp):
    1. m_SessionOrigin.transform.position = Vector3.Lerp(m_SessionOrigin.transform.position, m_TargetPosition.transform.position, .1f);
    That works great, thanks for the help!

    Just wanted to check, instead of the empty gameobject, is there a way to use "Pose" on its own?
     
  9. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    Hmmm ok I suspect there is something wrong with my code getting the prefab. In my non AR test scene, my prefab is already in the scene and doesnt need to be placed. Therefore it is found when looking at its tag.

    In my AR Scene, I'm looking for it during awake, and obviously it hasnt been placed yet at this stage, so therefore it's not moving anywhere.

    My AR Session code for the scaling and waypoint is therefore correct I suspect, but the code for moving the prefab is called on an "undefined" object. I need to think how to change my awake code to find the prefab and place it somewhere else...
     
  10. newguy123

    newguy123

    Joined:
    Aug 22, 2018
    Posts:
    1,248
    Yes as I suspected, my code to find the prefab should NOT be in Awake()
    If I move it to the update into one of the if's, then it works.

    All sorted, thank!
     
  11. tdmowrer

    tdmowrer

    Joined:
    Apr 21, 2017
    Posts:
    605
    Glad you got it sorted. Just wanted to answer your question:
    You don't need a GameObject just to hold a Pose. A pose is just a struct which stores a position and rotation:
    Code (CSharp):
    1. var pose = new Pose(hit.transform.position, hit.transform.rotation)
     
    AmarIbr and newguy123 like this.