Reputation: 489
I'm trying to render a WebGL image to a canvas using the Three.js library and then use the toDataURL() method on that canvas after the rendering. What I get as I examine the string from toDataURL is just a tiny sphere that is the light source in my scene and the 3D models that are rendered don't appear. The code is mainly taken from one of the examples on the Three.js site. Is there a way to use toDataURL after the whole rendering actually finished?
<script type="text/javascript">
var canvas = document.getElementById("drawing");
var hash;
var SCREEN_WIDTH = canvas.width;
var SCREEN_HEIGHT = canvas.height;
var container, stats;
var camera, scene, canvasRenderer, webglRenderer;
var loader;
var mesh, zmesh, lightMesh;
var directionalLight, pointLight;
var render_canvas = 1, render_gl = 1;
var has_gl = 0;
render_canvas = !has_gl;
function addMesh(geometry, scale, x, y, z, rx, ry, rz, material) {
mesh = new THREE.Mesh(geometry, material);
mesh.scale.set(scale, scale, scale);
mesh.position.set(x, y, z);
mesh.rotation.set(rx, ry, rz);
scene.add(mesh);
}
function init() {
camera = new THREE.PerspectiveCamera(50, SCREEN_WIDTH
/ SCREEN_HEIGHT, 1, 100000);
camera.position.z = 1500;
scene = new THREE.Scene();
// LIGHTS
var ambient = new THREE.AmbientLight(0x101010);
scene.add(ambient);
directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 2).normalize();
scene.add(directionalLight);
pointLight = new THREE.PointLight(0xffaa00);
pointLight.position.set(0, 0, 0);
scene.add(pointLight);
// light representation
sphere = new THREE.SphereGeometry(100, 16, 8, 1);
lightMesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({
color : 0xffaa00
}));
lightMesh.scale.set(0.05, 0.05, 0.05);
lightMesh.position = pointLight.position;
scene.add(lightMesh);
if (render_gl) {
try {
webglRenderer = new THREE.WebGLRenderer({
canvas : canvas,
antialias : true,
alpha : true
});
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
has_gl = 1;
} catch (e) {
alert("browser Doesn't support webGL");
return;
}
}
loader = new THREE.BinaryLoader(true);
loader.load('/static/lucy/Lucy100k_bin.js', function(geometry,
materials) {
addMesh(geometry, 0.75, 900, 0, 0, 0, 0, 0,
new THREE.MeshPhongMaterial({
ambient : 0x030303,
color : 0x030303,
specular : 0x990000,
shininess : 30
}));
addMesh(geometry, 0.75, 300, 0, 0, 0, 0, 0,
new THREE.MeshFaceMaterial(materials));
addMesh(geometry, 0.75, -300, 0, 0, 0, 0, 0,
new THREE.MeshPhongMaterial({
ambient : 0x030303,
color : 0x111111,
specular : 0xffaa00,
shininess : 10
}));
addMesh(geometry, 0.75, -900, 0, 0, 0, 0, 0,
new THREE.MeshPhongMaterial({
ambient : 0x030303,
color : 0x555555,
specular : 0x666666,
shininess : 10
}));
});
}
function animate() {
requestAnimationFrame(animate);
webglRenderer.render(scene, camera);
}
init();
animate();
var dataurl = canvas.toDataURL();
</script>
Upvotes: 2
Views: 5982
Reputation: 25381
create WebGL context with the preserveDrawingBuffer option.
var gl = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true});
var pixelData = new Uint8Array(width * height * 4);
gl.readPixels(left, top, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
console.log(pixelData);
see this question
Upvotes: 1
Reputation: 489
Ok I got it. I needed to add the "preserveDrawingBuffer : true" and to put my screenshot code at the end of the callback function of the loader.
Upvotes: 0
Reputation: 1377
hmmm, well I thought that placing toDataURL() after renderer.render(scene,cam); works fine, but you can set preserverDrawingBuffer: true in the renderer parameters and it works flawlessly although preserverDrawingBuffer cann have a negative impact on resources or performance. See here: http://learningthreejs.com/blog/2011/09/03/screenshot-in-javascript/
Upvotes: 3