Log in or register to post comments

rotating camera in NONE mode

November 2, 2011 - 5:49am #1

For my Unified Coordinate System project here:
https://ar.qualcomm.at/arforums/showthread.php?t=1030
I need the camera to be in NONE mode, meaning the camera will be stationary and the markers appearing to float in front of it. But if I do this, the physics will not work correctly. So I modified the gravity vector to fix this. This works ok, but not with rapid physical camera rotations. So I have to make the Unity3d scene stationary while the camera moves around it.

The mathematics for this isn't really the problem. The problem is that QCAR expects the camera to be stationary in NONE mode. If I force the camera to be in any other position and rotational attitude, then the marker position and rotation changes as well. This, perhaps, is to be expected and it shouldn't be too much of a problem if I know what the relation between the two is so I can take into account the changed marker transform.

In other words, if I change the transform of the camera, what would I need to do to the transform of the detected marker to make it appear as if the camera transform didn't change at all?

I have been monitoring what changing the camera transform in NONE mode does to the marker transform but I can't decipher it.
Any hints?

rotating camera in NONE mode

August 21, 2018 - 12:34pm #14

Can anybody help me?

I'm new to Unity and Vuforia and created an augmented reality model based on gps, but when visualizing or constructing my project, the 3d model appears exactly in the coordinates, as expected, however the model is running (or the camera is running) without stopping . I want the model to stand in relation to the world and I walk around it with the cell phone.

 

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class PortoAR : MonoBehaviour {

    public float originalLatitude;

    public float originalLongitude;

    private float currentLongitude;

    private float currentLatitude;

    private GameObject distanceTextObject;

    private double distance;

    private bool setOriginalValues = false;

    private Vector3 targetPosition;

    private Vector3 originalPosition;

    private float speed = .1f;

    IEnumerator GetCoordinates()

    {

        //while true so this function keeps running once started.

        while (true)

        {

            // check if user has location service enabled

            if (!Input.location.isEnabledByUser)

                yield break;

            // Start service before querying location

            Input.location.Start(1f, .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

            {

                // 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 save coordinates of player on app start

                if (setOriginalValues)

                {

                    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();

        }

    }

    //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

    }

    void Start()

    {

        //get distance text reference

        distanceTextObject = GameObject.FindGameObjectWithTag("distanceText");

        //start GetCoordinate() function

        StartCoroutine("GetCoordinates");

        //initialize target and original position

        targetPosition = transform.position;

        originalPosition = transform.position;

    }

    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);

    }

}

rotating camera in NONE mode

January 9, 2014 - 12:35am #13

Great, Happy that I was helpful to put you on track; and thanks for the tip with void OnPostRender() :  very nice and simple solution !

rotating camera in NONE mode

January 8, 2014 - 7:28pm #12

AlessandroB wrote:

Ok, let me try to recap, if I understand correctly:

- you are using World Center Mode = CAMERA (previously called NONE)

- you want to obtain the Pose (position and orientation) of the Trackables (targets/markers) expressed with respect to the Camera reference frame (regardless of where the "software" camera is located in World coordinates)

Is that a correct understanding ?

Yes, that is correct.
Thanks for the code. That did indeed work. However, is no need to calculate all three vectors. This works as well:

private void FixMarkerTransform(out Vector3 position, out Quaternion rotation, GameObject markerObject){

	// Get the trackable position in World coordinates
	Vector3 tbPos_WordRef = markerObject.transform.position;
	
	// Get the local orientation axis (U,V,W) in World coordinates
	Vector3 tbV_WordRef = markerObject.transform.TransformDirection(Vector3.up);
	Vector3 tbW_WordRef = markerObject.transform.TransformDirection(Vector3.forward);
	
	// Normalize axis to have unit length
	tbV_WordRef.Normalize();
	tbW_WordRef.Normalize();
	
	// Compute position and orientation axis in Camera coordinates
	// i.e. with respect to the camera
	position = Camera.main.transform.InverseTransformPoint(tbPos_WordRef);
	Vector3 tbV_CamRef = Camera.main.transform.InverseTransformDirection(tbV_WordRef);
	Vector3 tbW_CamRef = Camera.main.transform.InverseTransformDirection(tbW_WordRef);
	
	// Normalize axis to have unit length
	tbV_CamRef.Normalize();
	tbW_CamRef.Normalize();

	rotation = Quaternion.LookRotation(tbW_CamRef, tbV_CamRef);
}

By the way, this doesn't work for both frame markers and image targets, only one of them (forgot which):

StateManager sm = TrackerManager.Instance.GetStateManager();
IEnumerable<TrackableBehaviour> tbs = sm.GetActiveTrackableBehaviours();

That doesn't matter though. I already got that part to work. But I found out that adding this script to the camera has the same effect:

void OnPostRender() {

	Camera.main.transform.position = Vector3.zero;
	Camera.main.transform.rotation = Quaternion.identity;
}

That uses less CPU power :-)

rotating camera in NONE mode

January 7, 2014 - 7:30am #11

The following code snippet computes the position and orientation of a trackable with respect to the camera, no matter where the camera is positioned:

public class TargetCoords : MonoBehaviour {

	void Update () {
		Vector3 camPos = Camera.main.transform.position;

		StateManager sm = TrackerManager.Instance.GetStateManager();
		IEnumerable<TrackableBehaviour> tbs = sm.GetActiveTrackableBehaviours();

		foreach (TrackableBehaviour tb in tbs) {
			// Get the trackable position in World coordinates
			Vector3 tbPos_WordRef = tb.transform.position;

			// Get the local orientation axis (U,V,W) in World coordinates
			Vector3 tbU_WordRef = tb.transform.TransformDirection(Vector3.right);
			Vector3 tbV_WordRef = tb.transform.TransformDirection(Vector3.up);
			Vector3 tbW_WordRef = tb.transform.TransformDirection(Vector3.forward);

			// Normalize axis to have unit length
			tbU_WordRef.Normalize();
			tbV_WordRef.Normalize();
			tbW_WordRef.Normalize();

			// Compute position and orientation axis in Camera coordinates
			// i.e. with respect to the camera
			Vector3 tbPos_CamRef = Camera.main.transform.InverseTransformPoint(tbPos_WordRef);
			Vector3 tbU_CamRef = Camera.main.transform.InverseTransformDirection(tbU_WordRef);
			Vector3 tbV_CamRef = Camera.main.transform.InverseTransformDirection(tbV_WordRef);
			Vector3 tbW_CamRef = Camera.main.transform.InverseTransformDirection(tbW_WordRef);

			// Normalize axis to have unit length
			tbU_CamRef.Normalize();
			tbV_CamRef.Normalize();
			tbW_CamRef.Normalize();

			Debug.Log (tb.TrackableName + " - Pos: " + tbPos_CamRef.ToString() + " - U: " + tbU_CamRef + " - V: " + tbV_CamRef + " - W: " + tbW_CamRef);

			// Note: the localScale will be the same in either reference frames, since the camera does not alter the scale
		}
	}
}

 

rotating camera in NONE mode

January 7, 2014 - 6:39am #10

Ok, let me try to recap, if I understand correctly:

- you are using World Center Mode = CAMERA (previously called NONE)

- you want to obtain the Pose (position and orientation) of the Trackables (targets/markers) expressed with respect to the Camera reference frame (regardless of where the "software" camera is located in World coordinates)

Is that a correct understanding ?

rotating camera in NONE mode

January 7, 2014 - 3:36am #9

Not sure if that will work. The only thing I did in QCARBehaviour was resetting the camera transform to zero. The problem is that Vuforia changes the marker transform if the software camera transform changes in "World Center Mode = CAMERA" (previously called NONE).

If I change the software camera transform, I don't want the marker transform to change because I am only interested what the marker transform is in relation to the hardware camera. Vuforia is the only AR API which has this behaviour, none of the others do that.

Do you know any other trick to force Vuforia report the marker pose with reference to the hardware camera only?

rotating camera in NONE mode

January 7, 2014 - 12:52am #8

Hi Elecman. Any chance that you could bring your logic from QCARBehaviour to an external script ? for example, what about using the ITrackerEventHandler and hook your code in OnTrackablesUpdated() ?

Could that work ? 

 

rotating camera in NONE mode

January 5, 2014 - 12:49am #7

Unfortunately Vuforia 2.8 breaks compatibility with UCS. How do I make the previously discussed modifications to QCARBehaviour.cs? The QCARBehaviour code is now located in a DLL now so I can't modify it, nor can I change the script execution order.

