pmndrs / react-three-next

React Three Fiber, Threejs, Nextjs starter
https://react-three-next.vercel.app/
MIT License
2.52k stars 342 forks source link

Viewport size inaccurate inside <View/> #137

Open bryndsey opened 1 year ago

bryndsey commented 1 year ago

I'm trying to use viewport values inside of useFrame to position items relative to the size of the viewport. However, when resizing the browser window, the value will rapidly switch between the correct value and something that is not correct.

To reproduce, start from the base template and update the Dog component in Example.jsx to the following:

export function Dog(props) {
  const { scene } = useGLTF('/dog.glb')
  const ref = useRef(null)

  useFrame((state) => {
    if (ref.current === null) return

    ref.current.position.x = state.viewport.width / 4
  })

  return <primitive object={scene} {...props} ref={ref} />
}

Then, run the app, and when resizing the browser window, you can see the dog jitter back and forth between the expected position and somewhere else:

https://github.com/pmndrs/react-three-next/assets/2722461/f81d8ec7-4601-4881-b600-e99bec93d388

You can also log viewport.width to see that the values reported there are inaccurate at times. The same behavior can also be observed using useThree((state) => state.viewport) and using the result.

I also experimented with structuring the code such that I was using drei's built-in version of View as opposed to the wrapped version and it still occurred there, so that seems to rule out tunnel-rat as the issue. I also tried it out in a non-Next.js context, and the issue doesn't seem to occur (see sandbox). While it could be an issue with drei's underlying View implementation, since this template was the only place I've seen the issue, I figured I'd start here.

I can work around the issue by measuring the tracked div's size myself using something like react-use-measure, passing the sizing values to the canvas content, and then using state.viewport.getCurrentViewport(cameraRef.current, viewportTarget, bounds). This provides the correct viewport sizing, but has a number of drawbacks (managing extra refs, passing bounds arounds, extra arguments needed for getCurrentViewport), so not ideal.