How to save rendering scene to img?

I make a scene, and now I want to save it when user click a button. Everything comes from I want to do some image processing through shader and save the result, because I know that shader has high performance. The demo is below:
JSFiddle demo
I know how to save 2d canvas:

init2D()

function init2D() {
  // 2d context save code
  var cav = document.querySelector('#ctx2d'),
    ctx = cav.getContext('2d')
  ctx.beginPath();
  ctx.arc(20, 20, 50, 0, Math.PI);
  ctx.stroke();
  ctx.closePath()
  var base64 = cav.toDataURL()
  document.querySelector('#img').src = base64
}


But how to save three.js scene to img, it seems not work.

Hey, I think the answer is in preserving the drawing buffer. it is a gl property, which defaults to false, and you want it set to false generally for performance, so you could use some logic here to set it to true just before snapping the shot, then set it back to false after the image has been snapped and returned.

You can either preserve the drawing buffer as @amvdxc noticed by defining the renderer like so:

renderer = new THREE.WebGLRenderer({
    antialias: true,
    preserveDrawingBuffer: true,
});

this might make your rendering slow on old video cards / mobiles.

Or you need to capture the image at the same pass of JavaScript that executes renderer.render() function, before buffers swap, like so:

let snap = false;

const capture = () => {
  const cav = document.querySelector('#container canvas');
  const base64 = cav.toDataURL('img/png');
  document.querySelector('#img').src = base64;
};

document.getElementById('btn').addEventListener('click', () => { snap = true; });
...

function animate() {
  requestAnimationFrame(animate);

  renderer.render(scene, camera);
  if(snap) {
  	capture();
  	snap = false;
  }
}
3 Likes

Thank you for reply. I try above two methods, the second method has good performance. :grin:

1 Like