pmndrs / react-three-next

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

[Solved] Sharing View / r3f components across Canvas / Scene.tsx ? #170

Open rohanrehman opened 1 month ago

rohanrehman commented 1 month ago

@RenaudRohlinger great work on this!

Canvas is instantiated in Scene.txt

Keeping with framework conventions adding a View in the Scene to survive navigation returns an error.

export default function Scene({ ...props }) {
  // Everything defined in here will persist between route changes, only children are swapped
  return (
    <Canvas {...props}
      onCreated={(state) => (state.gl.toneMapping = THREE.AgXToneMapping)}
    >

          <View className='relative h-full sm:h-48 sm:w-full'>
              <Duck route='/blob' scale={2} position={[0, -1.6, 0]} />
          </View>

      {/* @ts-ignore */}
      <r3f.Out />
      <Preload all />
    </Canvas>
  )
}

Error: R3F: Div is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively

since you've added <div ref={localRef} {...props} /> to View.tx

Any r3f components created needs to be wrapped in View to be rendered, is there no way to add an r3f component that will be rendered across all app directory pages?

Thanks

rohanrehman commented 1 month ago

this solution leverages drei View components and its latest docs. Quick example off adding a Plane in the Scene that survives navigation while adjusting z index with tailwind to accommodate mouse event interaction of other Views rendered in rf3.Out.

import { Preload, Plane, View } from '@react-three/drei'

export default function Scene({ ...props }) {
  // Everything defined in here will persist between route changes, only children are swapped
  return (
    <>
      <View className='pointer-events-none absolute left-0 top-0 z-[-1] h-[600px] w-full bg-green-300'>
        <Plane args={[2, 2]} position={[-2, 0, 0]} {...props} />
      </View>
      <Canvas {...props} onCreated={(state) => (state.gl.toneMapping = THREE.AgXToneMapping)}>
        <View.Port />
        <r3f.Out />
        <Preload all />
      </Canvas>
    </>
  )
}