Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronization issues when firing events with a dynamic number of instances #1260

Open
Amatewasu opened this issue Jan 30, 2023 · 1 comment
Labels
bug Something isn't working

Comments

@Amatewasu
Copy link

Amatewasu commented Jan 30, 2023

Hi, thank you a lot for this awesome library!

  • three version: 0.148.0
  • @react-three/fiber version: 8.10.0
  • @react-three/drei version: 9.53.0
  • node version: 17.9.1
  • npm version: 8.11.0

Problem description:

According to the Drei Instances documentation, we can "make them [instances] conditional, mount/unmount them, lazy load them".

In order to get good performances with a lot of shapes, I instance them. When the user interacts with one instance, I load its own geometry (in order to get rid of most of the complexity related to instances) and remove the instance from the instances list.

However, by doing that, the onPointerOver is called twice both with the same instanceId but this instanceId does not correspond to the right object during the second call.

Relevant code:

Here's a code sandbox that reproduces the issue: https://codesandbox.io/s/multiple-instanceid-issue-forked-melpg8?file=/src/App.js

And a gif that depicts the issue:
issue_dre_hover_instances_and_no_instances

To reproduce:

  • Try to hover over different zones
  • and then sometimes another zone is also considered as hovered

If you change instanced={!hoveredZones.has(zoneId)} to instanced={true} (L72), the code works properly. Here's a codesandbox that describes that the code works properly in this case.

Here is the code (from the codesandbox) mounting the instance or the separated plane geometry:

  return instanced ? (
    <Instance
      color={color}
      position={position3D}
      scale={scale3D}
      onPointerOver={(e) => {
        console.log(`onPointerOver (instanced) ${zone.name}, instanceId: ${e.instanceId}, intersections: ${e.intersections}`)

        onPointerOver(e, zone)
      }}
      onPointerOut={(e) => {
        onPointerOut(e, zone)
      }}
    />
  ) : (
    <Plane
      args={[1, 1]}
      material-color={color}
      material-opacity={hoveredOpacity}
      material-transparent={true}
      scale={scale3D}
      position={position3D}
      onPointerOver={(e) => {
        console.log(`onPointerOver (non instanced) ${zone.name}, instanceId: ${e.instanceId}, intersections: ${e.intersections}`)

        onPointerOver(e, zone)
      }}
      onPointerOut={(e) => {
        onPointerOut(e, zone)
      }}
    />
  )
@Amatewasu Amatewasu added the bug Something isn't working label Jan 30, 2023
@Amatewasu
Copy link
Author

Amatewasu commented Feb 1, 2023

For those having the same issue, I've found a pretty good workaround: CodeSandbox.

The idea is the following:

  • keep the instanced mounted but give it a size of 0 so it's not visible on the display anymore
  • replace it with another object (otherwise a pointerOut event will be triggered)

Here's the relevant piece of code:

<group
    onPointerOver={(e) => {
      console.log(`onPointerOver (group) ${zone.name}, instanceId: ${e.instanceId}, intersections: ${e.intersections}`)

      onPointerOver(e, zone)
    }}
    onPointerOut={(e) => {
      onPointerOut(e, zone)
    }}>
    <Instance color={color} position={position3D} scale={instanced ? scale3D : [0, 0, 0]} />
    {!instanced && (
      <Plane
        args={[1, 1]}
        material-color={color}
        material-opacity={hoveredOpacity}
        material-transparent={true}
        scale={scale3D}
        position={position3D}
      />
    )}
  </group>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant