I am trying to create a visual illusion allowing a smooth transition from one scene to another using the MeshPortalMaterial
from react/three-drei
. To achieve this, I have tried using the PerspectiveCamera
from theatre.js
for the movement of the camera, but I have only little knowledge about the local position and the global position. So I decided to use two PerspectiveCamera
, one placed inside the MeshPortalMaterial
, with the other one placed outside of it. After spending some time tweaking the camera params using threatre.js
, I managed to get it work as intended, a little bit janky, but it worked. I have attached a gif below the code.
I wonder if I can use only one camera throughout the whole experience?
Are there any better approaches to do this?
Any caveats I should know when using the
MeshPortalMaterial
?In addition, I have been using components from
react-three/drei
likeSky
andSparkles
, and I noticed turning onEffectComposer
would mess up the color and the transparency of the material, I have tried using thelinear
colorspace management, but the color was still off. It's very noticeable in the gif below.
Please let me know if you need more info, I highly appreciate any help I can get, I have been struggling quite a bit. Thank you.
import { useRef } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { MeshPortalMaterial, ScrollControls, useScroll } from '@react-three/drei'
import { getProject, val } from '@theatre/core'
import studio from '@theatre/studio'
import extension from '@theatre/r3f/dist/extension'
import { editable as e, SheetProvider, PerspectiveCamera } from '@theatre/r3f'
import HomeScene from '@/src/components/scene/HomeScene'
const sheet = getProject('Portfolio Project').sheet('Portfolio Sheet')
studio.initialize()
studio.extend(extension)
const cameraConfig = {
fov: 60,
near: 0.1,
far: 40
}
function Scene() {
const windowPortalRef = useRef(null)
const scroll = useScroll()
useFrame(() => {
const sequenceLength = val(sheet.sequence.pointer.length)
sheet.sequence.position = scroll.offset * sequenceLength
})
return (
<>
<PerspectiveCamera
theatreKey='Camera'
makeDefault
fov={cameraConfig.fov}
near={cameraConfig.near}
far={cameraConfig.far}
/>
<mesh>
<planeGeometry args={[5, 5, 1]} />
<MeshPortalMaterial ref={windowPortalRef} blend={0}>
<PerspectiveCamera
theatreKey='Camera2'
makeDefault
fov={cameraConfig.fov}
near={cameraConfig.near}
far={cameraConfig.far}
/>
<HomeScene windowPortalRef={windowPortalRef} />
</MeshPortalMaterial>
</mesh>
</>
)
}
export default function Experience() {
return (
<main className='fixed left-0 top-0 z-0 h-full w-full overflow-hidden'>
<Canvas
flat
// linear
// eventPrefix='client'
// eventSource={document.getElementById('root') as HTMLElement}
gl={{ preserveDrawingBuffer: true }}
>
<ScrollControls pages={1} damping={0.5} maxSpeed={1}>
<SheetProvider sheet={sheet}>
<Scene />
</SheetProvider>
</ScrollControls>
</Canvas>
</main>
)
}