I'm using three.js to create an interactive web application, and I've run into a little stumbling block:
I have a number of canvases contained in draggable divs on the page. In each canvas I hope to display an unlit 3D object with a different material applied (each material is using custom shaders). All of those materials work off the same texture (one might be blue-tinted, one might be desaturated, etc.).
The number of canvases on the page can vary, but I expect the number to commonly reach/exceed 20 canvases, and as such sharing resources (particularly for large textures) would be very beneficial.
Up until now I have been using multiple renderers, cameras and scenes which has worked fine until I started trying to use the same texture in multiple scenes.
Most of the materials share uniforms and attributes to avoid having to duplicate the information, and also so that all of the materials stay in sync with one another (e.g. when some of the materials change over time they should all change in the same way).
I was wondering if there was a way I would be able to share textures between the scenes/renderers/canvases? When I try I get the following error:
WebGL: INVALID_OPERATION: bindTexture: object not from this context
In my research trying to find a solution for this problem I came across the suggestion that this could be solved by creating multiple viewports, however I do not know how to display different viewports over different canvases.
TL/DR;
Can I either:
Thanks in advance!
Griffork
Unfortunately you can not (yet) share resources across canvases. A couple of options
Render the different viewports in different parts of the same canvas.
Example: http://webglsamples.org/multiple-views/multiple-views.html
Make a canvas that covers the entire window, use place holder elements to figure out where to draw, use getClientBoundingRect to set the viewport & scissor settings to draw scenes in each element
Example: Is it possible to enable unbounded number of renderers in THREE.js?
Render the scene to an offscreen canvas then draw it into a visible canvases.
<canvas id="c1"></canvas>
<canvas id="c2"></canvas>
<script>
var webglCanvas = document.createElement("canvas");
var canvas1 = document.getElementById("c1");
var ctx1 = canvas1.getContext("2d");
var canvas2 = document.getElementById("c1");
var ctx2 = canvas1.getContext("2d");
... draw scene into webglCanvas from one view...
// copy scene to canvas1
ctx1.drawImage(webglCanvas, 0, 0);
... draw scene into webglCanvas from another view...
// copy scene to canvas2
ctx2.drawImage(webglCanvas, 0, 0);
Here's a live example (note: It's slow on Windows in Chrome26, FF20, Hopefully that will be fixed in future browsers)
Use OffscreenCanvas, transferToImageBitmap etc... (note: this feature has not shipped in any browser as of 2018/1/8 but it's available behind a flag on Firefox)
const one = document.getElementById("one").getContext("bitmaprenderer");
const two = document.getElementById("two").getContext("bitmaprenderer");
const offscreen = new OffscreenCanvas(256, 256);
constr gl = offscreen.getContext('webgl');
// ... some drawing for the first canvas using the gl context ...
gl.clearColor(1,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Commit rendering to the first canvas
let bitmapOne = offscreen.transferToImageBitmap();
one.transferImageBitmap(bitmapOne);
// ... some more drawing for the second canvas using the gl context ...
gl.clearColor(0,1,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Commit rendering to the second canvas
let bitmapTwo = offscreen.transferToImageBitmap();
two.transferImageBitmap(bitmapTwo);
<canvas id="one"></canvas>
<canvas id="two"></canvas>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With