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>