pmndrs / react-three-fiber

🇨🇭 A React renderer for Three.js
https://docs.pmnd.rs/react-three-fiber
MIT License
27.38k stars 1.57k forks source link

offscreencanvas #280

Closed nikitapilgrim closed 4 years ago

nikitapilgrim commented 4 years ago

https://evilmartians.com/chronicles/faster-webgl-three-js-3d-graphics-with-offscreencanvas-and-web-workers Did you manage to implement it in your projects?

drcmda commented 4 years ago

looks nice, but seems to me, like most workers i have seen, scaling it is messy. loaders, input events, etc. perhaps with a reconciler like r3f you could pull it off without causing that much damage. pointer input for instance is all predefined and could be transported into the worker.

you wanna give it a go?

drcmda commented 4 years ago

then again, i see that most of the threejs logic is inside the worker. that essentially kills declarativity since now you're doing everything imperatively again. 🤔

in our projects we tree shake the hell out of threejs manually to about 50kb (https://github.com/react-spring/react-three-fiber/blob/master/recipes.md#reducing-bundle-size) and bundle splitting/suspense. that takes three out of the picture for the first load.

mashafomasha commented 4 years ago

You could use @react-three/fiber with OffscreenCanvas with help of custom renderer.

In main thread create canvas and transfer it to the worker like this:

// main.jsx (main thread)
import React from "react"

export const Main = () => {
  const canvasRef = React.useRef()

  React.useEffect(() => {
    const offscreen = canvasRef.current.transferControlToOffscreen()
    const worker = new Worker('worker.js')
    worker.postMessage({ canvas: offscreen }, [offscreen])
  }, [])

  return <canvas ref={canvasRef} />
}

Inside worker create custom WebGLRenderer with offscreen canvas passed to it. Then use this custom renderer as said in the docs like this:

// worker.jsx (worker thread)
import { createRoot } from '@react-three/fiber'

ctx.onmessage = (event) => {
  const { canvas } = event.data
  createRoot(canvas).render(<ReactThreeFiberComponent />)
}
drcmda commented 4 years ago

that could work. in src/targets there are the building blocks for making render targets, for instance ResizeContainer, in which the the renderer is ramped up. you could try to wire this into a worker. although im sure it wont be so easy later on. pointer events, everything that has to sync between main and worker is going to be hell.