Sharing the same WebGL context for different canvases

Hello everyone, maybe someone knows an approach how to create one WebGL context and transfer it to different canvases without using drawImage (I’m using drawImage now, but it loads the Firefox browser a lot and I need to find another approach).

not possible afaik. is there a reason you can’t use a rendertarget instead of a separate canvas?

1 Like

I can have up to 32 objects, I display them on separate canvases using layers, I can interact with this objects, I can remove, I can resize it, etc. How can I implement the same through renderTarget?

What are you trying to make, and what do you mean by “32 objects” … 3d meshes / models / Images?

Generally we use 1 canvas over the whole screen to do threejs stuff… you add your objects to the three scene, and control ordering either by position, or by explicitly controlling render order, via .renderOrder , or by rendering in multiple render passes, or by creating renderTargets and rendering objects into them and using the rendertargets as textures on a plane with a material, for the final display.
If you need multiple canvases, for procedurally generated canvas images, you can use THREE.CanvasTexture() to use the canvas as a texture within your scene.

1 Like

I have a main scene when I add a new object, I load a glb model, create a separate canvas for it, add the scene I uploaded to the main scene and assign a layer to the child scene, and so on for new objects.
Given my case, what do you think is the best approach? and could you pls give some examples if there are any

The webgl multiple elements example would be a good place to start. Note that the entire page’s 3D content is drawn with a single WebGL canvas, using viewports and scissor tests.

4 Likes

Are you sure you need multiple canvases?
Can you just load all the glb models into your main scene? (which renders to a single canvas?)
Are you trying to create thumbnails of the models?
in that case, yes… you can make a new renderer and render the model to it, and then create a CanvasTexture of the renderer.domElement, in your main renderer context.
pseudocode:

let generateThumbnailCanvas=(glb)=>{
let thumbRenderer = new THREE.WebGLRenderer({preserveDrawingBuffer:true});
thumbRenderer.setSize(64,64);
let bounds =  new THREE.Box3();
bounds.setFromObject(glb.scene);
thumbCamera.position.copy(bounds.max).multiplyScalar(2);
thumbCamera.lookAt(bounds.getCenter(new THREE.Vector3());
thumbRenderer.render(thumbCamera,glb.scene);
return thumbRenderer.domElement;
}

let mainRenderer = new THREE.WebGLRenderer({preserveDrawingBuffer:true});
let mainScene = new THREE.Scene();
gltfLoader.load("test.glb",(glb)=>{
    let plane = new THREE.Mesh(new THREE.PlaneGeometry(),new THREE.MeshBasicMaterial({map:new THREE.CanvasTexture(generateThumbnailCanvas(glb))})
})
1 Like

I have a list of objects (GLB models), and I can add them to a certain container where a separate object with its own canvas is created, displaying the loaded GLB model. I can interact with this object. I can also delete it (It is also remove its scene from the main scene where all scenes added to the container are stored), or add more. Thus, the addition or removal of GLB models occurs dynamically.
I use drawImage for each new canvas created where the entire main scene is transferred and displayed child scene with a specified layer. The three js allow 32 layers to be used, which allows me to display them in a single created WebGL context. In your example, you create a new WebGL context for each thumbnail, which is very unoptimized for a large number of objects that will have their own WebGL context. I use drawImage for these purposes, and it works great for Chrome, but for Firefox, drawImage is very slow, and I need to consider other options to use one WebGL context and create separate canvases that can be flexibly managed (change size, rotate, change color, apply new animations, etc.).

The created webGL context can be immediately disposed in this context once the reference to it’s webGL context gets gc’ed. That’s why the function returns only the domElement not the renderer itself.

But I still don’t understand what in your scenario requires the use of multiple canvasses. And I am only emphasizing this, because I think it may be a misunderstanding on your part.

Look at the example tthat @donmccurdy linked for a performant approach to creating an object gallery with a single renderer+canvas.

2 Likes

Thank you, I’ll check it out.