Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't FileReader pass file to loader.load() used by three.js scene?

I'm trying to use FileReader to pass a client side ASCII file to loader.load() but it looks like the file never gets there. The file does appear in the 3D scene if I use loader.load('server path to test_file.stl') instead of loader.load(fileObject).

I included an alert() function to display the file's ASCII text and that tells me the JavaScript is grabbing and processing the file and there is no Chrome security barrier but apparently I'm not properly passing the file to loader.load().

<!DOCTYPE html>
<html>
<head>
<style>
    body        {
            background-color:#fea47c;
                }

    div         { 
            position:relative;
            left:200px;           
            top:0px;
            background-color: #eeeeee;
            border:1px solid black;             
            width:550px;
            height:550px;
                }

    canvas      {
            width:550px;
            height:550px;
                }
</style>
</head>

<body>

<script src="https://raw.github.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/loaders/STLLoader.js"></script>      
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script> 

<input type="file" id="pickfile"></input>

<script> 

   document.getElementById('pickfile').addEventListener('change', readFile, false);

    function readFile (evt) 
                {
    var fileObject = evt.target.files[0];    
    var reader = new FileReader();
    reader.onload = function() {alert(this.result)};    // verifies ASCII file contents were grabbed
    reader.readAsText(fileObject)
                }

        var container, camera, scene, renderer, controls;

        init();
        animate();

        function init() {

            container = document.createElement( 'div' );
            document.body.appendChild( container );

            var width = container.clientWidth;
            var height = container.clientHeight;

            camera = new THREE.PerspectiveCamera( 35, width / height, .1 , 10000);

            camera.position.set( 0, 0, 600);

            scene = new THREE.Scene();

            controls = new THREE.TrackballControls( camera , container); 
            controls.addEventListener( 'change', render );

            // object

            var loader = new THREE.STLLoader();
            loader.addEventListener( 'load', function ( event ) {

                var geometry = event.content;

                var material = new THREE.MeshLambertMaterial( { ambient: 0xff5533, color: 0xff5533 } );

                var mesh = new THREE.Mesh( geometry, material );

                scene.add( mesh );

            } );

            loader.load(fileObject);

            // lights

            scene.add( new THREE.AmbientLight( 0x222222 ) );

            var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
            directionalLight.position = camera.position;
            scene.add( directionalLight );

            // renderer

            renderer = new THREE.WebGLRenderer( { antialias: true } );
            renderer.setSize( width , height );
            container.appendChild( renderer.domElement );

            window.addEventListener( 'resize', onWindowResize, false );


        }

        function addLight( x, y, z, color, intensity ) {

            var directionalLight = new THREE.DirectionalLight( color, intensity );
            directionalLight.position.set( x, y, z )
            scene.add( directionalLight );

        }

       function onWindowResize() {   

            camera.aspect = width / height;
            camera.updateProjectionMatrix();

            renderer.setSize( width, height );
        }

        function animate() {

            requestAnimationFrame( animate );
            controls.update();
            render();

        }

       function render() {

           camera.lookAt( scene.position );
           renderer.render( scene, camera );

       }

</script>

</body>
</html>
like image 908
ForumLeech Avatar asked Jan 14 '23 18:01

ForumLeech


2 Answers

Ok, I tried again this morning, and I think the problem was I was trying to view the loaded results from a bad camera angle or something... anyways, here's an example based on https://raw.github.com/mrdoob/three.js/master/examples/webgl_loader_stl.html

The essential part:

