Threejs Canvas zu PNG / JPG

Canvas Pfad, Kurven und Kreisbögen oder Cancas Arc mit Javascript

Es gibt zwei Varianten, um das Bild in einem Canvas als PNG oder JPG zu speichern: die ältere Methode canvas.toDataURL und die bessere canvas.toBlob.

23-02-02 SITEMAP

canvas.toBlob

In den meisten Browsern wird der Screenshot einer 3D-Szene mit canvas.toBlob zwar ordnungsgemäß geladen, bleibt aber Schwarz, denn die Browser löschen der Performance zuliebe den WebGL-Canvas direkt nach dem Rendern.

Der Render-Code muss vor dem capture aufgerufen werden.

function render() {
   if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
   }
   cube.rotation.x += 0.01;
   cube.rotation.y += 0.01;
   cube.rotation.z += 0.01;
   renderer.render(scene, camera);
   requestAnimationFrame(render);
}

Den Klick auf den Button abfangen, um einen Screenshot mit der aktuellen Größe des canvas einzufangen:

const elem = document.querySelector('#button');
elem.addEventListener('click', () => {
   render();
   canvas.toBlob((blob) => {
      saveBlob(blob, "capture-" + 
              document.getElementById("canvas").width + " x " + 
              document.getElementById("canvas").height + ".png"
      );
   });
});

Die Animation mit requestAnimationFrame

const state = {
   time: 0,
};

function animate(time) {
   state.time = time * 0.001;
   render();
   requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

Die Funktion saveBlob erzeugt den Screenshot, setzt ihn in ein a-Element und lädt die Datei direkt herunter.

const saveBlob = (function() {
   const a = document.createElement('a');
   document.body.appendChild(a);
   a.style.display = 'none';
   return function saveData(blob, fileName) {
      const url = window.URL.createObjectURL(blob);
      a.href = url;
      a.download = fileName;
      a.click();
   };
}());

Das vollständige Script

<script type="module">
import * as THREE from '/threejs/r109/build/three.module.js';

function main() {
   const canvas = document.querySelector('#canvas');
   const renderer = new THREE.WebGLRenderer({canvas});

   const camera = new THREE.PerspectiveCamera(75, 2, 0.1, 5);
   camera.position.z = 2;
   const scene = new THREE.Scene();

   {
      const light = new THREE.DirectionalLight({ color: 0xFFFFFF }, 1);
      light.position.set(-1, 2, 4);
      scene.add(light);
   }

   const geometry = new THREE.BoxGeometry(1, 1, 1);
   const material = new THREE.MeshPhongMaterial({color:"plum"});
   const cube = new THREE.Mesh(geometry, material);
   scene.add(cube);

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

   const state = { time: 0 };

   function render() {
      if (resizeRendererToDisplaySize(renderer)) {
         const canvas = renderer.domElement;
         camera.aspect = canvas.clientWidth / canvas.clientHeight;
         camera.updateProjectionMatrix();
      }
      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;
      cube.rotation.z += 0.01;
      renderer.render(scene, camera);
   }

   function animate(time) {
      state.time = time * 0.001;
      render();
      requestAnimationFrame(animate);
   }
   requestAnimationFrame(animate);

   const elem = document.querySelector('#capture');
   elem.addEventListener('click', () => {
      render();
      canvas.toBlob((blob) => {
         saveBlob(blob, "capture-" + document.getElementById("canvas").width + " x " + document.getElementById("canvas").height + ".png");
      });
   });

  const saveBlob = (function() {
    const a = document.createElement('a');
    document.body.appendChild(a);
    a.style.display = 'none';
    return function saveData(blob, fileName) {
       const url = window.URL.createObjectURL(blob);
       a.href = url;
       a.download = fileName;
       a.click();
    };
  }());
}

main();

</script>