Three.JS- STL Loader - Uncaught TypeError: Cannot

2019-03-05 13:50发布

问题:

I am loading five elements with STL Loader to create a table. I am trying to apply dat.gui to Tabletop.STL to adjust scale of it.

Below is the code

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - STL</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <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;

            }

            a { color: skyblue }
            .button { background:#999; color:#eee; padding:0.2em 0.5em; cursor:pointer }
            .highlight { background:orange; color:#fff; }

            span {
                display: inline-block;
                width: 60px;
                float: left;
                text-align: center;
            }

        </style>
    </head>
    <body>
        <div id="info">
            <a href="http://threejs.org" target="_blank">three.js</a> -
            STL loader test by <a href="https://github.com/aleeper">aleeper</a>. PR2 head from <a href="http://www.ros.org/wiki/pr2_description">www.ros.org</a>
        </div>

        <script src="../build/three.min.js"></script>
        <script src="js/loaders/STLLoader.js"></script>
        <script src="js/Detector.js"></script>
        <script src="js/libs/stats.min.js"></script>
        <script src='js/libs/dat.gui.min.js'></script>
        <script src="js/controls/OrbitControls.js"></script>

        <script>

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

            var container, stats;

            var camera, cameraTarget, controls, scene, renderer;
            var myCube, mesh, effectController;
            var loader,  material, geometry;

            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.15, 3 );

                //cameraTarget = new THREE.Vector3( 0, -0.25, 0 );


                scene = new THREE.Scene();
                scene.fog = new THREE.Fog( 0x72645b, 2, 15 );

    // Ground

                var plane = new THREE.Mesh(
                    new THREE.PlaneBufferGeometry( 40, 40 ),
                    new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
                );
                plane.rotation.x = -Math.PI/2;
                plane.position.y = -0.5;
                scene.add( plane );

                plane.receiveShadow = true;



// 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 } );
                renderer.setClearColor( scene.fog.color );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );

                renderer.gammaInput = true;
                renderer.gammaOutput = true;

                renderer.shadowMapEnabled = true;
                renderer.shadowMapCullFace = THREE.CullFaceBack;

                container.appendChild( renderer.domElement );

                // stats

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.top = '0px';
                container.appendChild( stats.domElement );

                //

                controls = new THREE.OrbitControls( camera,  renderer.domElement  );
                controls.damping = 0.2;
                controls.addEventListener( 'change', render );

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


                //Set GUI
                var gui = new dat.GUI();          // needs dat.gui.mi.js

                effectController = new function() {
                this.xScaleCube =  0.05;
                this.yScaleCube =  0.05;
                this.zScaleCube =  0.05;

                }

                //effectController.zScaleCube = 1.5;    // initialize controller value
                var scalegui = gui.addFolder('Scale');
                scalegui.add(effectController,        // add a control to the GUI
                "xScaleCube",             // controller value
                0.1, 10, 0.05             // slider with lowest, highest, step
                ).name("Scale X");      // title of slider
                scalegui.add(effectController,"yScaleCube",0.1, 10, 0.05).name("Scale Y"); 
                scalegui.add(effectController,"zScaleCube",0.1, 10, 0.05).name("Scale Z");  


                //Cube
            //  var cubegeometry = new THREE.BoxGeometry(1,0.3,2);
