canvasthree.jswebgl

Three.js and HTML5 Canvas toDataURL


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>

Solution

  • 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/