Like I mentioned above, loader.load does not have any overload that would take the actual contents of the file (and it's kinda silly to think it would). It will only take a location for the file... you needed something that creates your model from the file contents. That would be loader.parse.

For example, the following handler adds your model to a scene where scene is in scope of readFile:

function readFile(evt)
{
    var fileObject = evt.target.files[0];
    var reader = new FileReader();
    reader.onload = function ()
    {
        var loader = new THREE.STLLoader();
        //alert(this.result)
        var geometry = loader.parse(this.result);
        var material = new THREE.MeshPhongMaterial(
        {
            ambient: 0xff5533,
            color: 0xff5533,
            specular: 0x111111,
            shininess: 200
        });
        var mesh = new THREE.Mesh(geometry, material);
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        scene.add(mesh);
    };
    reader.readAsText(fileObject)
}

Whole example:

I'd put this somewhere on the net but as it uses github to host some of the scripts, etc. that's probably not the best idea.

<!DOCTYPE html>
<html>
    <head>
        <style>
            body {
                font-family: Monospace;
                background-color: #000000;
                margin: 0px;
                overflow: hidden;
            }
            #info {
                color: #fff;
                position: absolute;
                top: 10px;
                width: 100%;
                text-align: center;
                z-index: 100;
                display:block;
            }
            #pickfile {
                color: #fff;
                position: absolute;
                top: 40px;
                width: 100%;
                text-align: center;
                z-index: 100;
                display:block;
            }
            a {
                color: skyblue
            }
        </style>
    </head>

    <body>
        <script src="https://raw.github.com/mrdoob/three.js/master/build/three.min.js"></script>
        <script src="https://raw.github.com/mrdoob/three.js/master/examples/js/loaders/STLLoader.js"></script>
        <script src="https://raw.github.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
        <script src="https://raw.github.com/mrdoob/three.js/master/examples/js/Detector.js"></script>
        <script src="https://raw.github.com/mrdoob/three.js/master/examples/js/libs/stats.min.js"></script>
        <input type="file" id="pickfile"></input>
        <script>
            document.getElementById('pickfile').addEventListener('change', readFile, false);

            function readFile(evt)
            {
                var fileObject = evt.target.files[0];
                var reader = new FileReader();
                reader.onload = function ()
                {
                    var loader = new THREE.STLLoader();
                    //alert(this.result)
                    var geometry = loader.parse(this.result);
                    var material = new THREE.MeshPhongMaterial(
                    {
                        ambient: 0xff5533,
                        color: 0xff5533,
                        specular: 0x111111,
                        shininess: 200
                    });
                    var mesh = new THREE.Mesh(geometry, material);
                    mesh.castShadow = true;
                    mesh.receiveShadow = true;
                    scene.add(mesh);
                }; 
                reader.readAsText(fileObject)
            }
            if (!Detector.webgl) Detector.addGetWebGLMessage();
            var container, stats;
            var camera, scene, renderer, objects;
            init();
            animate();

            function init()
            {
                container = document.createElement('div');
                document.body.appendChild(container);
                camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 15);
                camera.position.set(3, 0.5, 3);
                scene = new THREE.Scene();
                scene.fog = new THREE.Fog(0xffffff, 2, 15);
                scene.fog.color.setHSV(0.06, 0.2, 0.45);
                // Grid
                var size = 20,
                    step = 0.25;
                var geometry = new THREE.Geometry();
                var material = new THREE.LineBasicMaterial(
                {
                    color: 0x000000
                });
                for (var i = -size; i <= size; i += step)
                {
                    geometry.vertices.push(new THREE.Vector3(-size, -0.04, i));
                    geometry.vertices.push(new THREE.Vector3(size, -0.04, i));
                    geometry.vertices.push(new THREE.Vector3(i, -0.04, -size));
                    geometry.vertices.push(new THREE.Vector3(i, -0.04, size));
                }
                var line = new THREE.Line(geometry, material, THREE.LinePieces);
                line.position.y = -0.46;
                scene.add(line);
                // Ground
                var plane = new THREE.Mesh(new THREE.PlaneGeometry(40, 40), new THREE.MeshPhongMaterial(
                {
                    ambient: 0x999999,
                    color: 0x999999,
                    specular: 0x101010
                }));
                plane.rotation.x = -Math.PI / 2;
                plane.position.y = -0.5;
                scene.add(plane);
                plane.receiveShadow = true;
                // Object
                // Lights
                scene.add(new THREE.AmbientLight(0x777777));
                addShadowedLight(1, 1, 1, 0xffffff, 1.35);
                addShadowedLight(0.5, 1, -1, 0xffaa00, 1);
                // renderer
                renderer = new THREE.WebGLRenderer(
                {
                    antialias: true,
                    clearColor: 0x111111,
                    clearAlpha: 1,
                    alpha: false
                });
                renderer.setSize(window.innerWidth, window.innerHeight);
                renderer.setClearColor(scene.fog.color, 1);
                renderer.gammaInput = true;
                renderer.gammaOutput = true;
                renderer.physicallyBasedShading = true;
                renderer.shadowMapEnabled = true;
                renderer.shadowMapCullFrontFaces = false;
                container.appendChild(renderer.domElement);
                // stats
                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.top = '0px';
                container.appendChild(stats.domElement);
                //
                window.addEventListener('resize', onWindowResize, false);
            }

            function addShadowedLight(x, y, z, color, intensity)
            {
                var directionalLight = new THREE.DirectionalLight(color, intensity);
                directionalLight.position.set(x, y, z)
                scene.add(directionalLight);
                directionalLight.castShadow = true;
                //directionalLight.shadowCameraVisible = true;
                var d = 1;
                directionalLight.shadowCameraLeft = -d;
                directionalLight.shadowCameraRight = d;
                directionalLight.shadowCameraTop = d;
                directionalLight.shadowCameraBottom = -d;
                directionalLight.shadowCameraNear = 1;
                directionalLight.shadowCameraFar = 4;
                directionalLight.shadowMapWidth = 2048;
                directionalLight.shadowMapHeight = 2048;
                directionalLight.shadowBias = -0.005;
                directionalLight.shadowDarkness = 0.15;
            }

            function onWindowResize()
            {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
            }
            //
            function animate()
            {
                requestAnimationFrame(animate);
                render();
                stats.update();
            }

            function render()
            {
                var timer = Date.now() * 0.0005;
                camera.position.x = Math.cos(timer) * 5;
                camera.position.z = Math.sin(timer) * 5;
                camera.lookAt(scene.position);
                renderer.render(scene, camera);
            }
        </script>
    </body>
</html>
like image 125
JayC Avatar answered Feb 17 '23 10:02

JayC


Thanks a lot for your snippet, this made my day

Though I had a problem implementing your solution at this line :

reader.readAsText(fileObject) ;

I changed it to :

reader.readAsArrayBuffer(fileObject) ;

and it works like a charm...


So for the complete code :

1) I have a button in my html to load the .stl file :

select your stl file <br>
<input type="file" id="pickFile" />

2) in my js file :

if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

var camera, scene, renderer, mesh, controls ;
var group ;

var container = document.getElementById('canvas3D');

// Create default material
material = new THREE.MeshPhongMaterial();

init();
animate();

// file input button
document.getElementById('pickFile').addEventListener('change', openFile, false);

// file load
function openFile (evt) {

    var fileObject = evt.target.files[0];

    // delete previous objects from scene 
    while(group.children.length > 0){ 
        group.remove(group.children[0]); 
    }

    var reader = new FileReader();
    reader.onload = function ()
    {
        var loader = new THREE.STLLoader();
        // parse the .stl file
        var geometry = loader.parse(this.result);
        var mesh = new THREE.Mesh(geometry, material);
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        group.add(mesh);
    };
    // --> update here 
    reader.readAsArrayBuffer(fileObject) ;
};

// and the rest of my three.js code there : init() and animate() functions ...
like image 29
Julien_ Avatar answered Feb 17 '23 10:02

Julien_