Are multiple instances of `WebGLRenderer` ok to use?

I did some research, but I wasn’t able to convince myself, that I’m using the WebGLRenderer right. To be sure, I would like to check this with you guys.

I’m using three.js to render simple geometries in different parts of my website. Each part use it’s own WebGLRenderer. I’m not quite sure if this is a bad practice, a mistake or common to do.

Here is a short example:

export default class CubeAnimation extends React.Component {
  private readonly _renderer = new WebGLRenderer({ antialias: true, alpha: true });

  private _ref: React.RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>();

  constructor(props: {}) {
    // Initialize the scene, light, geometry, etc.
  }

  componentDidMount() {
    this._ref.current?.appendChild(this._renderer.domElement);
    // ...
  }

  render() {
    return <div ref={this._ref} />;
  }
}

<ul>
  <li>
    <CubeAnimation />
  </li>
  <li>
    <CubeAnimation />
  </li>
</ul>

The example above creates two instances of the WebGLRenderer, is that ok?

It’s not ideal to create multiple because of the amount of resources each WebGL context consumes to render 60 frames per second. If it’s only two simple spinning cubes you wouldn’t notice it, but it could quickly get out of control once you start adding more elements.

Instead, you should use a single context that covers the full width/height of the page, and ask it to only render in specific areas, like in this example with multiple elements.

Here’s a second similar example with text in between. It basically uses several <div>s as a placeholder, then on each frame it checks the position of the divs on the screen, and renders those scenes in sequence, so there’s no need to create an extra renderer for each <div>.

2 Likes

it depends. it’s overhead for sure, but can be completely OK under certain circumstances. also keep in mind that the amount of canvas elements is limited in browsers, you can have ~ 20, it seems to vary depending on the browser.

if you are using three in react, use react-three-fiber. with this having multiple canvases is easy, but also performant. it will ootb:

  • accumulate all canvases into a unified renderloop, which removes one of the bigger bottlenecks
  • it can render on demand, so if nothing’s moving in one canvas then it’s not active, another bottleneck removed
  • you can readily re-use some data between canvases, this saves memory
  • you can re-use components in them, which is near impossible otherwise, saves you complexity

here’s an example: The difference between color modes - CodeSandbox notice how the same component (<Sphere />) renders in all four canvases.

vanilla threejs in react is not so feasible imo, but with multiple renderers and without any optimization i think it would be a memory and performance nightmare.