//              var cubematerial = new THREE.MeshBasicMaterial( { color: 0x0000ff } );
//              myCube = new THREE.Mesh( cubegeometry, cubematerial );
//          
//              myCube.position.set( -1.8,  0.71, -1 );
//              myCube.rotation.set( 0,-0.7, 0 );
//              scene.add( myCube );


                 loader = new THREE.STLLoader();

                material = new THREE.MeshPhongMaterial( { color: 0xff6700, specular: 0xffffff, shininess: 100  } );

                loader.load( './models/stl/binary/Tabletop.STL', function ( geometry ) {

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

                    mesh.position.set( -1.8,  0.71, -0.2   );
                    mesh.rotation.set( 0,-0.7, 0);
                    //mesh.scale.set( 0.05, 0.05, 0.05 );

                    mesh.castShadow = true;
                    mesh.receiveShadow = true;


                    scene.add( mesh );

                } );



                //red
                var material1 = new THREE.MeshPhongMaterial( { color: 0xff0000, specular: 0xffffff, shininess: 100  } );

                loader.load( './models/stl/binary/Legs.STL', function ( geometry1 ) {

                    var mesh1 = new THREE.Mesh( geometry1, material1 );

                    mesh1.position.set(  -1, 0.9, 1.5  );
                    mesh1.rotation.set( - Math.PI / 2, 3.1, -1);
                    mesh1.scale.set( 0.05, 0.05, 0.05 );

                    mesh1.castShadow = true;
                    mesh1.receiveShadow = true;


                    scene.add( mesh1 );

                } );
                //green
                var material2 = new THREE.MeshPhongMaterial( { color: 0x00ff40, specular: 0xffffff, shininess: 100} );

                loader.load( './models/stl/binary/Legs.STL', function ( geometry2 ) {

                    var mesh2 = new THREE.Mesh( geometry2, material2 );

                    mesh2.position.set( 0.6,0.88,-1.8 );
                    mesh2.rotation.set(- Math.PI / 2, 3.15, 3.6 );
                    mesh2.scale.set( 0.05, 0.05, 0.05 );

                    mesh2.castShadow = true;
                    mesh2.receiveShadow = true;


                    scene.add( mesh2 );

                } );
                //blue
                var material3 = new THREE.MeshPhongMaterial( { color: 0x00bfff, specular: 0xffffff, shininess: 100 } );

                loader.load( './models/stl/binary/Legs.STL', function ( geometry3 ) {

                    var mesh3 = new THREE.Mesh( geometry3, material3 );

                    mesh3.position.set( -2.6, 0.8, -4);
                    mesh3.rotation.set(  - Math.PI / 2, 3.2, 2.6  );
                    mesh3.scale.set( 0.05, 0.05, 0.05 );

                    mesh3.castShadow = true;
                    mesh3.receiveShadow = true;


                    scene.add( mesh3 );

                } );
                //pink
                var material4 = new THREE.MeshPhongMaterial( { color: 0xff00ff, specular: 0xffffff, shininess: 100 } );

                loader.load( './models/stl/binary/Legs.STL', function ( geometry4 ) {

                    var mesh4 = new THREE.Mesh( geometry4, material4 );

                    mesh4.position.set( -5.2, 0.8, -0.5);
                    mesh4.rotation.set( - Math.PI / 2, 3.1, 0.8 );
                    mesh4.scale.set( 0.05, 0.05, 0.05 );

                    mesh4.castShadow = true;
                    mesh4.receiveShadow = true;


                    scene.add( mesh4 );

                } );


            }

            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 = 1024;
                directionalLight.shadowMapHeight = 1024;

                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() {
                mesh.scale.x = effectController.xScaleCube;     // set GUI params
                mesh.scale.y = effectController.yScaleCube;
                mesh.scale.z = effectController.zScaleCube;
                    stats.update();
                    controls.update();
                    requestAnimationFrame( animate );
                    render();   
            }

            function render() {

                //var timer = Date.now() * 0.0005;
//
//              camera.position.x = Math.cos( timer ) * 3;
//              camera.position.z = Math.sin( timer ) * 3;
//
//              camera.lookAt( cameraTarget );
                    renderer.render( scene, camera );
            }

        </script>
    </body>
</html>

If I use dat.gui to the cube created from BoxGeometry insted of loading Tabletop.STL, then it works for cube.

But now I have loaded Tabletop.STL instead of cube for top surface of table and declared all variables of Tabletop.STL globally like loader, material, mesh. Still its giving me error like Uncaught TypeError: Cannot read property 'scale' of undefined in below function lines

function animate() {
                    mesh.scale.x = effectController.xScaleCube;     // Error at this line
                    mesh.scale.y = effectController.yScaleCube;
                    mesh.scale.z = effectController.zScaleCube;
                        stats.update();
                        controls.update();
                        requestAnimationFrame( animate );
                        render();   
                }

Can anyone please tell me where I am making mistake?

回答1:

loader.load() is an asynchronous method. You are calling animate() before the mesh loads, and before mesh is defined in the loader callback function.

Inside your animate() method, do this:

if ( mesh ) {

    mesh.scale.x = ...

}