Canvas rerendering or camera resetting on route change

I am using react-three-fiber.

I am using the faces of the cubes to function as links to go to my routes. The links are transparent pages that are in front of my scene. I use OrbitControls to rotate the cube to click the faces. I indicate what face is being hovered by setting a highlight material on intersected objects from raycast.

The link does successfully change moment I click a face to change the link, but the camera is reset to its original position.

The material of the Cube is also reset to its original and I lose the highlight hover effects.

When I try to click the faces behind the cube, the front faces of the cube are the ones outputted in console.

I assume react rerenders my components, canvas included, therefore it gets reset when remounted? How do I keep my CubeScene the same when changing links?

it’s hard to read the code tbh, like 90% of the threejs code can be removed, fiber already has pointer events, you dont need to raycast, you don’t need to imperatively create meshes and materials.

other than that it looks to me like you do not persist the canvas in between route changes? your canvas should be able to handle routes just like anything else in react, you wouldn’t reconstruct everything anew but react to routes, exchange and alter scene contents. the <Route> component from react-router can be within canvas, all of its hooks as well.

also consider the nextjs boilerplate, takes care of some common issues

1 Like

thanks, using the pointer events simplified everything a lot. everything works as intended now. though, I have a question about the object event data. how would I access material property from an Object3D object? I needed to type cast e.object as Mesh in order to set the material.

      {meshes.map((mesh) => (
        <mesh
          key={mesh.name}
          name={mesh.name}
          position={mesh.position}
          rotation={mesh.rotation}
          geometry={plane}
          material={default_material}
          onPointerEnter={(e) => _onPointerEnter(e, e.object as Mesh)}
          onPointerLeave={(e) => _onPointerLeave(e, e.object as Mesh)}
        />
      ))}

  function _onPointerEnter(e: ThreeEvent<MouseEvent>, mesh: Mesh) {
    e.stopPropagation()
    mesh.material = highlight_material
  }

  function _onPointerLeave(e: ThreeEvent<MouseEvent>, mesh: Mesh) {
    e.stopPropagation()
    mesh.material = default_material
  }

for example, I couldn’t use e.object.material = highlight_material

it’s better if the view is the pure outcome of state:

but either way, you cast it, i think there is no way typescript can possibly know what mesh it is, given that a mesh can have meshes as children.

1 Like