Log in or register to post comments

Using multiple image targets with separate scenes?

November 20, 2013 - 7:12am #1

In my application I have three ImageTargets. I originally had each world attached as a child of the ImageTarget it belonged to and that worked well. Now that my worlds need to have a Unity derived navmesh, I'm not able to keep them in the same scene.

One approach I tried was having a main scene with the ARCamera, and three ImageTargets and I set the "ARCamera Keep Alive" property to true. Then I had three scenes with one of the ImageTargets from the main scene but with its world attached as a child. This enabled me to recognize one ImageTarget and load that scene, but I couldn't recognize any other trackables and I couldn't go back to the main scene after losing tracking. The screen would go black and no more ImageTargets were being tracked.

Another approach I'm trying is to have the main scene contain the ARCamera and the three ImageTargets as well as setting the "ARCamera Keep Alive" and "Trackables Prefabs Keep Alive" properties to true. Then I could parent each scene, which contains each world, to the ImageTarget it belongs to when it is tracked. And I wouldn't have to return to the main scene ever again, because the ImageTargets are all persisted and theoretically the ARCamera would start tracking any new ImageTargets and load those scenes.

I'm not sure if I'm heading in the right direction so I was wondering if anyone had some ideas for me. I did find a post that showed how to use two buttons to switch between scenes from last month but I'm not sure how to apply that to what I'm doing.

Using multiple image targets with separate scenes?

November 22, 2013 - 10:20am #6

Actaully come to find out, the unity navmesh system doesn't allow loading a navmesh from another scene using LoadLevelAdditive. So although this works well for Vuforia's purposes, I can't use it for my original problem. Oh well, thanks for the help though.

Using multiple image targets with separate scenes?

November 20, 2013 - 12:02pm #5

I was using the scene name as the key to that hashmap, so I changed it to the name of the image file for the trackable like it's supposed to be. Now it works perfectly!

Using multiple image targets with separate scenes?

November 20, 2013 - 11:58am #4

I don't set anything to keep alive.  It's load level additive, so it merges one of your scenes with the main one that has the ar camera and targets and then destroys it when tracking is lost.  You'll obvisouly have to fill out the trackables hashtable with your own values and make sure you have your scenes added to the build.

Using multiple image targets with separate scenes?

November 20, 2013 - 11:31am #3

Thanks so much for your script! I'm trying to use it now but I don't see my scene information being loaded. I have the ARCamera set to keep alive, but not the ImageTargets. That's right, right? I'll look more into this but this looks like it might be just what I needed! :)

Using multiple image targets with separate scenes?

November 20, 2013 - 8:04am #2

Here's my DefaultTrackableEventHandler that handles multiple scenes with multiple targets.  Your main scene would contain all the targets and the ARCamera.  Each scene would have a root gameobject and no camera.  Async is Pro only i think, so you may have to use regular loadleveladditive.  Also in this script i run an animation script when the level is loaded, you might want to remove those lines.  Hope it helps.

using UnityEngine;
using System.Collections;

public class DefaultTrackableEventHandler : MonoBehaviour,
                                            ITrackableEventHandler
{
	
    private TrackableBehaviour mTrackableBehaviour;
	
	private Hashtable trackables = new Hashtable();

	private static string currentTrackableName = "";
	private static bool loaded = false;
	private static bool working = false;
	public static bool lostQueued = false;
	public static bool isCurrentlyTracking = false;
	
	private const int SCENE_NAME = 0;
	private const int MODEL_NAME = 1;
	private const int IMAGE_TARGET_NAME = 2;
	
    void Start()
    {
		mTrackableBehaviour = GetComponent<TrackableBehaviour>();
        
		if (mTrackableBehaviour) 
        {
            mTrackableBehaviour.RegisterTrackableEventHandler(this);
        }
		
		trackables.Add("", new string[]	{"", "", "" }); //SCENE_NAME, MODEL_NAME (ROOT GAMEOBJECT), IMAGE_TARGET_NAME
		trackables.Add("", new string[]	{"", "", "" });
		trackables.Add("", new string[]	{"", "", "" });
		
		OnTrackingLost();
    }
	
	void Update()
	{
		if (lostQueued)
		{
			OnTrackingLost();
		}	
	}
	
    public void OnTrackableStateChanged(
                                    TrackableBehaviour.Status previousStatus,
                                    TrackableBehaviour.Status newStatus)
    {
        if (newStatus == TrackableBehaviour.Status.DETECTED ||
            newStatus == TrackableBehaviour.Status.TRACKED)
        {
            OnTrackingFound();
			isCurrentlyTracking = true;
        }
        else
        {
            OnTrackingLost();
			isCurrentlyTracking = false;
        }
    }


    private void OnTrackingFound()
    {
		if (working || loaded || lostQueued)
			return;
		
		working = true;
		loaded = true;
		
        Renderer[] rendererComponents = GetComponentsInChildren<Renderer>();
        foreach (Renderer component in rendererComponents) 
		{
            component.enabled = true;
        }

		foreach(DictionaryEntry t in trackables)
		{
			if (mTrackableBehaviour.TrackableName == t.Key.ToString())
			{
				string[] sa = (string[])t.Value;
				currentTrackableName = t.Key.ToString();
				StartCoroutine(LoadLevel(sa[SCENE_NAME], sa));
			}
		}	
    }
	
	
	IEnumerator LoadLevel(string levelName, string[] levelData)
	{
		AsyncOperation async = Application.LoadLevelAdditiveAsync(levelName);
        yield return async;
		LoadLevelData(levelData[MODEL_NAME], levelData[IMAGE_TARGET_NAME]);
		working = false;
	}
	
    private void OnTrackingLost()
    {
		if (working)
		{
			lostQueued = true;
			return;
		}

		lostQueued = false;
		working = true;
	
		if (!gameObject.activeSelf)
			return;
	
		foreach(DictionaryEntry t in trackables)
		{
			if (currentTrackableName == t.Key.ToString())
			{
				string[] sa = (string[])t.Value;
				DestroyLevelData(sa[MODEL_NAME]);
			}
		}
		
		Renderer[] rendererComponents = GetComponentsInChildren<Renderer>();

        foreach (Renderer component in rendererComponents) 
		{
            component.enabled = false;
        }

	    System.GC.Collect(); 
		
		working = false;
		loaded = false;
    }
	
	private void LoadLevelData(string objectName, string parentName)
	{	
		GameObject go = GameObject.Find(objectName);
		
		if (go != null)
		{
			SetParent(go, parentName);
			AnimationScript script = go.GetComponent<AnimationScript>();
			if (script != null) {
				script.begin();
			}
		}
	}
	
	private void SetParent(GameObject child, string parentName)
	{
		GameObject parent = GameObject.Find(parentName + " Plane");
		if (parent != null && child != null)
		{
			child.transform.parent = parent.transform;
			child.transform.position = parent.transform.position;
		}
	}
	
	private void DestroyLevelData(string objectName)
	{
		GameObject go = GameObject.Find(objectName);
		if (go != null)
		{
			AnimationScript script = go.GetComponent<AnimationScript>();
			if (script != null) script.end();
			Destroy(go);
		}
	}	
}
 
Log in or register to post comments