How to have simultaneous image targets in Studio?

Hi, I’m wondering if I can have two different image targets activating at the same time in Studio. If I simply add two image targets, only one will activate at a time.

I tried to search for this and found Simultaneous Targets | 8th Wall Playground | 8th Wall , but this example was made in legacy editor and I don’t know how to translate that into Studio editor. I’m wondering if anyone can tell me how or have a working example made with the Studio editor that I can look at. Thanks in advance!!

You can have up to 32 Image Targets in loaded at any given time with Studio, you simply need to upload the Image Target and then add the Image Target entity to your space. If only one in view is working at a time my thoughts are the other Image Targets aren’t set to “Auto Load”. If you don’t auto load the Image Target it won’t be found unless it’s loaded programmatically.

Can you land your changes and share the project with the support workspace so I can take a look?

thanks for replying, I shared the “image track test” project with support.

So I have a different question now - I have made two image targets and I can get the two models (the 8 and the well) to show up simultaneously, but I want to create the following effect: when I move the target image close to each other and the 8 and well collide, I want to trigger some event (in my toy example, I want to bring up dodeca.glb).

So I have added collide.ts and added it as a component to infin8-white.glb (1). I also have

  stateMachine: ({world, eid, schemaAttribute}) => {
    // Use a state machine for simple event listening
    ecs.defineState('default')
      .initial()
      .listen(world.events.globalId, ecs.physics.COLLISION_START_EVENT, (e) => {
        console.log('hello world collide')

but this never seems to get triggered even though I see the two models (the well and the 8) are moving in and out of each other. Can you tell me what I’m doing wrong here?

Thanks!

You need to add a Collider component to the entities for the objects to register in the physics system. You might be better off with a pre-baked animation made in something like Blender though and exporting that as a glb and simply playing the animation when both targets are in frame.

Thanks, I’m not sure if you’re able to look at the share project, but I do have the Physics Collider component on both infin8-white.glb (1) and well.glb (1). Is this not where I should add it?

Also thanks for the workaround suggestion; although I would like to understand how the collision events work since I’m sure this will be very useful to know going forward.

Collisions can be tricky. Since these are Static bodies, you’ll need to change them to Kinematic (because you’re moving them with code rather than forces like gravity). Static bodies don’t generate physics events since they’re not meant to move.

If you find that two Kinematic bodies aren’t generating physics events, let me know. There have been some recent changes to our physics system with the 2.0 release, and we’re still ironing out a few bugs.

Thanks; I tried changing both physics colliders to Kinematic and I still don’t see the listener for COLLISION_START_EVENT getting triggered.

I’ve reviewed this with the engineering team, and it looks like the behavior you’re seeing is due to a bug. Currently, collision events are only generated when at least one of the bodies is marked as Dynamic.

While I don’t have a timeline for when a fix will be released, as a workaround you can either set one of the objects to Dynamic with a gravity factor of 0, or bake the animation as previously mentioned.

ahh thank you so much, I tried what you suggested with Dynamic and it indeed worked.

As for the animation suggestion - what’s the best way to know when both targets’ models are triggered and displayed in frame?

I’d recommend handling this with a Custom Component. Here’s an example you could build from:

import * as ecs from '@8thwall/ecs'

ecs.registerComponent({
  name: 'Multi Image',
  schema: {
    firstImageTargetName: ecs.string,
    secondImageTargetName: ecs.string,
  },
  schemaDefaults: {
    firstImageTargetName: '',
    secondImageTargetName: '',
  },
  stateMachine: ({world, eid, schemaAttribute, dataAttribute}) => {
    const foundTargets = []

    ecs.defineState('default')
      .initial()
      .listen(world.events.globalId, 'reality.imagefound', (e) => {
        const {name} = e.data as any
        const {firstImageTargetName, secondImageTargetName} = schemaAttribute.get(eid)

        if (name === firstImageTargetName) {
          foundTargets[0] = name
        } else if (name === secondImageTargetName) {
          foundTargets[1] = name
        }

        if (foundTargets.length === 2) {
          // Both images found
        }
      })
      .listen(world.events.globalId, 'reality.imagelost', (e) => {
        const {name} = e.data as any
        const {firstImageTargetName, secondImageTargetName} = schemaAttribute.get(eid)

        if (name === firstImageTargetName) {
          foundTargets[0] = undefined
        } else if (name === secondImageTargetName) {
          foundTargets[1] = undefined
        }

        if (foundTargets.length === 0) {
          // Both images lost
        }
      })
  },
})