Re: rotating camera in NONE mode

December 15, 2011 - 3:53am #6

Thanks Kim. I tried it, but none of the methods work. The only way to get it to work is to add the camera reset code to TrackerBehaviour.cs (EDIT: QCARBehaviour.cs in v1.5+)
If you can add it as a feature (so the developer can decide if the unity3d camera movement affects things or not) it would be great.

Not to nag, but with String it works out of the box. I emailed them to ask if this is a coincidence and they replied that it is designed this way. Unity3d camera movement in NONE mode or comparable mode is not supposed to influence the tracking transform.

Re: rotating camera in NONE mode

December 3, 2011 - 10:09am #5

http://unity3d.com/support/documentation/ScriptReference/WaitForEndOfFrame.html

Now the next frame will start with the camera at the origin. You would still need to use script ordering to make sure the TrackerBehaviour Update method is called before you move the camera. Or, you could move the camera in the LateUpdate method:

http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.LateUpdate.html

Just some thoughts. I do agree that we can probably improve this with a change to our ARCamera, I have a feature request queued up.

- Kim

Re: rotating camera in NONE mode

November 30, 2011 - 10:45pm #4

Bump

Kim, is there any chance of incorporating this into the QCAR code?

Re: rotating camera in NONE mode

November 6, 2011 - 7:43am #3

I finally made it to work. Your method didn't had the desired effect but it did point me in the right direction.

So the aim is to either offset the detected marker transform for the error produced by changing the Unity3d camera, or make QCAR ignore the Unity3d camera transform when it is calculating the marker transform. I went for the last option because it involves less math and is therefore faster. This is how to solved the problem:

In "TrackerBehaviour.cs" (EDIT: QCARBehaviour.cs in v1.5+) go to the Update() function and add these lines at the beginning of that function:

Camera.main.transform.position = Vector3.zero;
Camera.main.transform.rotation = Quaternion.identity;

Then click on any script in the Project window, and on the top of the inspector, click on "Execution Order". Put TrackerBehaviour.cs (EDIT: QCARBehaviour.cs in v1.5+) on top and the script with the custom camera positioning code below that.

This brings me to a feature request for QCAR:

I don't like to modify the QCAR code, so could you add an option that makes QCAR ignore the camera transform and always use the identity transform when calculating the marker pose when that box is ticked? If this option would work without the need to re-order the script execution, that would be great. Thanks

Re: rotating camera in NONE mode

November 2, 2011 - 9:45pm #2

If you position the camera before the TrackerBehaviour's Update method is called then the augmentations will move accordingly. That's somewhat tricky to do without using Unity 3.4's script ordering feature, or otherwise diving into the TrackerBehaviour script. If you were willing to modify our code I might suggesting adding another callback to the ITrackerEventHandler interface that is called before the trackables are updated. This won't necessarily be future-proof as our SDK is updated, however.

If you knew for a fact that your code was called after the TrackerBehaviour's Update method (e.g. you could use LateUpdate, or the ITrackerEventHandler OnTrackablesUpdated callback) then you could move the camera and trackables in lockstep to keep their relative position. I might suggest a little parenting trick here, here's a script that worked for me:

using UnityEngine;

// A custom handler that implements the ITrackerEventHandler interface.
public class TrackerEventHandler : MonoBehaviour,
                                   ITrackerEventHandler
{
    public TrackableBehaviour mTrackable;

    void Start()
    {
        TrackerBehaviour trackerBehaviour = GetComponent<TrackerBehaviour>();
        if (trackerBehaviour)
        {
            trackerBehaviour.RegisterTrackerEventHandler(this);
        }

        Camera.main.transform.position = new Vector3(100, 0, 0);
    }

    // Implementation of the ITrackerEventHandler function called after all
    // trackables have changed.
    public void OnTrackablesUpdated()
    {
    	// attach the trackable to the camera
    	mTrackable.transform.parent = Camera.main.transform;

    	// move the camera
        Camera.main.transform.RotateAround(Vector3.zero, Vector3.up, -60 * Time.deltaTime);
        Camera.main.transform.transform.LookAt(Vector3.zero);
        Debug.Log("camera position: " + Camera.main.transform.position + ", rotation: " + Camera.main.transform.rotation);

        // detach the trackable
        mTrackable.transform.parent = null;
    }
}

- Kim

Log in or register to post comments