Canvases vs. Views?

Hello!
I want to create multiple threejs scenes on my page, one on the top of the page, another or the bottom.
Is there any general rule that suggest the usage of multiple views inside one Canvas?
Are there any caveats or drawback of using multiple canvases on the same page?
In terms of performance, is it better to use several Canvases or several Drei Views inside one Canvas?
Or is it just a matter of personal preference?

Two Canvases

<Canvas className="canvas">
        <ambientLight intensity={1} />
        <mesh>
            <boxGeometry/>
            <meshStandardMaterial color="red" />
        </mesh>
      </Canvas>
      <Canvas>
      <mesh position={[1,1,1]}>
            <boxGeometry />
            <meshStandardMaterial color="blue" />
        </mesh>
        <OrbitControls makeDefault />
      </Canvas>

VS

Multiple Views inside one Canvas

import "css/books.css"
import { useRef, Suspense } from 'react'
import { Canvas } from '@react-three/fiber'
import { View, Preload, OrbitControls, useGLTF } from '@react-three/drei'

export default function Books() {
  const ref = useRef(null)
  const box = useRef(null)
  const box2 = useRef(null)
  const journal = useGLTF(process.env.PUBLIC_URL + '/journal.glb')
  return (
    <div ref={ref} className="container">
      <div className="text">
        <div ref={box} className="view scale" style={{ height: 300 }} />
        <div ref={box2} className="view scale" style={{ height: 300 }} />
      </div>
        
      <Canvas eventSource={ref} className="canvas">
        <View track={box}>
        <ambientLight intensity={1} />
        <primitive object={journal.scene} scale={3} rotation={[Math.PI / 2, 0, 0]}/>
          <mesh rotation={[Math.PI/2, Math.PI/2, Math.PI/2]}>
            <boxGeometry />
            <meshStandardMaterial color="red" />
          </mesh>
          <OrbitControls makeDefault />
        </View>
        <View track={box2}>
            <ambientLight intensity={1} />
            <mesh position={[1,1,1]}>
                <boxGeometry />
                <meshStandardMaterial color="blue" />
            </mesh>
          <OrbitControls makeDefault />
        </View>
        <Preload all />
      </Canvas>
    </div>
  )
}

In my experience, multiple views on a single canvas appear to almost always better performing.
This example three.js examples
Illustrates this really well imo. If you tried to do this example with multiple canvasses, it would be really slow, and I’ve examined this in the context of creating windowing systems with threejs.

4 Likes

using views is correct. like @manthrax said, multiple canvas take resources, performance, you can’t share data between them, the browser will kill them if you have an arbitrary amount of them.

view gives you almost full isolation, and it’s cheap.

im sure you’ve seen it but here are some example use cases in case you haven’t

3 Likes

Thank you for your answer!

1 Like

Thank you for your answer!

1st example has a problem where sometimes the pink view starts jumping really fast between two different mouse positions, back and forth (ff / win).

that’s just me not understanding which dom coordinates to use. it gets 0/0 for some reason for a frame so <View> happily places it there. the hover stuff is user land implemented with this code

      onPointerMove={(e) => {
        const x = e.nativeEvent.offsetX
        const y = e.nativeEvent.offsetY - e.target.offsetTop - 100
        fRef.current.style.transform = `translate3d(${x}px,${y}px,0)`
      }}

the - 100 is completely arbitrary, i don’t know how to calculate it properly tbh. in the hands of someone that knows dom/css a little better it’ll be fine. :smile:

when in doubt, use getBoundingClientRect() :sweat_smile:

1 Like

i’ve been doing nothing but threejs for so long i forgot it even existed.

but now that you mention it, i once made a library to fix nightmarish gBCR shortcomings GitHub - pmndrs/react-use-measure: 🙌 Utility to measure view bounds :rofl: would have been be the perfect use case for it.