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>