Multiple Image Tracking in iOS Workaround

Hi! I know I cannot use multiple images as trackers in AR at once on iOS. The good thing is, I don’t need them at the same time or in the same AR session.

My idea was: I let the user choose in the HTML UI which mural (mural #1 or mural #2) should be animated in AR. Shortly before switching to AR mode—before my scene is converted into USDZ—I enable or disable the correct object with the ImageTracking component.

So, I have two WebXR Image Tracking components in my scene, but only one is set to active. I also have a custom script that sets the correct object I want to export to USDZ (it switches between the two objects depending on whether the user selected mural #1 or mural #2).

I noticed that Quick Look seems to ignore which WebXR Image Tracking component is active and which isn’t, and it starts mixing up the image trackers. (It feels like it always picks the one that was active when I exported my needle project)

Do you have any workaround ideas? I was thinking of using only one WebXR Image Tracking component with two images in an array, and then removing one shortly before entering AR. But iOS doesn’t open scenes at all if there are two images in the array.

Hi Katja Rempel,

This is a known limitation when exporting scenes with multiple image tracking components for use in AR Quick Look on iOS. Quick Look essentially “bakes in” the initial scene state, meaning that even though you disable one of the WebXR Image Tracking components before export, iOS still “sees” the tracker active at the time of export. This can result in the behavior you’re describing, where Quick Look mixes up the image trackers and always uses the one that was active during export.

A reliable workaround is to only include a single active image tracker in the scene at export time. In other words, you can generate two separate USDZ files – one for mural #1 and one for mural #2 – each containing only the relevant WebXR Image Tracking component. This way, iOS Quick Look loads a USDZ file with only one image tracker, avoiding the conflict you’re seeing.

If generating separate USDZ files isn’t practical for your workflow, another approach is to completely remove the inactive image tracker from the scene (instead of simply disabling it) just before export. However, given that USDZ export captures a static snapshot of the scene, any state that isn’t fully removed may still be incorporated during the conversion process.

It might also be worthwhile to double-check that you’re using the latest version of Needle Engine, as improvements and workarounds for platform-specific AR behavior (see the WebXR Image Tracking docs at WebXRImageTracking.d.ts.md and (docs/xr.html)) may have been introduced.

I hope this helps clarify your options. Let me know if you need further details or assistance with your workflow!

4 replies left
thread_5DCraH4veuSfK0L60WjXJ8mB
Reply to this post directly if you need further help (bottom right button)

That is what I tried, but in this case the tracking is working only for one tracked image. I know it sounds like it shouldnt happen. My hierarchy is

  • Image1Group
    -ObjectToPlaceOnImage
    -ObjectWithWebXRImageTracking Component With 1 ImageTracker (for image 1)

  • Image2Group
    -ObjectToPlaceOnImage
    -ObjectWithWebXRImageTracking Component With 1 ImageTracker (for image 2)

And I pass only one of the group to USDZ exporter to export. Nevertheless it seems to access the other WebXRImageTracking Component

Hi Katja,

There’s a simple solution/workaround yes:

Instead of multiple WebXRImageTracking components you should have one ImageTrackingComponent with all your images and just move the image you want to become active in iOS AR to the first entry in the trackedImages list.

That being said: I think this should also work as you described. Going to look into it right now

cc @hybridherbst

Hi @Marcel_Wiessler1 thank you for the reply!
In my experience, when I try to export a WebXRImageTracking Component with a longer array (2 items), Quicklook will not open the USDZ file at all, writing "you need a newer iOS version”

But I will also try it again, to get 100% sure

The exporter does explictly only export the first image since iOS AR does not support multiple images so this is most likely unrelated

I set up a quick test based on the ImageTracking Sample scene - with the same result of “You need a newer iOS version.

I can send you a Bug report with this scene.
And the exported project to try out is here https://imagetracking-1chvlrzrmk5v-latest.needle.run/

And the error doesnt appear when you have two WebXRImageTracking components with the same objects in the same scene?

not when one of them is set to “not active”.

But let me make the same setup with the sample-scene

So, I checked:

2 separate active WebXRTracking Components with 1 image each in 1 Scene –> “Newer iOS error”
1 active WebXRTracking Components with 2 images in 1 Scene –> “Newer iOS error”

2 separate WebXRTracking Components with 1 image each, (1 is active, the secons is disabled) –> Scene will open.

Right now I am trying to understand why turning the image-tracking “groups” on/off in runtime before exporting do not behave as they should (they always pick the same image-tracker, even when this image is not in the exported group). Will keep you in the loop

Here is what I tried in my simplified test:turn the group i do not want to export off, say to the usdzExporter which object-group to export.But I get the same “newer iOS version” error this time.

```import { Behaviour, GameObject, Renderer, USDZExporter, serializable } from "@needle-tools/engine";

import { Material, Object3D } from "three";



export class SwitchARGroups extends Behaviour {



    @serializable(GameObject)

    group1: GameObject | undefined; 

    @serializable(GameObject)

    group2: GameObject | undefined;



    @serializable()

    group1On: boolean = true;



    private originalMaterial?: Material;

    private usdzExporter!: USDZExporter;



    onEnable() {

        this.usdzExporter = GameObject.findObjectOfType(USDZExporter)!;

        this.subscribeToBeforeExportEvent();

    }



    onDisable() {

        this.unsubscribeFromBeforeExportEvent();

    }



    private subscribeToBeforeExportEvent() {

        this.usdzExporter.addEventListener("before-export", this.onBeforeExport);

        this.usdzExporter.addEventListener("after-export", this.onAfterExport);

    }



    private unsubscribeFromBeforeExportEvent() {

        this.usdzExporter.removeEventListener("before-export", this.onBeforeExport);

        this.usdzExporter.removeEventListener("after-export", this.onAfterExport);

    }



    onBeforeExport = () => {

        console.log("onBeforeExport");



        if (this.group1 && this.group2) {

            this.group1.activeSelf = this.group1On;

            this.group2.activeSelf = !this.group1On;

        }



        // check which group is active and set the exporter to that group

        const groupToExport = this.group1On ? this.group1 : this.group2;



        this.usdzExporter!.objectToExport = groupToExport;

    }



    onAfterExport = () => {

        console.log("onAfterExport");

        this.group1On = !this.group1On;

        //



    }

}

Hi Katja, I’m currently testing my changes to improve reliability of Image Tracking for USDZ. Been just successfully testing with the project you sent (no error on export and I get the different object/image tracked depending on what i turn on/off in Unity). It will then work both with multiple ImageTracking components (first component / first image will be tracked as before)

Will test a bit more but most likely it’ll just work as you have it right now without any hacks on your side with the next version

What you can do right now to test is open your web project’s package.json and force the pre-release needle engine version. Just remember to remove this syntax later when you update your Unity package again to let the version be managed by Unity :slight_smile:

package.json

  "dependencies": {
	  "@needle-tools/engine": "npm:@needle-tools/engine@4.8.7-next.1715881",
          ....
   }

You might need to restart your local server to see the change applied

Thank you, Marcel! We are getting further.
I used the pre-released version, and I do not get “new iOS”-error anymore!

But what is still strange, in my scene with two groups (the last one I described and shared code of here in forum):

  • switching objects bevore exporting them ist working
  • BUT both groups (wether I export group 1 or group 2 (each with the richt image-tracking component) they both are recognizing my first image tracker (the one with the cactus)

I exported the project in case you want to try it: https://imagetracking-only_first-tracker_working-1chvlrz1fhy4v-z1fhy4v.needle.run/

here are both images I use for tracking:

@Marcel_Wiessler1 , can it be, that Quicklook/USDZExporter somehow caches the setting of the object I export as USDZ first? and when I exit ar, select another group to export, it exports the right object to place, but takes the cached Image Tracker information?

I made a test which somehow proves that. I will write it down

My test looked like this.

2 groups with different objects to place:

Each time I press AR-Button, i toggle between the groups and export only 1 group

  • If in the first group i export is Group 1 (with WebXRImageTracking ), I go back, click “enter AR”, export the second group → the second group will have ImageTracking behaviour (even though there is no WebXRImageTracking conponent)
    **
    BUT
    **
  • if the first group i export is Group 2 (the one without WebXRImageTracking ), I go back, click “enter AR”, export the Group 1 → the Group 1 will have no ImageTracking behaviour (even though there is a WebXRImageTracking component inside this group)

The workaround with 1 WebXRTracking component and 2 Images is working :slight_smile:
I just change the order of the images in the array as you suggested :folded_hands:

Nevertheless I am still curious why another method did not work as expected :slight_smile: